aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs2
-rw-r--r--Makefile.target8
-rw-r--r--async.c1
-rw-r--r--compatfd.c12
-rw-r--r--cpus.c497
-rw-r--r--cpus.h3
-rw-r--r--exec-all.h14
-rw-r--r--exec.c3
-rw-r--r--hw/hda-audio.c26
-rw-r--r--hw/intel-hda.c18
-rw-r--r--hw/intel-hda.h2
-rw-r--r--hw/m48t59.c4
-rw-r--r--hw/mac_dbdma.c5
-rw-r--r--hw/mac_dbdma.h1
-rw-r--r--hw/pci_bridge.c2
-rw-r--r--iohandler.c55
-rw-r--r--linux-user/main.c19
-rw-r--r--main-loop.c475
-rw-r--r--main-loop.h351
-rw-r--r--os-win32.c123
-rw-r--r--qemu-char.c227
-rw-r--r--qemu-char.h12
-rw-r--r--qemu-common.h37
-rw-r--r--qemu-coroutine-lock.c1
-rw-r--r--qemu-os-posix.h4
-rw-r--r--qemu-os-win32.h17
-rw-r--r--qemu-timer.c489
-rw-r--r--qemu-timer.h31
-rw-r--r--savevm.c25
-rw-r--r--slirp/libslirp.h11
-rw-r--r--sysemu.h3
-rw-r--r--target-sparc/cc_helper.c485
-rw-r--r--target-sparc/cpu.h7
-rw-r--r--target-sparc/cpu_init.c848
-rw-r--r--target-sparc/fop_helper.c394
-rw-r--r--target-sparc/helper.c1074
-rw-r--r--target-sparc/helper.h180
-rw-r--r--target-sparc/int32_helper.c125
-rw-r--r--target-sparc/int64_helper.c164
-rw-r--r--target-sparc/op_helper.c2590
-rw-r--r--target-sparc/translate.c314
-rw-r--r--target-sparc/vis_helper.c406
-rw-r--r--target-sparc/win_helper.c518
-rw-r--r--vl.c189
44 files changed, 5234 insertions, 4538 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 9e2077833e..01587c8f8f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -81,7 +81,7 @@ common-obj-y += $(oslib-obj-y)
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
-common-obj-y += tcg-runtime.o host-utils.o
+common-obj-y += tcg-runtime.o host-utils.o main-loop.o
common-obj-y += irq.o input.o
common-obj-$(CONFIG_PTIMER) += ptimer.o
common-obj-$(CONFIG_MAX7310) += max7310.o
diff --git a/Makefile.target b/Makefile.target
index 417f23e00e..1e90df7e70 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -74,8 +74,14 @@ libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o
endif
+libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
+ifeq ($(TARGET_BASE_ARCH), sparc)
+libobj-y += fop_helper.o cc_helper.o win_helper.o cpu_init.o
+endif
+libobj-$(TARGET_SPARC) += int32_helper.o
+libobj-$(TARGET_SPARC64) += int64_helper.o
libobj-y += disas.o
@@ -91,7 +97,7 @@ tcg/tcg.o: cpu.h
# HELPER_CFLAGS is used for all the code compiled with static register
# variables
-op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+op_helper.o win_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in user-exec.c.
diff --git a/async.c b/async.c
index ca13962222..332d511ed5 100644
--- a/async.c
+++ b/async.c
@@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "qemu-aio.h"
+#include "main-loop.h"
/* Anchor of the list of Bottom Halves belonging to the context */
static struct QEMUBH *first_bh;
diff --git a/compatfd.c b/compatfd.c
index 31654c62a6..02306a4f71 100644
--- a/compatfd.c
+++ b/compatfd.c
@@ -119,9 +119,17 @@ int qemu_signalfd(const sigset_t *mask)
bool qemu_signalfd_available(void)
{
#ifdef CONFIG_SIGNALFD
+ sigset_t mask;
+ int fd;
+ bool ok;
+ sigemptyset(&mask);
errno = 0;
- syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
- return errno != ENOSYS;
+ fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
+ ok = (errno != ENOSYS);
+ if (fd >= 0) {
+ close(fd);
+ }
+ return ok;
#else
return false;
#endif
diff --git a/cpus.c b/cpus.c
index 5f5b763e2c..79a76560cb 100644
--- a/cpus.c
+++ b/cpus.c
@@ -33,17 +33,12 @@
#include "qemu-thread.h"
#include "cpus.h"
+#include "main-loop.h"
#ifndef _WIN32
#include "compatfd.h"
#endif
-#ifdef SIGRTMIN
-#define SIG_IPI (SIGRTMIN+4)
-#else
-#define SIG_IPI SIGUSR1
-#endif
-
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
@@ -65,6 +60,281 @@
static CPUState *next_cpu;
/***********************************************************/
+/* guest cycle counter */
+
+/* Conversion factor from emulated instructions to virtual clock ticks. */
+static int icount_time_shift;
+/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
+#define MAX_ICOUNT_SHIFT 10
+/* Compensate for varying guest execution speed. */
+static int64_t qemu_icount_bias;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+static QEMUTimer *icount_warp_timer;
+static int64_t vm_clock_warp_start;
+static int64_t qemu_icount;
+
+typedef struct TimersState {
+ int64_t cpu_ticks_prev;
+ int64_t cpu_ticks_offset;
+ int64_t cpu_clock_offset;
+ int32_t cpu_ticks_enabled;
+ int64_t dummy;
+} TimersState;
+
+TimersState timers_state;
+
+/* Return the virtual CPU time, based on the instruction counter. */
+int64_t cpu_get_icount(void)
+{
+ int64_t icount;
+ CPUState *env = cpu_single_env;;
+
+ icount = qemu_icount;
+ if (env) {
+ if (!can_do_io(env)) {
+ fprintf(stderr, "Bad clock read\n");
+ }
+ icount -= (env->icount_decr.u16.low + env->icount_extra);
+ }
+ return qemu_icount_bias + (icount << icount_time_shift);
+}
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+ if (use_icount) {
+ return cpu_get_icount();
+ }
+ if (!timers_state.cpu_ticks_enabled) {
+ return timers_state.cpu_ticks_offset;
+ } else {
+ int64_t ticks;
+ ticks = cpu_get_real_ticks();
+ if (timers_state.cpu_ticks_prev > ticks) {
+ /* Note: non increasing ticks may happen if the host uses
+ software suspend */
+ timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+ }
+ timers_state.cpu_ticks_prev = ticks;
+ return ticks + timers_state.cpu_ticks_offset;
+ }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+int64_t cpu_get_clock(void)
+{
+ int64_t ti;
+ if (!timers_state.cpu_ticks_enabled) {
+ return timers_state.cpu_clock_offset;
+ } else {
+ ti = get_clock();
+ return ti + timers_state.cpu_clock_offset;
+ }
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+ if (!timers_state.cpu_ticks_enabled) {
+ timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
+ timers_state.cpu_clock_offset -= get_clock();
+ timers_state.cpu_ticks_enabled = 1;
+ }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+ cpu_get_ticks() after that. */
+void cpu_disable_ticks(void)
+{
+ if (timers_state.cpu_ticks_enabled) {
+ timers_state.cpu_ticks_offset = cpu_get_ticks();
+ timers_state.cpu_clock_offset = cpu_get_clock();
+ timers_state.cpu_ticks_enabled = 0;
+ }
+}
+
+/* Correlation between real and virtual time is always going to be
+ fairly approximate, so ignore small variation.
+ When the guest is idle real and virtual time will be aligned in
+ the IO wait loop. */
+#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
+
+static void icount_adjust(void)
+{
+ int64_t cur_time;
+ int64_t cur_icount;
+ int64_t delta;
+ static int64_t last_delta;
+ /* If the VM is not running, then do nothing. */
+ if (!runstate_is_running()) {
+ return;
+ }
+ cur_time = cpu_get_clock();
+ cur_icount = qemu_get_clock_ns(vm_clock);
+ delta = cur_icount - cur_time;
+ /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
+ if (delta > 0
+ && last_delta + ICOUNT_WOBBLE < delta * 2
+ && icount_time_shift > 0) {
+ /* The guest is getting too far ahead. Slow time down. */
+ icount_time_shift--;
+ }
+ if (delta < 0
+ && last_delta - ICOUNT_WOBBLE > delta * 2
+ && icount_time_shift < MAX_ICOUNT_SHIFT) {
+ /* The guest is getting too far behind. Speed time up. */
+ icount_time_shift++;
+ }
+ last_delta = delta;
+ qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+}
+
+static void icount_adjust_rt(void *opaque)
+{
+ qemu_mod_timer(icount_rt_timer,
+ qemu_get_clock_ms(rt_clock) + 1000);
+ icount_adjust();
+}
+
+static void icount_adjust_vm(void *opaque)
+{
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+ icount_adjust();
+}
+
+static int64_t qemu_icount_round(int64_t count)
+{
+ return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
+}
+
+static void icount_warp_rt(void *opaque)
+{
+ if (vm_clock_warp_start == -1) {
+ return;
+ }
+
+ if (runstate_is_running()) {
+ int64_t clock = qemu_get_clock_ns(rt_clock);
+ int64_t warp_delta = clock - vm_clock_warp_start;
+ if (use_icount == 1) {
+ qemu_icount_bias += warp_delta;
+ } else {
+ /*
+ * In adaptive mode, do not let the vm_clock run too
+ * far ahead of real time.
+ */
+ int64_t cur_time = cpu_get_clock();
+ int64_t cur_icount = qemu_get_clock_ns(vm_clock);
+ int64_t delta = cur_time - cur_icount;
+ qemu_icount_bias += MIN(warp_delta, delta);
+ }
+ if (qemu_clock_expired(vm_clock)) {
+ qemu_notify_event();
+ }
+ }
+ vm_clock_warp_start = -1;
+}
+
+void qemu_clock_warp(QEMUClock *clock)
+{
+ int64_t deadline;
+
+ /*
+ * There are too many global variables to make the "warp" behavior
+ * applicable to other clocks. But a clock argument removes the
+ * need for if statements all over the place.
+ */
+ if (clock != vm_clock || !use_icount) {
+ return;
+ }
+
+ /*
+ * If the CPUs have been sleeping, advance the vm_clock timer now. This
+ * ensures that the deadline for the timer is computed correctly below.
+ * This also makes sure that the insn counter is synchronized before the
+ * CPU starts running, in case the CPU is woken by an event other than
+ * the earliest vm_clock timer.
+ */
+ icount_warp_rt(NULL);
+ if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) {
+ qemu_del_timer(icount_warp_timer);
+ return;
+ }
+
+ vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
+ deadline = qemu_clock_deadline(vm_clock);
+ if (deadline > 0) {
+ /*
+ * Ensure the vm_clock proceeds even when the virtual CPU goes to
+ * sleep. Otherwise, the CPU might be waiting for a future timer
+ * interrupt to wake it up, but the interrupt never comes because
+ * the vCPU isn't running any insns and thus doesn't advance the
+ * vm_clock.
+ *
+ * An extreme solution for this problem would be to never let VCPUs
+ * sleep in icount mode if there is a pending vm_clock timer; rather
+ * time could just advance to the next vm_clock event. Instead, we
+ * do stop VCPUs and only advance vm_clock after some "real" time,
+ * (related to the time left until the next event) has passed. This
+ * rt_clock timer will do this. This avoids that the warps are too
+ * visible externally---for example, you will not be sending network
+ * packets continously instead of every 100ms.
+ */
+ qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
+ } else {
+ qemu_notify_event();
+ }
+}
+
+static const VMStateDescription vmstate_timers = {
+ .name = "timer",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(cpu_ticks_offset, TimersState),
+ VMSTATE_INT64(dummy, TimersState),
+ VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+void configure_icount(const char *option)
+{
+ vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+ if (!option) {
+ return;
+ }
+
+ icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+ if (strcmp(option, "auto") != 0) {
+ icount_time_shift = strtol(option, NULL, 0);
+ use_icount = 1;
+ return;
+ }
+
+ use_icount = 2;
+
+ /* 125MIPS seems a reasonable initial guess at the guest speed.
+ It will be corrected fairly quickly anyway. */
+ icount_time_shift = 3;
+
+ /* Have both realtime and virtual time triggers for speed adjustment.
+ The realtime trigger catches emulated time passing too slowly,
+ the virtual time trigger catches emulated time passing too fast.
+ Realtime triggers occur even when idle, so use them less frequently
+ than VM triggers. */
+ icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
+ qemu_mod_timer(icount_rt_timer,
+ qemu_get_clock_ms(rt_clock) + 1000);
+ icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+}
+
+/***********************************************************/
void hw_error(const char *fmt, ...)
{
va_list ap;
@@ -272,143 +542,10 @@ static void qemu_kvm_eat_signals(CPUState *env)
#endif /* !CONFIG_LINUX */
#ifndef _WIN32
-static int io_thread_fd = -1;
-
-static void qemu_event_increment(void)
-{
- /* Write 8 bytes to be compatible with eventfd. */
- static const uint64_t val = 1;
- ssize_t ret;
-
- if (io_thread_fd == -1) {
- return;
- }
- do {
- ret = write(io_thread_fd, &val, sizeof(val));
- } while (ret < 0 && errno == EINTR);
-
- /* EAGAIN is fine, a read must be pending. */
- if (ret < 0 && errno != EAGAIN) {
- fprintf(stderr, "qemu_event_increment: write() failed: %s\n",
- strerror(errno));
- exit (1);
- }
-}
-
-static void qemu_event_read(void *opaque)
-{
- int fd = (intptr_t)opaque;
- ssize_t len;
- char buffer[512];
-
- /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
- do {
- len = read(fd, buffer, sizeof(buffer));
- } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
-}
-
-static int qemu_event_init(void)
-{
- int err;
- int fds[2];
-
- err = qemu_eventfd(fds);
- if (err == -1) {
- return -errno;
- }
- err = fcntl_setfl(fds[0], O_NONBLOCK);
- if (err < 0) {
- goto fail;
- }
- err = fcntl_setfl(fds[1], O_NONBLOCK);
- if (err < 0) {
- goto fail;
- }
- qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
- (void *)(intptr_t)fds[0]);
-
- io_thread_fd = fds[1];
- return 0;
-
-fail:
- close(fds[0]);
- close(fds[1]);
- return err;
-}
-
static void dummy_signal(int sig)
{
}
-/* If we have signalfd, we mask out the signals we want to handle and then
- * use signalfd to listen for them. We rely on whatever the current signal
- * handler is to dispatch the signals when we receive them.
- */
-static void sigfd_handler(void *opaque)
-{
- int fd = (intptr_t)opaque;
- struct qemu_signalfd_siginfo info;
- struct sigaction action;
- ssize_t len;
-
- while (1) {
- do {
- len = read(fd, &info, sizeof(info));
- } while (len == -1 && errno == EINTR);
-
- if (len == -1 && errno == EAGAIN) {
- break;
- }
-
- if (len != sizeof(info)) {
- printf("read from sigfd returned %zd: %m\n", len);
- return;
- }
-
- sigaction(info.ssi_signo, NULL, &action);
- if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
- action.sa_sigaction(info.ssi_signo,
- (siginfo_t *)&info, NULL);
- } else if (action.sa_handler) {
- action.sa_handler(info.ssi_signo);
- }
- }
-}
-
-static int qemu_signal_init(void)
-{
- int sigfd;
- sigset_t set;
-
- /*
- * SIG_IPI must be blocked in the main thread and must not be caught
- * by sigwait() in the signal thread. Otherwise, the cpu thread will
- * not catch it reliably.
- */
- sigemptyset(&set);
- sigaddset(&set, SIG_IPI);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-
- sigemptyset(&set);
- sigaddset(&set, SIGIO);
- sigaddset(&set, SIGALRM);
- sigaddset(&set, SIGBUS);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-
- sigfd = qemu_signalfd(&set);
- if (sigfd == -1) {
- fprintf(stderr, "failed to create signalfd\n");
- return -errno;
- }
-
- fcntl_setfl(sigfd, O_NONBLOCK);
-
- qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
- (void *)(intptr_t)sigfd);
-
- return 0;
-}
-
static void qemu_kvm_init_cpu_signals(CPUState *env)
{
int r;
@@ -452,38 +589,6 @@ static void qemu_tcg_init_cpu_signals(void)
}
#else /* _WIN32 */
-
-HANDLE qemu_event_handle;
-
-static void dummy_event_handler(void *opaque)
-{
-}
-
-static int qemu_event_init(void)
-{
- qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!qemu_event_handle) {
- fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
- return -1;
- }
- qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
- return 0;
-}
-
-static void qemu_event_increment(void)
-{
- if (!SetEvent(qemu_event_handle)) {
- fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
- GetLastError());
- exit (1);
- }
-}
-
-static int qemu_signal_init(void)
-{
- return 0;
-}
-
static void qemu_kvm_init_cpu_signals(CPUState *env)
{
abort();
@@ -509,38 +614,16 @@ static QemuCond qemu_cpu_cond;
static QemuCond qemu_pause_cond;
static QemuCond qemu_work_cond;
-int qemu_init_main_loop(void)
+void qemu_init_cpu_loop(void)
{
- int ret;
-
qemu_init_sigbus();
-
- ret = qemu_signal_init();
- if (ret) {
- return ret;
- }
-
- /* Note eventfd must be drained before signalfd handlers run */
- ret = qemu_event_init();
- if (ret) {
- return ret;
- }
-
qemu_cond_init(&qemu_cpu_cond);
qemu_cond_init(&qemu_pause_cond);
qemu_cond_init(&qemu_work_cond);
qemu_cond_init(&qemu_io_proceeded_cond);
qemu_mutex_init(&qemu_global_mutex);
- qemu_mutex_lock(&qemu_global_mutex);
qemu_thread_get_self(&io_thread);
-
- return 0;
-}
-
-void qemu_main_loop_start(void)
-{
- resume_all_vcpus();
}
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
@@ -686,7 +769,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
while (1) {
cpu_exec_all();
- if (use_icount && qemu_next_icount_deadline() <= 0) {
+ if (use_icount && qemu_clock_deadline(vm_clock) <= 0) {
qemu_notify_event();
}
qemu_tcg_wait_io_event();
@@ -784,6 +867,7 @@ void pause_all_vcpus(void)
{
CPUState *penv = first_cpu;
+ qemu_clock_enable(vm_clock, false);
while (penv) {
penv->stop = 1;
qemu_cpu_kick(penv);
@@ -858,11 +942,6 @@ void qemu_init_vcpu(void *_env)
}
}
-void qemu_notify_event(void)
-{
- qemu_event_increment();
-}
-
void cpu_stop_current(void)
{
if (cpu_single_env) {
@@ -914,7 +993,7 @@ static int tcg_cpu_exec(CPUState *env)
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
env->icount_decr.u16.low = 0;
env->icount_extra = 0;
- count = qemu_icount_round(qemu_next_icount_deadline());
+ count = qemu_icount_round(qemu_clock_deadline(vm_clock));
qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count;
count -= decr;
@@ -1006,22 +1085,6 @@ void set_cpu_log_filename(const char *optarg)
cpu_set_log_filename(optarg);
}
-/* Return the virtual CPU time, based on the instruction counter. */
-int64_t cpu_get_icount(void)
-{
- int64_t icount;
- CPUState *env = cpu_single_env;;
-
- icount = qemu_icount;
- if (env) {
- if (!can_do_io(env)) {
- fprintf(stderr, "Bad clock read\n");
- }
- icount -= (env->icount_decr.u16.low + env->icount_extra);
- }
- return qemu_icount_bias + (icount << icount_time_shift);
-}
-
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
{
/* XXX: implement xxx_cpu_list for targets that still miss it */
diff --git a/cpus.h b/cpus.h
index 58858855ff..3525375756 100644
--- a/cpus.h
+++ b/cpus.h
@@ -2,8 +2,7 @@
#define QEMU_CPUS_H
/* cpus.c */
-int qemu_init_main_loop(void);
-void qemu_main_loop_start(void);
+void qemu_init_cpu_loop(void);
void resume_all_vcpus(void);
void pause_all_vcpus(void);
void cpu_stop_current(void);
diff --git a/exec-all.h b/exec-all.h
index 1120f84661..72ef246793 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -356,4 +356,18 @@ extern int singlestep;
/* cpu-exec.c */
extern volatile sig_atomic_t exit_request;
+/* Deterministic execution requires that IO only be performed on the last
+ instruction of a TB so that interrupts take effect immediately. */
+static inline int can_do_io(CPUState *env)
+{
+ if (!use_icount) {
+ return 1;
+ }
+ /* If not executing code then assume we are ok. */
+ if (!env->current_tb) {
+ return 1;
+ }
+ return env->can_do_io != 0;
+}
+
#endif
diff --git a/exec.c b/exec.c
index d0cbf15822..9dc4edbf61 100644
--- a/exec.c
+++ b/exec.c
@@ -125,9 +125,6 @@ CPUState *cpu_single_env;
1 = Precise instruction counting.
2 = Adaptive rate instruction counting. */
int use_icount = 0;
-/* Current instruction counter. While executing translated code this may
- include some instructions that have not yet been executed. */
-int64_t qemu_icount;
typedef struct PageDesc {
/* list of TBs intersecting this ram page */
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index c699d6fd8b..9b089e65b4 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -466,7 +466,8 @@ struct HDAAudioState {
QEMUSoundCard card;
const desc_codec *desc;
HDAAudioStream st[4];
- bool running[16];
+ bool running_compat[16];
+ bool running_real[2 * 16];
/* properties */
uint32_t debug;
@@ -663,7 +664,7 @@ static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
st->channel = payload & 0x0f;
dprint(a, 2, "%s: stream %d, channel %d\n",
st->node->name, st->stream, st->channel);
- hda_audio_set_running(st, a->running[st->stream]);
+ hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
hda_codec_response(hda, true, 0);
break;
case AC_VERB_GET_CONV:
@@ -746,16 +747,20 @@ fail:
hda_codec_response(hda, true, 0);
}
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
{
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
int s;
- a->running[stnr] = running;
+ a->running_compat[stnr] = running;
+ a->running_real[output * 16 + stnr] = running;
for (s = 0; s < ARRAY_SIZE(a->st); s++) {
if (a->st[s].node == NULL) {
continue;
}
+ if (a->st[s].output != output) {
+ continue;
+ }
if (a->st[s].stream != stnr) {
continue;
}
@@ -837,6 +842,12 @@ static int hda_audio_post_load(void *opaque, int version)
int i;
dprint(a, 1, "%s\n", __FUNCTION__);
+ if (version == 1) {
+ /* assume running_compat[] is for output streams */
+ for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
+ a->running_real[16 + i] = a->running_compat[i];
+ }
+
for (i = 0; i < ARRAY_SIZE(a->st); i++) {
st = a->st + i;
if (st->node == NULL)
@@ -844,7 +855,7 @@ static int hda_audio_post_load(void *opaque, int version)
hda_codec_parse_fmt(st->format, &st->as);
hda_audio_setup(st);
hda_audio_set_amp(st);
- hda_audio_set_running(st, a->running[st->stream]);
+ hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
}
return 0;
}
@@ -868,13 +879,14 @@ static const VMStateDescription vmstate_hda_audio_stream = {
static const VMStateDescription vmstate_hda_audio = {
.name = "hda-audio",
- .version_id = 1,
+ .version_id = 2,
.post_load = hda_audio_post_load,
.fields = (VMStateField []) {
VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
vmstate_hda_audio_stream,
HDAAudioStream),
- VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+ VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
+ VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 4272204e03..f97775c235 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -389,14 +389,15 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
{
HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
- IntelHDAStream *st = NULL;
target_phys_addr_t addr;
uint32_t s, copy, left;
+ IntelHDAStream *st;
bool irq = false;
- for (s = 0; s < ARRAY_SIZE(d->st); s++) {
- if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
- st = d->st + s;
+ st = output ? d->st + 4 : d->st;
+ for (s = 0; s < 4; s++) {
+ if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+ st = st + s;
break;
}
}
@@ -484,7 +485,7 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
st->bp = 0;
}
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
{
DeviceState *qdev;
HDACodecDevice *cdev;
@@ -492,7 +493,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->info->stream) {
- cdev->info->stream(cdev, stream, running);
+ cdev->info->stream(cdev, stream, running, output);
}
}
}
@@ -566,6 +567,7 @@ static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t
static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{
+ bool output = reg->stream >= 4;
IntelHDAStream *st = d->st + reg->stream;
if (st->ctl & 0x01) {
@@ -581,11 +583,11 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
reg->stream, stnr, st->cbl);
intel_hda_parse_bdl(d, st);
- intel_hda_notify_codecs(d, stnr, true);
+ intel_hda_notify_codecs(d, stnr, true, output);
} else {
/* stop */
dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
- intel_hda_notify_codecs(d, stnr, false);
+ intel_hda_notify_codecs(d, stnr, false, output);
}
}
intel_hda_update_irq(d);
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 4e44e3894f..65fd2a85bb 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -34,7 +34,7 @@ struct HDACodecDeviceInfo {
int (*init)(HDACodecDevice *dev);
int (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
- void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+ void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
};
void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
diff --git a/hw/m48t59.c b/hw/m48t59.c
index f318e67919..a77937ef68 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -480,7 +480,6 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
{
M48t59State *NVRAM = opaque;
- addr -= NVRAM->io_base;
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
switch (addr) {
case 0:
@@ -492,7 +491,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
NVRAM->addr |= val << 8;
break;
case 3:
- m48t59_write(NVRAM, val, NVRAM->addr);
+ m48t59_write(NVRAM, NVRAM->addr, val);
NVRAM->addr = 0x0000;
break;
default:
@@ -505,7 +504,6 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
M48t59State *NVRAM = opaque;
uint32_t retval;
- addr -= NVRAM->io_base;
switch (addr) {
case 3:
retval = m48t59_read(NVRAM, NVRAM->addr);
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 5affdd18a5..1791ec12e1 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -661,11 +661,6 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
ch->io.channel = ch;
}
-void DBDMA_schedule(void)
-{
- qemu_notify_event();
-}
-
static void
dbdma_control_write(DBDMA_channel *ch)
{
diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
index 933e17c5b9..6d1abe6aae 100644
--- a/hw/mac_dbdma.h
+++ b/hw/mac_dbdma.h
@@ -41,5 +41,4 @@ struct DBDMA_io {
void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
DBDMA_rw rw, DBDMA_flush flush,
void *opaque);
-void DBDMA_schedule(void);
void* DBDMA_init (MemoryRegion **dbdma_mem);
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index b6287cdc6d..650d1650c5 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -319,7 +319,7 @@ int pci_bridge_initfn(PCIDevice *dev)
sec_bus->parent_dev = dev;
sec_bus->map_irq = br->map_irq;
sec_bus->address_space_mem = &br->address_space_mem;
- memory_region_init(&br->address_space_mem, "pci_pridge_pci", INT64_MAX);
+ memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
sec_bus->address_space_io = &br->address_space_io;
memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
pci_bridge_region_init(br);
diff --git a/iohandler.c b/iohandler.c
index 4cc1c5ade6..5640d49388 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -26,6 +26,7 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "qemu-queue.h"
+#include "main-loop.h"
#ifndef _WIN32
#include <sys/wait.h>
@@ -80,64 +81,12 @@ int qemu_set_fd_handler2(int fd,
return 0;
}
-typedef struct IOTrampoline
-{
- GIOChannel *chan;
- IOHandler *fd_read;
- IOHandler *fd_write;
- void *opaque;
- guint tag;
-} IOTrampoline;
-
-static gboolean fd_trampoline(GIOChannel *chan, GIOCondition cond, gpointer opaque)
-{
- IOTrampoline *tramp = opaque;
-
- if ((cond & G_IO_IN) && tramp->fd_read) {
- tramp->fd_read(tramp->opaque);
- }
-
- if ((cond & G_IO_OUT) && tramp->fd_write) {
- tramp->fd_write(tramp->opaque);
- }
-
- return TRUE;
-}
-
int qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
- static IOTrampoline fd_trampolines[FD_SETSIZE];
- IOTrampoline *tramp = &fd_trampolines[fd];
-
- if (tramp->tag != 0) {
- g_io_channel_unref(tramp->chan);
- g_source_remove(tramp->tag);
- tramp->tag = 0;
- }
-
- if (fd_read || fd_write || opaque) {
- GIOCondition cond = 0;
-
- tramp->fd_read = fd_read;
- tramp->fd_write = fd_write;
- tramp->opaque = opaque;
-
- if (fd_read) {
- cond |= G_IO_IN | G_IO_ERR;
- }
-
- if (fd_write) {
- cond |= G_IO_OUT | G_IO_ERR;
- }
-
- tramp->chan = g_io_channel_unix_new(fd);
- tramp->tag = g_io_add_watch(tramp->chan, cond, fd_trampoline, tramp);
- }
-
- return 0;
+ return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
diff --git a/linux-user/main.c b/linux-user/main.c
index 186358bd63..e7dad547b8 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3084,6 +3084,7 @@ static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
+ exit(0);
}
struct qemu_argument {
@@ -3129,7 +3130,7 @@ struct qemu_argument arg_table[] = {
{"strace", "QEMU_STRACE", false, handle_arg_strace,
"", "log system calls"},
{"version", "QEMU_VERSION", false, handle_arg_version,
- "", "log system calls"},
+ "", "display version information and exit"},
{NULL, NULL, false, NULL, NULL, NULL}
};
@@ -3231,16 +3232,15 @@ static int parse_args(int argc, char **argv)
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (!strcmp(r, arginfo->argv)) {
- if (optind >= argc) {
- usage();
- }
-
- arginfo->handle_opt(argv[optind]);
-
if (arginfo->has_arg) {
+ if (optind >= argc) {
+ usage();
+ }
+ arginfo->handle_opt(argv[optind]);
optind++;
+ } else {
+ arginfo->handle_opt(NULL);
}
-
break;
}
}
@@ -3276,9 +3276,6 @@ int main(int argc, char **argv, char **envp)
int i;
int ret;
- if (argc <= 1)
- usage();
-
qemu_cache_utils_init(envp);
if ((envlist = envlist_create()) == NULL) {
diff --git a/main-loop.c b/main-loop.c
new file mode 100644
index 0000000000..60e9748324
--- /dev/null
+++ b/main-loop.c
@@ -0,0 +1,475 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "slirp/slirp.h"
+#include "main-loop.h"
+
+#ifndef _WIN32
+
+#include "compatfd.h"
+
+static int io_thread_fd = -1;
+
+void qemu_notify_event(void)
+{
+ /* Write 8 bytes to be compatible with eventfd. */
+ static const uint64_t val = 1;
+ ssize_t ret;
+
+ if (io_thread_fd == -1) {
+ return;
+ }
+ do {
+ ret = write(io_thread_fd, &val, sizeof(val));
+ } while (ret < 0 && errno == EINTR);
+
+ /* EAGAIN is fine, a read must be pending. */
+ if (ret < 0 && errno != EAGAIN) {
+ fprintf(stderr, "qemu_notify_event: write() failed: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+}
+
+static void qemu_event_read(void *opaque)
+{
+ int fd = (intptr_t)opaque;
+ ssize_t len;
+ char buffer[512];
+
+ /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
+ do {
+ len = read(fd, buffer, sizeof(buffer));
+ } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
+}
+
+static int qemu_event_init(void)
+{
+ int err;
+ int fds[2];
+
+ err = qemu_eventfd(fds);
+ if (err == -1) {
+ return -errno;
+ }
+ err = fcntl_setfl(fds[0], O_NONBLOCK);
+ if (err < 0) {
+ goto fail;
+ }
+ err = fcntl_setfl(fds[1], O_NONBLOCK);
+ if (err < 0) {
+ goto fail;
+ }
+ qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+ (void *)(intptr_t)fds[0]);
+
+ io_thread_fd = fds[1];
+ return 0;
+
+fail:
+ close(fds[0]);
+ close(fds[1]);
+ return err;
+}
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them. We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+ int fd = (intptr_t)opaque;
+ struct qemu_signalfd_siginfo info;
+ struct sigaction action;
+ ssize_t len;
+
+ while (1) {
+ do {
+ len = read(fd, &info, sizeof(info));
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1 && errno == EAGAIN) {
+ break;
+ }
+
+ if (len != sizeof(info)) {
+ printf("read from sigfd returned %zd: %m\n", len);
+ return;
+ }
+
+ sigaction(info.ssi_signo, NULL, &action);
+ if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+ action.sa_sigaction(info.ssi_signo,
+ (siginfo_t *)&info, NULL);
+ } else if (action.sa_handler) {
+ action.sa_handler(info.ssi_signo);
+ }
+ }
+}
+
+static int qemu_signal_init(void)
+{
+ int sigfd;
+ sigset_t set;
+
+ /*
+ * SIG_IPI must be blocked in the main thread and must not be caught
+ * by sigwait() in the signal thread. Otherwise, the cpu thread will
+ * not catch it reliably.
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIG_IPI);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGBUS);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigfd = qemu_signalfd(&set);
+ if (sigfd == -1) {
+ fprintf(stderr, "failed to create signalfd\n");
+ return -errno;
+ }
+
+ fcntl_setfl(sigfd, O_NONBLOCK);
+
+ qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+ (void *)(intptr_t)sigfd);
+
+ return 0;
+}
+
+#else /* _WIN32 */
+
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+ qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!qemu_event_handle) {
+ fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+ return -1;
+ }
+ qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+ return 0;
+}
+
+void qemu_notify_event(void)
+{
+ if (!SetEvent(qemu_event_handle)) {
+ fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
+ GetLastError());
+ exit(1);
+ }
+}
+
+static int qemu_signal_init(void)
+{
+ return 0;
+}
+#endif
+
+int qemu_init_main_loop(void)
+{
+ int ret;
+
+ qemu_mutex_lock_iothread();
+ ret = qemu_signal_init();
+ if (ret) {
+ return ret;
+ }
+
+ /* Note eventfd must be drained before signalfd handlers run */
+ ret = qemu_event_init();
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
+static int n_poll_fds;
+static int max_priority;
+
+static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
+ fd_set *xfds, struct timeval *tv)
+{
+ GMainContext *context = g_main_context_default();
+ int i;
+ int timeout = 0, cur_timeout;
+
+ g_main_context_prepare(context, &max_priority);
+
+ n_poll_fds = g_main_context_query(context, max_priority, &timeout,
+ poll_fds, ARRAY_SIZE(poll_fds));
+ g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
+
+ for (i = 0; i < n_poll_fds; i++) {
+ GPollFD *p = &poll_fds[i];
+
+ if ((p->events & G_IO_IN)) {
+ FD_SET(p->fd, rfds);
+ *max_fd = MAX(*max_fd, p->fd);
+ }
+ if ((p->events & G_IO_OUT)) {
+ FD_SET(p->fd, wfds);
+ *max_fd = MAX(*max_fd, p->fd);
+ }
+ if ((p->events & G_IO_ERR)) {
+ FD_SET(p->fd, xfds);
+ *max_fd = MAX(*max_fd, p->fd);
+ }
+ }
+
+ cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
+ if (timeout >= 0 && timeout < cur_timeout) {
+ tv->tv_sec = timeout / 1000;
+ tv->tv_usec = (timeout % 1000) * 1000;
+ }
+}
+
+static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
+ bool err)
+{
+ GMainContext *context = g_main_context_default();
+
+ if (!err) {
+ int i;
+
+ for (i = 0; i < n_poll_fds; i++) {
+ GPollFD *p = &poll_fds[i];
+
+ if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
+ p->revents |= G_IO_IN;
+ }
+ if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
+ p->revents |= G_IO_OUT;
+ }
+ if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
+ p->revents |= G_IO_ERR;
+ }
+ }
+ }
+
+ if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+ g_main_context_dispatch(context);
+ }
+}
+
+#ifdef _WIN32
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+ PollingFunc *func;
+ void *opaque;
+ struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+ PollingEntry **ppe, *pe;
+ pe = g_malloc0(sizeof(PollingEntry));
+ pe->func = func;
+ pe->opaque = opaque;
+ for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+ *ppe = pe;
+ return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+ PollingEntry **ppe, *pe;
+ for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+ pe = *ppe;
+ if (pe->func == func && pe->opaque == opaque) {
+ *ppe = pe->next;
+ g_free(pe);
+ break;
+ }
+ }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+ int num;
+ HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+ WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+ void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ WaitObjects *w = &wait_objects;
+ if (w->num >= MAXIMUM_WAIT_OBJECTS) {
+ return -1;
+ }
+ w->events[w->num] = handle;
+ w->func[w->num] = func;
+ w->opaque[w->num] = opaque;
+ w->num++;
+ return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ int i, found;
+ WaitObjects *w = &wait_objects;
+
+ found = 0;
+ for (i = 0; i < w->num; i++) {
+ if (w->events[i] == handle) {
+ found = 1;
+ }
+ if (found) {
+ w->events[i] = w->events[i + 1];
+ w->func[i] = w->func[i + 1];
+ w->opaque[i] = w->opaque[i + 1];
+ }
+ }
+ if (found) {
+ w->num--;
+ }
+}
+
+static void os_host_main_loop_wait(int *timeout)
+{
+ int ret, ret2, i;
+ PollingEntry *pe;
+
+ /* XXX: need to suppress polling by better using win32 events */
+ ret = 0;
+ for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
+ ret |= pe->func(pe->opaque);
+ }
+ if (ret == 0) {
+ int err;
+ WaitObjects *w = &wait_objects;
+
+ qemu_mutex_unlock_iothread();
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+ qemu_mutex_lock_iothread();
+ if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+ if (w->func[ret - WAIT_OBJECT_0]) {
+ w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+ }
+
+ /* Check for additional signaled events */
+ for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+ /* Check if event is signaled */
+ ret2 = WaitForSingleObject(w->events[i], 0);
+ if (ret2 == WAIT_OBJECT_0) {
+ if (w->func[i]) {
+ w->func[i](w->opaque[i]);
+ }
+ } else if (ret2 != WAIT_TIMEOUT) {
+ err = GetLastError();
+ fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ }
+ }
+ } else if (ret != WAIT_TIMEOUT) {
+ err = GetLastError();
+ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+ }
+ }
+
+ *timeout = 0;
+}
+#else
+static inline void os_host_main_loop_wait(int *timeout)
+{
+}
+#endif
+
+int main_loop_wait(int nonblocking)
+{
+ fd_set rfds, wfds, xfds;
+ int ret, nfds;
+ struct timeval tv;
+ int timeout;
+
+ if (nonblocking) {
+ timeout = 0;
+ } else {
+ timeout = qemu_calculate_timeout();
+ qemu_bh_update_timeout(&timeout);
+ }
+
+ os_host_main_loop_wait(&timeout);
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ /* poll any events */
+ /* XXX: separate device handlers from system ones */
+ nfds = -1;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+
+#ifdef CONFIG_SLIRP
+ slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+#endif
+ qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+ glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
+
+ if (timeout > 0) {
+ qemu_mutex_unlock_iothread();
+ }
+
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+
+ if (timeout > 0) {
+ qemu_mutex_lock_iothread();
+ }
+
+ glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+ qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+#ifdef CONFIG_SLIRP
+ slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+#endif
+
+ qemu_run_all_timers();
+
+ /* Check bottom-halves last in case any of the earlier events triggered
+ them. */
+ qemu_bh_poll();
+
+ return ret;
+}
diff --git a/main-loop.h b/main-loop.h
new file mode 100644
index 0000000000..8a716b133f
--- /dev/null
+++ b/main-loop.h
@@ -0,0 +1,351 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_MAIN_LOOP_H
+#define QEMU_MAIN_LOOP_H 1
+
+#ifdef SIGRTMIN
+#define SIG_IPI (SIGRTMIN+4)
+#else
+#define SIG_IPI SIGUSR1
+#endif
+
+/**
+ * qemu_init_main_loop: Set up the process so that it can run the main loop.
+ *
+ * This includes setting up signal handlers. It should be called before
+ * any other threads are created. In addition, threads other than the
+ * main one should block signals that are trapped by the main loop.
+ * For simplicity, you can consider these signals to be safe: SIGUSR1,
+ * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
+ * signals if available. Remember that Windows in practice does not have
+ * signals, though.
+ */
+int qemu_init_main_loop(void);
+
+/**
+ * main_loop_wait: Run one iteration of the main loop.
+ *
+ * If @nonblocking is true, poll for events, otherwise suspend until
+ * one actually occurs. The main loop usually consists of a loop that
+ * repeatedly calls main_loop_wait(false).
+ *
+ * Main loop services include file descriptor callbacks, bottom halves
+ * and timers (defined in qemu-timer.h). Bottom halves are similar to timers
+ * that execute immediately, but have a lower overhead and scheduling them
+ * is wait-free, thread-safe and signal-safe.
+ *
+ * It is sometimes useful to put a whole program in a coroutine. In this
+ * case, the coroutine actually should be started from within the main loop,
+ * so that the main loop can run whenever the coroutine yields. To do this,
+ * you can use a bottom half to enter the coroutine as soon as the main loop
+ * starts:
+ *
+ * void enter_co_bh(void *opaque) {
+ * QEMUCoroutine *co = opaque;
+ * qemu_coroutine_enter(co, NULL);
+ * }
+ *
+ * ...
+ * QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry);
+ * QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co);
+ * qemu_bh_schedule(start_bh);
+ * while (...) {
+ * main_loop_wait(false);
+ * }
+ *
+ * (In the future we may provide a wrapper for this).
+ *
+ * @nonblocking: Whether the caller should block until an event occurs.
+ */
+int main_loop_wait(int nonblocking);
+
+/**
+ * qemu_notify_event: Force processing of pending events.
+ *
+ * Similar to signaling a condition variable, qemu_notify_event forces
+ * main_loop_wait to look at pending events and exit. The caller of
+ * main_loop_wait will usually call it again very soon, so qemu_notify_event
+ * also has the side effect of recalculating the sets of file descriptors
+ * that the main loop waits for.
+ *
+ * Calling qemu_notify_event is rarely necessary, because main loop
+ * services (bottom halves and timers) call it themselves. One notable
+ * exception occurs when using qemu_set_fd_handler2 (see below).
+ */
+void qemu_notify_event(void);
+
+#ifdef _WIN32
+/* return TRUE if no sleep should be done afterwards */
+typedef int PollingFunc(void *opaque);
+
+/**
+ * qemu_add_polling_cb: Register a Windows-specific polling callback
+ *
+ * Currently, under Windows some events are polled rather than waited for.
+ * Polling callbacks do not ensure that @func is called timely, because
+ * the main loop might wait for an arbitrarily long time. If possible,
+ * you should instead create a separate thread that does a blocking poll
+ * and set a Win32 event object. The event can then be passed to
+ * qemu_add_wait_object.
+ *
+ * Polling callbacks really have nothing Windows specific in them, but
+ * as they are a hack and are currenly not necessary under POSIX systems,
+ * they are only available when QEMU is running under Windows.
+ *
+ * @func: The function that does the polling, and returns 1 to force
+ * immediate completion of main_loop_wait.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_polling_cb(PollingFunc *func, void *opaque);
+
+/**
+ * qemu_del_polling_cb: Unregister a Windows-specific polling callback
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_polling_cb.
+ *
+ * @func: The function that was passed to qemu_add_polling_cb.
+ * @opaque: A pointer-size value that was passed to qemu_add_polling_cb.
+ */
+void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+/**
+ * qemu_add_wait_object: Register a callback for a Windows handle
+ *
+ * Under Windows, the iohandler mechanism can only be used with sockets.
+ * QEMU must use the WaitForMultipleObjects API to wait on other handles.
+ * This function registers a #HANDLE with QEMU, so that it will be included
+ * in the main loop's calls to WaitForMultipleObjects. When the handle
+ * is in a signaled state, QEMU will call @func.
+ *
+ * @handle: The Windows handle to be observed.
+ * @func: A function to be called when @handle is in a signaled state.
+ * @opaque: A pointer-size value that is passed to @func.
+ */
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+
+/**
+ * qemu_del_wait_object: Unregister a callback for a Windows handle
+ *
+ * This function removes a callback that was registered with
+ * qemu_add_wait_object.
+ *
+ * @func: The function that was passed to qemu_add_wait_object.
+ * @opaque: A pointer-size value that was passed to qemu_add_wait_object.
+ */
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+#endif
+
+/* async I/O support */
+
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanReadHandler(void *opaque);
+typedef void IOHandler(void *opaque);
+
+/**
+ * qemu_set_fd_handler2: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * @fd_read_poll can be used to disable the @fd_read callback temporarily.
+ * This is useful to avoid calling qemu_set_fd_handler2 every time the
+ * client becomes interested in reading (or dually, stops being interested).
+ * A typical example is when @fd is a listening socket and you want to bound
+ * the number of active clients. Remember to call qemu_notify_event whenever
+ * the condition may change from %false to %true.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler2 are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed. Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read_poll: A function that returns 1 if the @fd_read callback
+ * should be fired. If the function returns 0, the main loop will not
+ * end its iteration even if @fd becomes readable.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read_poll,
+ * @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler2(int fd,
+ IOCanReadHandler *fd_read_poll,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
+ void *opaque);
+
+/**
+ * qemu_set_fd_handler: Register a file descriptor with the main loop
+ *
+ * This function tells the main loop to wake up whenever one of the
+ * following conditions is true:
+ *
+ * 1) if @fd_write is not %NULL, when the file descriptor is writable;
+ *
+ * 2) if @fd_read is not %NULL, when the file descriptor is readable.
+ *
+ * The callbacks that are set up by qemu_set_fd_handler are level-triggered.
+ * If @fd_read does not read from @fd, or @fd_write does not write to @fd
+ * until its buffers are full, they will be called again on the next
+ * iteration.
+ *
+ * @fd: The file descriptor to be observed. Under Windows it must be
+ * a #SOCKET.
+ *
+ * @fd_read: A level-triggered callback that is fired if @fd is readable
+ * at the beginning of a main loop iteration, or if it becomes readable
+ * during one.
+ *
+ * @fd_write: A level-triggered callback that is fired when @fd is writable
+ * at the beginning of a main loop iteration, or if it becomes writable
+ * during one.
+ *
+ * @opaque: A pointer-sized value that is passed to @fd_read and @fd_write.
+ */
+int qemu_set_fd_handler(int fd,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
+ void *opaque);
+
+typedef struct QEMUBH QEMUBH;
+typedef void QEMUBHFunc(void *opaque);
+
+/**
+ * qemu_bh_new: Allocate a new bottom half structure.
+ *
+ * Bottom halves are lightweight callbacks whose invocation is guaranteed
+ * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
+ * is opaque and must be allocated prior to its use.
+ */
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
+
+/**
+ * qemu_bh_schedule: Schedule a bottom half.
+ *
+ * Scheduling a bottom half interrupts the main loop and causes the
+ * execution of the callback that was passed to qemu_bh_new.
+ *
+ * Bottom halves that are scheduled from a bottom half handler are instantly
+ * invoked. This can create an infinite loop if a bottom half handler
+ * schedules itself.
+ *
+ * @bh: The bottom half to be scheduled.
+ */
+void qemu_bh_schedule(QEMUBH *bh);
+
+/**
+ * qemu_bh_cancel: Cancel execution of a bottom half.
+ *
+ * Canceling execution of a bottom half undoes the effect of calls to
+ * qemu_bh_schedule without freeing its resources yet. While cancellation
+ * itself is also wait-free and thread-safe, it can of course race with the
+ * loop that executes bottom halves unless you are holding the iothread
+ * mutex. This makes it mostly useless if you are not holding the mutex.
+ *
+ * @bh: The bottom half to be canceled.
+ */
+void qemu_bh_cancel(QEMUBH *bh);
+
+/**
+ *qemu_bh_delete: Cancel execution of a bottom half and free its resources.
+ *
+ * Deleting a bottom half frees the memory that was allocated for it by
+ * qemu_bh_new. It also implies canceling the bottom half if it was
+ * scheduled.
+ *
+ * @bh: The bottom half to be deleted.
+ */
+void qemu_bh_delete(QEMUBH *bh);
+
+#ifdef CONFIG_POSIX
+/**
+ * qemu_add_child_watch: Register a child process for reaping.
+ *
+ * Under POSIX systems, a parent process must read the exit status of
+ * its child processes using waitpid, or the operating system will not
+ * free some of the resources attached to that process.
+ *
+ * This function directs the QEMU main loop to observe a child process
+ * and call waitpid as soon as it exits; the watch is then removed
+ * automatically. It is useful whenever QEMU forks a child process
+ * but will find out about its termination by other means such as a
+ * "broken pipe".
+ *
+ * @pid: The pid that QEMU should observe.
+ */
+int qemu_add_child_watch(pid_t pid);
+#endif
+
+/**
+ * qemu_mutex_lock_iothread: Lock the main loop mutex.
+ *
+ * This function locks the main loop mutex. The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select). The mutex should be taken
+ * by threads other than the main loop thread when calling
+ * qemu_bh_new(), qemu_set_fd_handler() and basically all other
+ * functions documented in this file.
+ */
+void qemu_mutex_lock_iothread(void);
+
+/**
+ * qemu_mutex_unlock_iothread: Unlock the main loop mutex.
+ *
+ * This function unlocks the main loop mutex. The mutex is taken by
+ * qemu_init_main_loop and always taken except while waiting on
+ * external events (such as with select). The mutex should be unlocked
+ * as soon as possible by threads other than the main loop thread,
+ * because it prevents the main loop from processing callbacks,
+ * including timers and bottom halves.
+ */
+void qemu_mutex_unlock_iothread(void);
+
+/* internal interfaces */
+
+void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
+void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+
+void qemu_bh_schedule_idle(QEMUBH *bh);
+int qemu_bh_poll(void);
+void qemu_bh_update_timeout(int *timeout);
+
+#endif
diff --git a/os-win32.c b/os-win32.c
index f09f01fc49..79094016f1 100644
--- a/os-win32.c
+++ b/os-win32.c
@@ -48,129 +48,6 @@ int setenv(const char *name, const char *value, int overwrite)
return result;
}
-/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
- PollingFunc *func;
- void *opaque;
- struct PollingEntry *next;
-} PollingEntry;
-
-static PollingEntry *first_polling_entry;
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- pe = g_malloc0(sizeof(PollingEntry));
- pe->func = func;
- pe->opaque = opaque;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
- *ppe = pe;
- return 0;
-}
-
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
- pe = *ppe;
- if (pe->func == func && pe->opaque == opaque) {
- *ppe = pe->next;
- g_free(pe);
- break;
- }
- }
-}
-
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
- int num;
- HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
- WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
- void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- WaitObjects *w = &wait_objects;
-
- if (w->num >= MAXIMUM_WAIT_OBJECTS)
- return -1;
- w->events[w->num] = handle;
- w->func[w->num] = func;
- w->opaque[w->num] = opaque;
- w->num++;
- return 0;
-}
-
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- int i, found;
- WaitObjects *w = &wait_objects;
-
- found = 0;
- for (i = 0; i < w->num; i++) {
- if (w->events[i] == handle)
- found = 1;
- if (found) {
- w->events[i] = w->events[i + 1];
- w->func[i] = w->func[i + 1];
- w->opaque[i] = w->opaque[i + 1];
- }
- }
- if (found)
- w->num--;
-}
-
-void os_host_main_loop_wait(int *timeout)
-{
- int ret, ret2, i;
- PollingEntry *pe;
-
- /* XXX: need to suppress polling by better using win32 events */
- ret = 0;
- for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
- ret |= pe->func(pe->opaque);
- }
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
-
- qemu_mutex_unlock_iothread();
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
- qemu_mutex_lock_iothread();
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0])
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
- for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if(ret2 == WAIT_OBJECT_0) {
- if (w->func[i])
- w->func[i](w->opaque[i]);
- } else if (ret2 == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
- } else if (ret == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
- }
- }
-
- *timeout = 0;
-}
-
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
{
exit(STATUS_CONTROL_C_EXIT);
diff --git a/qemu-char.c b/qemu-char.c
index fb9e058961..9fd94d1bb4 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -538,6 +538,9 @@ int send_all(int fd, const void *_buf, int len1)
}
#endif /* !_WIN32 */
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients;
+
#ifndef _WIN32
typedef struct {
@@ -545,8 +548,6 @@ typedef struct {
int max_size;
} FDCharDriver;
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients = 0;
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
@@ -1451,6 +1452,8 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
#else /* _WIN32 */
+static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+
typedef struct {
int max_size;
HANDLE hcom, hrecv, hsend;
@@ -1459,6 +1462,14 @@ typedef struct {
DWORD len;
} WinCharState;
+typedef struct {
+ HANDLE hStdIn;
+ HANDLE hInputReadyEvent;
+ HANDLE hInputDoneEvent;
+ HANDLE hInputThread;
+ uint8_t win_stdio_buf;
+} WinStdioCharState;
+
#define NSENDBUF 2048
#define NRECVBUF 2048
#define MAXCONNECT 1
@@ -1809,6 +1820,217 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
return qemu_chr_open_win_file(fd_out, _chr);
}
+
+static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD dwSize;
+ int len1;
+
+ len1 = len;
+
+ while (len1 > 0) {
+ if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
+ break;
+ }
+ buf += dwSize;
+ len1 -= dwSize;
+ }
+
+ return len - len1;
+}
+
+static void win_stdio_wait_func(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ WinStdioCharState *stdio = chr->opaque;
+ INPUT_RECORD buf[4];
+ int ret;
+ DWORD dwSize;
+ int i;
+
+ ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf),
+ &dwSize);
+
+ if (!ret) {
+ /* Avoid error storm */
+ qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
+ return;
+ }
+
+ for (i = 0; i < dwSize; i++) {
+ KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
+
+ if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
+ int j;
+ if (kev->uChar.AsciiChar != 0) {
+ for (j = 0; j < kev->wRepeatCount; j++) {
+ if (qemu_chr_be_can_write(chr)) {
+ uint8_t c = kev->uChar.AsciiChar;
+ qemu_chr_be_write(chr, &c, 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+static DWORD WINAPI win_stdio_thread(LPVOID param)
+{
+ CharDriverState *chr = param;
+ WinStdioCharState *stdio = chr->opaque;
+ int ret;
+ DWORD dwSize;
+
+ while (1) {
+
+ /* Wait for one byte */
+ ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
+
+ /* Exit in case of error, continue if nothing read */
+ if (!ret) {
+ break;
+ }
+ if (!dwSize) {
+ continue;
+ }
+
+ /* Some terminal emulator returns \r\n for Enter, just pass \n */
+ if (stdio->win_stdio_buf == '\r') {
+ continue;
+ }
+
+ /* Signal the main thread and wait until the byte was eaten */
+ if (!SetEvent(stdio->hInputReadyEvent)) {
+ break;
+ }
+ if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
+ != WAIT_OBJECT_0) {
+ break;
+ }
+ }
+
+ qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
+ return 0;
+}
+
+static void win_stdio_thread_wait_func(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ WinStdioCharState *stdio = chr->opaque;
+
+ if (qemu_chr_be_can_write(chr)) {
+ qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
+ }
+
+ SetEvent(stdio->hInputDoneEvent);
+}
+
+static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
+{
+ WinStdioCharState *stdio = chr->opaque;
+ DWORD dwMode = 0;
+
+ GetConsoleMode(stdio->hStdIn, &dwMode);
+
+ if (echo) {
+ SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
+ } else {
+ SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
+ }
+}
+
+static void win_stdio_close(CharDriverState *chr)
+{
+ WinStdioCharState *stdio = chr->opaque;
+
+ if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
+ CloseHandle(stdio->hInputReadyEvent);
+ }
+ if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
+ CloseHandle(stdio->hInputDoneEvent);
+ }
+ if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
+ TerminateThread(stdio->hInputThread, 0);
+ }
+
+ g_free(chr->opaque);
+ g_free(chr);
+ stdio_nb_clients--;
+}
+
+static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr)
+{
+ CharDriverState *chr;
+ WinStdioCharState *stdio;
+ DWORD dwMode;
+ int is_console = 0;
+
+ if (stdio_nb_clients >= STDIO_MAX_CLIENTS
+ || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
+ return -EIO;
+ }
+
+ chr = g_malloc0(sizeof(CharDriverState));
+ stdio = g_malloc0(sizeof(WinStdioCharState));
+
+ stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "cannot open stdio: invalid handle\n");
+ exit(1);
+ }
+
+ is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+
+ chr->opaque = stdio;
+ chr->chr_write = win_stdio_write;
+ chr->chr_close = win_stdio_close;
+
+ if (stdio_nb_clients == 0) {
+ if (is_console) {
+ if (qemu_add_wait_object(stdio->hStdIn,
+ win_stdio_wait_func, chr)) {
+ fprintf(stderr, "qemu_add_wait_object: failed\n");
+ }
+ } else {
+ DWORD dwId;
+
+ stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread,
+ chr, 0, &dwId);
+
+ if (stdio->hInputThread == INVALID_HANDLE_VALUE
+ || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+ || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "cannot create stdio thread or event\n");
+ exit(1);
+ }
+ if (qemu_add_wait_object(stdio->hInputReadyEvent,
+ win_stdio_thread_wait_func, chr)) {
+ fprintf(stderr, "qemu_add_wait_object: failed\n");
+ }
+ }
+ }
+
+ dwMode |= ENABLE_LINE_INPUT;
+
+ stdio_clients[stdio_nb_clients++] = chr;
+ if (stdio_nb_clients == 1 && is_console) {
+ /* set the terminal in raw mode */
+ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
+ dwMode |= ENABLE_PROCESSED_INPUT;
+ }
+
+ SetConsoleMode(stdio->hStdIn, dwMode);
+
+ chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
+ qemu_chr_fe_set_echo(chr, false);
+
+ *_chr = chr;
+
+ return 0;
+}
#endif /* !_WIN32 */
/***********************************************************/
@@ -2519,6 +2741,7 @@ static const struct {
{ .name = "pipe", .open = qemu_chr_open_win_pipe },
{ .name = "console", .open = qemu_chr_open_win_con },
{ .name = "serial", .open = qemu_chr_open_win },
+ { .name = "stdio", .open = qemu_chr_open_win_stdio },
#else
{ .name = "file", .open = qemu_chr_open_file_out },
{ .name = "pipe", .open = qemu_chr_open_pipe },
diff --git a/qemu-char.h b/qemu-char.h
index eebbdd8f01..7efcf99f53 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -7,6 +7,7 @@
#include "qemu-config.h"
#include "qobject.h"
#include "qstring.h"
+#include "main-loop.h"
/* character device */
@@ -237,15 +238,4 @@ void qemu_chr_close_mem(CharDriverState *chr);
QString *qemu_chr_mem_to_qs(CharDriverState *chr);
size_t qemu_chr_mem_osize(const CharDriverState *chr);
-/* async I/O support */
-
-int qemu_set_fd_handler2(int fd,
- IOCanReadHandler *fd_read_poll,
- IOHandler *fd_read,
- IOHandler *fd_write,
- void *opaque);
-int qemu_set_fd_handler(int fd,
- IOHandler *fd_read,
- IOHandler *fd_write,
- void *opaque);
#endif
diff --git a/qemu-common.h b/qemu-common.h
index 5e87bdf2f2..1c15cb17a7 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -13,7 +13,6 @@
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUFile QEMUFile;
-typedef struct QEMUBH QEMUBH;
typedef struct DeviceState DeviceState;
struct Monitor;
@@ -96,6 +95,10 @@ static inline char *realpath(const char *path, char *resolved_path)
}
#endif
+/* icount */
+void configure_icount(const char *option);
+extern int use_icount;
+
/* FIXME: Remove NEED_CPU_H. */
#ifndef NEED_CPU_H
@@ -113,23 +116,6 @@ static inline char *realpath(const char *path, char *resolved_path)
int qemu_main(int argc, char **argv, char **envp);
#endif
-/* bottom halves */
-typedef void QEMUBHFunc(void *opaque);
-
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
-void qemu_bh_schedule(QEMUBH *bh);
-/* Bottom halfs that are scheduled from a bottom half handler are instantly
- * invoked. This can create an infinite loop if a bottom half handler
- * schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by
- * ensuring that the bottom half isn't executed until the next main loop
- * iteration.
- */
-void qemu_bh_schedule_idle(QEMUBH *bh);
-void qemu_bh_cancel(QEMUBH *bh);
-void qemu_bh_delete(QEMUBH *bh);
-int qemu_bh_poll(void);
-void qemu_bh_update_timeout(int *timeout);
-
void qemu_get_timedate(struct tm *tm, int offset);
int qemu_timedate_diff(struct tm *tm);
@@ -183,16 +169,12 @@ const char *path(const char *pathname);
void *qemu_oom_check(void *ptr);
-void qemu_mutex_lock_iothread(void);
-void qemu_mutex_unlock_iothread(void);
-
int qemu_open(const char *name, int flags, ...);
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
QEMU_WARN_UNUSED_RESULT;
void qemu_set_cloexec(int fd);
#ifndef _WIN32
-int qemu_add_child_watch(pid_t pid);
int qemu_eventfd(int pipefd[2]);
int qemu_pipe(int pipefd[2]);
#endif
@@ -207,14 +189,6 @@ int qemu_pipe(int pipefd[2]);
void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-/* IO callbacks. */
-typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
-typedef int IOCanReadHandler(void *opaque);
-typedef void IOHandler(void *opaque);
-
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
-
struct ParallelIOArg {
void *buffer;
int count;
@@ -276,9 +250,6 @@ void cpu_exec_init_all(void);
void cpu_save(QEMUFile *f, void *opaque);
int cpu_load(QEMUFile *f, void *opaque, int version_id);
-/* Force QEMU to process pending events */
-void qemu_notify_event(void);
-
/* Unblock cpu */
void qemu_cpu_kick(void *env);
void qemu_cpu_kick_self(void);
diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
index 2a385a3bb8..6b58160058 100644
--- a/qemu-coroutine-lock.c
+++ b/qemu-coroutine-lock.c
@@ -26,6 +26,7 @@
#include "qemu-coroutine.h"
#include "qemu-coroutine-int.h"
#include "qemu-queue.h"
+#include "main-loop.h"
#include "trace.h"
static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
diff --git a/qemu-os-posix.h b/qemu-os-posix.h
index 81fd9ab389..920499d836 100644
--- a/qemu-os-posix.h
+++ b/qemu-os-posix.h
@@ -26,10 +26,6 @@
#ifndef QEMU_OS_POSIX_H
#define QEMU_OS_POSIX_H
-static inline void os_host_main_loop_wait(int *timeout)
-{
-}
-
void os_set_line_buffering(void);
void os_set_proc_name(const char *s);
void os_setup_signal_handling(void);
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index 8a069d7fb6..8eda4bdc20 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -28,26 +28,11 @@
#include <windows.h>
#include <winsock2.h>
+#include "main-loop.h"
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
-/* Polling handling */
-
-/* return TRUE if no sleep should be done afterwards */
-typedef int PollingFunc(void *opaque);
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque);
-void qemu_del_polling_cb(PollingFunc *func, void *opaque);
-
-/* Wait objects handling */
-typedef void WaitObjectFunc(void *opaque);
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-
-void os_host_main_loop_wait(int *timeout);
-
static inline void os_setup_signal_handling(void) {}
static inline void os_daemonize(void) {}
static inline void os_setup_post(void) {}
diff --git a/qemu-timer.c b/qemu-timer.c
index ad1fc8b871..f11a28dd03 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -46,82 +46,6 @@
#include "qemu-timer.h"
-/* Conversion factor from emulated instructions to virtual clock ticks. */
-int icount_time_shift;
-/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
-#define MAX_ICOUNT_SHIFT 10
-/* Compensate for varying guest execution speed. */
-int64_t qemu_icount_bias;
-static QEMUTimer *icount_rt_timer;
-static QEMUTimer *icount_vm_timer;
-
-/***********************************************************/
-/* guest cycle counter */
-
-typedef struct TimersState {
- int64_t cpu_ticks_prev;
- int64_t cpu_ticks_offset;
- int64_t cpu_clock_offset;
- int32_t cpu_ticks_enabled;
- int64_t dummy;
-} TimersState;
-
-TimersState timers_state;
-
-/* return the host CPU cycle counter and handle stop/restart */
-int64_t cpu_get_ticks(void)
-{
- if (use_icount) {
- return cpu_get_icount();
- }
- if (!timers_state.cpu_ticks_enabled) {
- return timers_state.cpu_ticks_offset;
- } else {
- int64_t ticks;
- ticks = cpu_get_real_ticks();
- if (timers_state.cpu_ticks_prev > ticks) {
- /* Note: non increasing ticks may happen if the host uses
- software suspend */
- timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
- }
- timers_state.cpu_ticks_prev = ticks;
- return ticks + timers_state.cpu_ticks_offset;
- }
-}
-
-/* return the host CPU monotonic timer and handle stop/restart */
-static int64_t cpu_get_clock(void)
-{
- int64_t ti;
- if (!timers_state.cpu_ticks_enabled) {
- return timers_state.cpu_clock_offset;
- } else {
- ti = get_clock();
- return ti + timers_state.cpu_clock_offset;
- }
-}
-
-/* enable cpu_get_ticks() */
-void cpu_enable_ticks(void)
-{
- if (!timers_state.cpu_ticks_enabled) {
- timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
- timers_state.cpu_clock_offset -= get_clock();
- timers_state.cpu_ticks_enabled = 1;
- }
-}
-
-/* disable cpu_get_ticks() : the clock is stopped. You must not call
- cpu_get_ticks() after that. */
-void cpu_disable_ticks(void)
-{
- if (timers_state.cpu_ticks_enabled) {
- timers_state.cpu_ticks_offset = cpu_get_ticks();
- timers_state.cpu_clock_offset = cpu_get_clock();
- timers_state.cpu_ticks_enabled = 0;
- }
-}
-
/***********************************************************/
/* timers */
@@ -133,7 +57,7 @@ struct QEMUClock {
int type;
int enabled;
- QEMUTimer *warp_timer;
+ QEMUTimer *active_timers;
NotifierList reset_notifiers;
int64_t last;
@@ -152,7 +76,7 @@ struct qemu_alarm_timer {
char const *name;
int (*start)(struct qemu_alarm_timer *t);
void (*stop)(struct qemu_alarm_timer *t);
- void (*rearm)(struct qemu_alarm_timer *t);
+ void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns);
#if defined(__linux__)
int fd;
timer_t timer;
@@ -180,12 +104,46 @@ static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
return !!t->rearm;
}
+static int64_t qemu_next_alarm_deadline(void)
+{
+ int64_t delta;
+ int64_t rtdelta;
+
+ if (!use_icount && vm_clock->active_timers) {
+ delta = vm_clock->active_timers->expire_time -
+ qemu_get_clock_ns(vm_clock);
+ } else {
+ delta = INT32_MAX;
+ }
+ if (host_clock->active_timers) {
+ int64_t hdelta = host_clock->active_timers->expire_time -
+ qemu_get_clock_ns(host_clock);
+ if (hdelta < delta) {
+ delta = hdelta;
+ }
+ }
+ if (rt_clock->active_timers) {
+ rtdelta = (rt_clock->active_timers->expire_time -
+ qemu_get_clock_ns(rt_clock));
+ if (rtdelta < delta) {
+ delta = rtdelta;
+ }
+ }
+
+ return delta;
+}
+
static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
{
- if (!alarm_has_dynticks(t))
+ int64_t nearest_delta_ns;
+ assert(alarm_has_dynticks(t));
+ if (!rt_clock->active_timers &&
+ !vm_clock->active_timers &&
+ !host_clock->active_timers) {
return;
-
- t->rearm(t);
+ }
+ nearest_delta_ns = qemu_next_alarm_deadline();
+ t->rearm(t, nearest_delta_ns);
}
/* TODO: MIN_TIMER_REARM_NS should be optimized */
@@ -195,83 +153,28 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
static int mm_start_timer(struct qemu_alarm_timer *t);
static void mm_stop_timer(struct qemu_alarm_timer *t);
-static void mm_rearm_timer(struct qemu_alarm_timer *t);
+static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
static int win32_start_timer(struct qemu_alarm_timer *t);
static void win32_stop_timer(struct qemu_alarm_timer *t);
-static void win32_rearm_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
#else
static int unix_start_timer(struct qemu_alarm_timer *t);
static void unix_stop_timer(struct qemu_alarm_timer *t);
-static void unix_rearm_timer(struct qemu_alarm_timer *t);
+static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
#ifdef __linux__
static int dynticks_start_timer(struct qemu_alarm_timer *t);
static void dynticks_stop_timer(struct qemu_alarm_timer *t);
-static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta);
#endif /* __linux__ */
#endif /* _WIN32 */
-/* Correlation between real and virtual time is always going to be
- fairly approximate, so ignore small variation.
- When the guest is idle real and virtual time will be aligned in
- the IO wait loop. */
-#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
-
-static void icount_adjust(void)
-{
- int64_t cur_time;
- int64_t cur_icount;
- int64_t delta;
- static int64_t last_delta;
- /* If the VM is not running, then do nothing. */
- if (!runstate_is_running())
- return;
-
- cur_time = cpu_get_clock();
- cur_icount = qemu_get_clock_ns(vm_clock);
- delta = cur_icount - cur_time;
- /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
- if (delta > 0
- && last_delta + ICOUNT_WOBBLE < delta * 2
- && icount_time_shift > 0) {
- /* The guest is getting too far ahead. Slow time down. */
- icount_time_shift--;
- }
- if (delta < 0
- && last_delta - ICOUNT_WOBBLE > delta * 2
- && icount_time_shift < MAX_ICOUNT_SHIFT) {
- /* The guest is getting too far behind. Speed time up. */
- icount_time_shift++;
- }
- last_delta = delta;
- qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
-}
-
-static void icount_adjust_rt(void * opaque)
-{
- qemu_mod_timer(icount_rt_timer,
- qemu_get_clock_ms(rt_clock) + 1000);
- icount_adjust();
-}
-
-static void icount_adjust_vm(void * opaque)
-{
- qemu_mod_timer(icount_vm_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
- icount_adjust();
-}
-
-int64_t qemu_icount_round(int64_t count)
-{
- return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
-}
-
static struct qemu_alarm_timer alarm_timers[] = {
#ifndef _WIN32
#ifdef __linux__
@@ -352,14 +255,10 @@ next:
}
}
-#define QEMU_NUM_CLOCKS 3
-
QEMUClock *rt_clock;
QEMUClock *vm_clock;
QEMUClock *host_clock;
-static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
-
static QEMUClock *qemu_new_clock(int type)
{
QEMUClock *clock;
@@ -367,101 +266,43 @@ static QEMUClock *qemu_new_clock(int type)
clock = g_malloc0(sizeof(QEMUClock));
clock->type = type;
clock->enabled = 1;
+ clock->last = INT64_MIN;
notifier_list_init(&clock->reset_notifiers);
- /* required to detect & report backward jumps */
- if (type == QEMU_CLOCK_HOST) {
- clock->last = get_clock_realtime();
- }
return clock;
}
void qemu_clock_enable(QEMUClock *clock, int enabled)
{
+ bool old = clock->enabled;
clock->enabled = enabled;
+ if (enabled && !old) {
+ qemu_rearm_alarm_timer(alarm_timer);
+ }
}
-static int64_t vm_clock_warp_start;
-
-static void icount_warp_rt(void *opaque)
+int64_t qemu_clock_has_timers(QEMUClock *clock)
{
- if (vm_clock_warp_start == -1) {
- return;
- }
-
- if (runstate_is_running()) {
- int64_t clock = qemu_get_clock_ns(rt_clock);
- int64_t warp_delta = clock - vm_clock_warp_start;
- if (use_icount == 1) {
- qemu_icount_bias += warp_delta;
- } else {
- /*
- * In adaptive mode, do not let the vm_clock run too
- * far ahead of real time.
- */
- int64_t cur_time = cpu_get_clock();
- int64_t cur_icount = qemu_get_clock_ns(vm_clock);
- int64_t delta = cur_time - cur_icount;
- qemu_icount_bias += MIN(warp_delta, delta);
- }
- if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
- qemu_get_clock_ns(vm_clock))) {
- qemu_notify_event();
- }
- }
- vm_clock_warp_start = -1;
+ return !!clock->active_timers;
}
-void qemu_clock_warp(QEMUClock *clock)
+int64_t qemu_clock_expired(QEMUClock *clock)
{
- int64_t deadline;
+ return (clock->active_timers &&
+ clock->active_timers->expire_time < qemu_get_clock_ns(clock));
+}
- if (!clock->warp_timer) {
- return;
- }
+int64_t qemu_clock_deadline(QEMUClock *clock)
+{
+ /* To avoid problems with overflow limit this to 2^32. */
+ int64_t delta = INT32_MAX;
- /*
- * There are too many global variables to make the "warp" behavior
- * applicable to other clocks. But a clock argument removes the
- * need for if statements all over the place.
- */
- assert(clock == vm_clock);
-
- /*
- * If the CPUs have been sleeping, advance the vm_clock timer now. This
- * ensures that the deadline for the timer is computed correctly below.
- * This also makes sure that the insn counter is synchronized before the
- * CPU starts running, in case the CPU is woken by an event other than
- * the earliest vm_clock timer.
- */
- icount_warp_rt(NULL);
- if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
- qemu_del_timer(clock->warp_timer);
- return;
+ if (clock->active_timers) {
+ delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock);
}
-
- vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
- deadline = qemu_next_icount_deadline();
- if (deadline > 0) {
- /*
- * Ensure the vm_clock proceeds even when the virtual CPU goes to
- * sleep. Otherwise, the CPU might be waiting for a future timer
- * interrupt to wake it up, but the interrupt never comes because
- * the vCPU isn't running any insns and thus doesn't advance the
- * vm_clock.
- *
- * An extreme solution for this problem would be to never let VCPUs
- * sleep in icount mode if there is a pending vm_clock timer; rather
- * time could just advance to the next vm_clock event. Instead, we
- * do stop VCPUs and only advance vm_clock after some "real" time,
- * (related to the time left until the next event) has passed. This
- * rt_clock timer will do this. This avoids that the warps are too
- * visible externally---for example, you will not be sending network
- * packets continously instead of every 100ms.
- */
- qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline);
- } else {
- qemu_notify_event();
+ if (delta < 0) {
+ delta = 0;
}
+ return delta;
}
QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
@@ -489,7 +330,7 @@ void qemu_del_timer(QEMUTimer *ts)
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
+ pt = &ts->clock->active_timers;
for(;;) {
t = *pt;
if (!t)
@@ -504,7 +345,7 @@ void qemu_del_timer(QEMUTimer *ts)
/* modify the current timer so that it will be fired when current_time
>= expire_time. The corresponding callback will be called. */
-static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
{
QEMUTimer **pt, *t;
@@ -513,7 +354,7 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
/* add the timer in the sorted list */
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
+ pt = &ts->clock->active_timers;
for(;;) {
t = *pt;
if (!qemu_timer_expired_ns(t, expire_time)) {
@@ -526,7 +367,7 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
*pt = ts;
/* Rearm if necessary */
- if (pt == &active_timers[ts->clock->type]) {
+ if (pt == &ts->clock->active_timers) {
if (!alarm_timer->pending) {
qemu_rearm_alarm_timer(alarm_timer);
}
@@ -538,8 +379,6 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
}
}
-/* modify the current timer so that it will be fired when current_time
- >= expire_time. The corresponding callback will be called. */
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
{
qemu_mod_timer_ns(ts, expire_time * ts->scale);
@@ -548,7 +387,7 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
int qemu_timer_pending(QEMUTimer *ts)
{
QEMUTimer *t;
- for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+ for (t = ts->clock->active_timers; t != NULL; t = t->next) {
if (t == ts)
return 1;
}
@@ -569,7 +408,7 @@ static void qemu_run_timers(QEMUClock *clock)
return;
current_time = qemu_get_clock_ns(clock);
- ptimer_head = &active_timers[clock->type];
+ ptimer_head = &clock->active_timers;
for(;;) {
ts = *ptimer_head;
if (!qemu_timer_expired_ns(ts, current_time)) {
@@ -624,79 +463,11 @@ void init_clocks(void)
rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
-
- rtc_clock = host_clock;
}
-/* save a timer */
-void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
{
- uint64_t expire_time;
-
- if (qemu_timer_pending(ts)) {
- expire_time = ts->expire_time;
- } else {
- expire_time = -1;
- }
- qemu_put_be64(f, expire_time);
-}
-
-void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
-{
- uint64_t expire_time;
-
- expire_time = qemu_get_be64(f);
- if (expire_time != -1) {
- qemu_mod_timer_ns(ts, expire_time);
- } else {
- qemu_del_timer(ts);
- }
-}
-
-static const VMStateDescription vmstate_timers = {
- .name = "timer",
- .version_id = 2,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField []) {
- VMSTATE_INT64(cpu_ticks_offset, TimersState),
- VMSTATE_INT64(dummy, TimersState),
- VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void configure_icount(const char *option)
-{
- vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
- if (!option)
- return;
-
- vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
-
- if (strcmp(option, "auto") != 0) {
- icount_time_shift = strtol(option, NULL, 0);
- use_icount = 1;
- return;
- }
-
- use_icount = 2;
-
- /* 125MIPS seems a reasonable initial guess at the guest speed.
- It will be corrected fairly quickly anyway. */
- icount_time_shift = 3;
-
- /* Have both realtime and virtual time triggers for speed adjustment.
- The realtime trigger catches emulated time passing too slowly,
- the virtual time trigger catches emulated time passing too fast.
- Realtime triggers occur even when idle, so use them less frequently
- than VM triggers. */
- icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
- qemu_mod_timer(icount_rt_timer,
- qemu_get_clock_ms(rt_clock) + 1000);
- icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
- qemu_mod_timer(icount_vm_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+ return qemu_timer_pending(ts) ? ts->expire_time : -1;
}
void qemu_run_all_timers(void)
@@ -710,16 +481,11 @@ void qemu_run_all_timers(void)
}
/* vm time timers */
- if (runstate_is_running()) {
- qemu_run_timers(vm_clock);
- }
-
+ qemu_run_timers(vm_clock);
qemu_run_timers(rt_clock);
qemu_run_timers(host_clock);
}
-static int64_t qemu_next_alarm_deadline(void);
-
#ifdef _WIN32
static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused)
#else
@@ -767,50 +533,6 @@ static void host_alarm_handler(int host_signum)
}
}
-int64_t qemu_next_icount_deadline(void)
-{
- /* To avoid problems with overflow limit this to 2^32. */
- int64_t delta = INT32_MAX;
-
- assert(use_icount);
- if (active_timers[QEMU_CLOCK_VIRTUAL]) {
- delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
- qemu_get_clock_ns(vm_clock);
- }
-
- if (delta < 0)
- delta = 0;
-
- return delta;
-}
-
-static int64_t qemu_next_alarm_deadline(void)
-{
- int64_t delta;
- int64_t rtdelta;
-
- if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
- delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
- qemu_get_clock_ns(vm_clock);
- } else {
- delta = INT32_MAX;
- }
- if (active_timers[QEMU_CLOCK_HOST]) {
- int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
- qemu_get_clock_ns(host_clock);
- if (hdelta < delta)
- delta = hdelta;
- }
- if (active_timers[QEMU_CLOCK_REALTIME]) {
- rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
- qemu_get_clock_ns(rt_clock));
- if (rtdelta < delta)
- delta = rtdelta;
- }
-
- return delta;
-}
-
#if defined(__linux__)
#include "compatfd.h"
@@ -863,20 +585,13 @@ static void dynticks_stop_timer(struct qemu_alarm_timer *t)
timer_delete(host_timer);
}
-static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t,
+ int64_t nearest_delta_ns)
{
timer_t host_timer = t->timer;
struct itimerspec timeout;
- int64_t nearest_delta_ns = INT64_MAX;
int64_t current_ns;
- assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST])
- return;
-
- nearest_delta_ns = qemu_next_alarm_deadline();
if (nearest_delta_ns < MIN_TIMER_REARM_NS)
nearest_delta_ns = MIN_TIMER_REARM_NS;
@@ -918,19 +633,12 @@ static int unix_start_timer(struct qemu_alarm_timer *t)
return 0;
}
-static void unix_rearm_timer(struct qemu_alarm_timer *t)
+static void unix_rearm_timer(struct qemu_alarm_timer *t,
+ int64_t nearest_delta_ns)
{
struct itimerval itv;
- int64_t nearest_delta_ns = INT64_MAX;
int err;
- assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST])
- return;
-
- nearest_delta_ns = qemu_next_alarm_deadline();
if (nearest_delta_ns < MIN_TIMER_REARM_NS)
nearest_delta_ns = MIN_TIMER_REARM_NS;
@@ -1017,23 +725,14 @@ static void mm_stop_timer(struct qemu_alarm_timer *t)
timeEndPeriod(mm_period);
}
-static void mm_rearm_timer(struct qemu_alarm_timer *t)
+static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
{
- int nearest_delta_ms;
-
- assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST]) {
- return;
- }
-
- timeKillEvent(mm_timer);
-
- nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+ int nearest_delta_ms = (delta + 999999) / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
+
+ timeKillEvent(mm_timer);
mm_timer = timeSetEvent(nearest_delta_ms,
mm_period,
mm_alarm_handler,
@@ -1085,19 +784,14 @@ static void win32_stop_timer(struct qemu_alarm_timer *t)
}
}
-static void win32_rearm_timer(struct qemu_alarm_timer *t)
+static void win32_rearm_timer(struct qemu_alarm_timer *t,
+ int64_t nearest_delta_ns)
{
HANDLE hTimer = t->timer;
int nearest_delta_ms;
BOOLEAN success;
- assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST])
- return;
-
- nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+ nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
@@ -1116,11 +810,11 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t)
#endif /* _WIN32 */
-static void alarm_timer_on_change_state_rearm(void *opaque, int running,
- RunState state)
+static void quit_timers(void)
{
- if (running)
- qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
+ struct qemu_alarm_timer *t = alarm_timer;
+ alarm_timer = NULL;
+ t->stop(t);
}
int init_timer_alarm(void)
@@ -1142,9 +836,9 @@ int init_timer_alarm(void)
}
/* first event is at time 0 */
+ atexit(quit_timers);
t->pending = 1;
alarm_timer = t;
- qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t);
return 0;
@@ -1152,13 +846,6 @@ fail:
return err;
}
-void quit_timers(void)
-{
- struct qemu_alarm_timer *t = alarm_timer;
- alarm_timer = NULL;
- t->stop(t);
-}
-
int qemu_calculate_timeout(void)
{
return 1000;
diff --git a/qemu-timer.h b/qemu-timer.h
index 0a43469847..67ca72e045 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -2,6 +2,7 @@
#define QEMU_TIMER_H
#include "qemu-common.h"
+#include "main-loop.h"
#include "notify.h"
#include <time.h>
#include <sys/time.h>
@@ -38,6 +39,9 @@ extern QEMUClock *vm_clock;
extern QEMUClock *host_clock;
int64_t qemu_get_clock_ns(QEMUClock *clock);
+int64_t qemu_clock_has_timers(QEMUClock *clock);
+int64_t qemu_clock_expired(QEMUClock *clock);
+int64_t qemu_clock_deadline(QEMUClock *clock);
void qemu_clock_enable(QEMUClock *clock, int enabled);
void qemu_clock_warp(QEMUClock *clock);
@@ -49,19 +53,18 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
QEMUTimerCB *cb, void *opaque);
void qemu_free_timer(QEMUTimer *ts);
void qemu_del_timer(QEMUTimer *ts);
+void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
int qemu_timer_pending(QEMUTimer *ts);
int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
+uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
void qemu_run_all_timers(void);
int qemu_alarm_pending(void);
-int64_t qemu_next_icount_deadline(void);
void configure_alarms(char const *opt);
-void configure_icount(const char *option);
int qemu_calculate_timeout(void);
void init_clocks(void);
int init_timer_alarm(void);
-void quit_timers(void);
int64_t cpu_get_ticks(void);
void cpu_enable_ticks(void);
@@ -150,12 +153,8 @@ void ptimer_run(ptimer_state *s, int oneshot);
void ptimer_stop(ptimer_state *s);
/* icount */
-int64_t qemu_icount_round(int64_t count);
-extern int64_t qemu_icount;
-extern int use_icount;
-extern int icount_time_shift;
-extern int64_t qemu_icount_bias;
int64_t cpu_get_icount(void);
+int64_t cpu_get_clock(void);
/*******************************************/
/* host CPU ticks (if available) */
@@ -311,22 +310,6 @@ static inline int64_t cpu_get_real_ticks (void)
}
#endif
-#ifdef NEED_CPU_H
-/* Deterministic execution requires that IO only be performed on the last
- instruction of a TB so that interrupts take effect immediately. */
-static inline int can_do_io(CPUState *env)
-{
- if (!use_icount)
- return 1;
-
- /* If not executing code then assume we are ok. */
- if (!env->current_tb)
- return 1;
-
- return env->can_do_io != 0;
-}
-#endif
-
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
{
diff --git a/savevm.c b/savevm.c
index cf79a56871..f01838fb2d 100644
--- a/savevm.c
+++ b/savevm.c
@@ -81,6 +81,7 @@
#include "migration.h"
#include "qemu_socket.h"
#include "qemu-queue.h"
+#include "qemu-timer.h"
#include "cpus.h"
#define SELF_ANNOUNCE_ROUNDS 5
@@ -712,6 +713,30 @@ uint64_t qemu_get_be64(QEMUFile *f)
return v;
}
+
+/* timer */
+
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_timer_expire_time_ns(ts);
+ qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_get_be64(f);
+ if (expire_time != -1) {
+ qemu_mod_timer_ns(ts, expire_time);
+ } else {
+ qemu_del_timer(ts);
+ }
+}
+
+
/* bool */
static int get_bool(QEMUFile *f, void *pv, size_t size)
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a7551235e2..890fd86c3c 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -3,8 +3,6 @@
#include "qemu-common.h"
-#ifdef CONFIG_SLIRP
-
struct Slirp;
typedef struct Slirp Slirp;
@@ -44,13 +42,4 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
-#else /* !CONFIG_SLIRP */
-
-static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
- fd_set *writefds, fd_set *xfds) { }
-
-static inline void slirp_select_poll(fd_set *readfds, fd_set *writefds,
- fd_set *xfds, int select_error) { }
-#endif /* !CONFIG_SLIRP */
-
#endif
diff --git a/sysemu.h b/sysemu.h
index 7d288f865d..22cd720016 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -8,6 +8,7 @@
#include "qemu-timer.h"
#include "qapi-types.h"
#include "notify.h"
+#include "main-loop.h"
/* vl.c */
@@ -64,8 +65,6 @@ void do_info_snapshots(Monitor *mon);
void qemu_announce_self(void);
-int main_loop_wait(int nonblocking);
-
bool qemu_savevm_state_blocked(Monitor *mon);
int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
int shared);
diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c
new file mode 100644
index 0000000000..04bd2cf9c7
--- /dev/null
+++ b/target-sparc/cc_helper.c
@@ -0,0 +1,485 @@
+/*
+ * Helpers for lazy condition code handling
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+static uint32_t compute_all_flags(CPUState *env)
+{
+ return env->psr & PSR_ICC;
+}
+
+static uint32_t compute_C_flags(CPUState *env)
+{
+ return env->psr & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_icc(int32_t dst)
+{
+ uint32_t ret = 0;
+
+ if (dst == 0) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
+ return ret;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_flags_xcc(CPUState *env)
+{
+ return env->xcc & PSR_ICC;
+}
+
+static uint32_t compute_C_flags_xcc(CPUState *env)
+{
+ return env->xcc & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_xcc(target_long dst)
+{
+ uint32_t ret = 0;
+
+ if (!dst) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
+ return ret;
+}
+#endif
+
+static inline uint32_t get_V_div_icc(target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (src2 != 0) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_div(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_V_div_icc(CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_div(CPUState *env)
+{
+ return 0;
+}
+
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
+{
+ uint32_t ret = 0;
+
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
+{
+ uint32_t ret = 0;
+
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_add_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_add_xcc(CC_DST, CC_SRC);
+ ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_add_xcc(CPUState *env)
+{
+ return get_C_add_xcc(CC_DST, CC_SRC);
+}
+#endif
+
+static uint32_t compute_all_add(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_add(CPUState *env)
+{
+ return get_C_add_icc(CC_DST, CC_SRC);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_addx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_addx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+#endif
+
+static uint32_t compute_all_addx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_addx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if ((src1 | src2) & 0x3) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_tadd(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_taddtv(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ return ret;
+}
+
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_sub_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_sub_xcc(CPUState *env)
+{
+ return get_C_sub_xcc(CC_SRC, CC_SRC2);
+}
+#endif
+
+static uint32_t compute_all_sub(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_sub(CPUState *env)
+{
+ return get_C_sub_icc(CC_SRC, CC_SRC2);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_subx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_subx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+#endif
+
+static uint32_t compute_all_subx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_subx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_tsub(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_tsubtv(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_logic(CPUState *env)
+{
+ return get_NZ_icc(CC_DST);
+}
+
+static uint32_t compute_C_logic(CPUState *env)
+{
+ return 0;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_logic_xcc(CPUState *env)
+{
+ return get_NZ_xcc(CC_DST);
+}
+#endif
+
+typedef struct CCTable {
+ uint32_t (*compute_all)(CPUState *env); /* return all the flags */
+ uint32_t (*compute_c)(CPUState *env); /* return the C flag */
+} CCTable;
+
+static const CCTable icc_table[CC_OP_NB] = {
+ /* CC_OP_DYNAMIC should never happen */
+ [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
+ [CC_OP_DIV] = { compute_all_div, compute_C_div },
+ [CC_OP_ADD] = { compute_all_add, compute_C_add },
+ [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+ [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+ [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
+ [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
+ [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+ [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+ [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
+ [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
+};
+
+#ifdef TARGET_SPARC64
+static const CCTable xcc_table[CC_OP_NB] = {
+ /* CC_OP_DYNAMIC should never happen */
+ [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
+ [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
+ [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
+ [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
+ [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
+};
+#endif
+
+void helper_compute_psr(CPUState *env)
+{
+ uint32_t new_psr;
+
+ new_psr = icc_table[CC_OP].compute_all(env);
+ env->psr = new_psr;
+#ifdef TARGET_SPARC64
+ new_psr = xcc_table[CC_OP].compute_all(env);
+ env->xcc = new_psr;
+#endif
+ CC_OP = CC_OP_FLAGS;
+}
+
+uint32_t helper_compute_C_icc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
+ return ret;
+}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 19de5ba334..6bf9275a74 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -485,10 +485,11 @@ typedef struct CPUSPARCState {
} CPUSPARCState;
#ifndef NO_CPU_IO_DEFS
-/* helper.c */
+/* cpu_init.c */
CPUSPARCState *cpu_sparc_init(const char *cpu_model);
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+/* helper.c */
int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
@@ -508,7 +509,7 @@ void gen_intermediate_code_init(CPUSPARCState *env);
/* cpu-exec.c */
int cpu_sparc_exec(CPUSPARCState *s);
-/* op_helper.c */
+/* win_helper.c */
target_ulong cpu_get_psr(CPUState *env1);
void cpu_put_psr(CPUState *env1, target_ulong val);
#ifdef TARGET_SPARC64
@@ -521,6 +522,8 @@ void cpu_change_pstate(CPUState *env1, uint32_t new_pstate);
int cpu_cwp_inc(CPUState *env1, int cwp);
int cpu_cwp_dec(CPUState *env1, int cwp);
void cpu_set_cwp(CPUState *env1, int new_cwp);
+
+/* op_helper.c */
void leon3_irq_manager(void *irq_manager, int intno);
/* sun4m.c, sun4u.c */
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
new file mode 100644
index 0000000000..6954800af0
--- /dev/null
+++ b/target-sparc/cpu_init.c
@@ -0,0 +1,848 @@
+/*
+ * Sparc CPU init helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_FEATURES
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+void cpu_reset(CPUSPARCState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ tlb_flush(env, 1);
+ env->cwp = 0;
+#ifndef TARGET_SPARC64
+ env->wim = 1;
+#endif
+ env->regwptr = env->regbase + (env->cwp * 16);
+ CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+ env->cleanwin = env->nwindows - 2;
+ env->cansave = env->nwindows - 2;
+ env->pstate = PS_RMO | PS_PEF | PS_IE;
+ env->asi = 0x82; /* Primary no-fault */
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+ env->psret = 0;
+ env->psrs = 1;
+ env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+ env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+ env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+ env->tl = env->maxtl;
+ cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+ env->lsu = 0;
+#else
+ env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+ env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+ env->pc = 0;
+ env->npc = env->pc + 4;
+#endif
+ env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+ sparc_def_t def1, *def = &def1;
+
+ if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+ return -1;
+ }
+
+ env->def = g_new0(sparc_def_t, 1);
+ memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+ if ((env->def->features & CPU_FEATURE_FLOAT)) {
+ env->def->features |= CPU_FEATURE_FLOAT128;
+ }
+#endif
+ env->cpu_model_str = cpu_model;
+ env->version = def->iu_version;
+ env->fsr = def->fpu_version;
+ env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+ env->mmuregs[0] |= def->mmu_version;
+ cpu_sparc_set_id(env, 0);
+ env->mxccregs[7] |= def->mxcc_version;
+#else
+ env->mmu_version = def->mmu_version;
+ env->maxtl = def->maxtl;
+ env->version |= def->maxtl << 8;
+ env->version |= def->nwindows - 1;
+#endif
+ return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+ g_free(env->def);
+ g_free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+ CPUSPARCState *env;
+
+ env = g_new0(CPUSPARCState, 1);
+ cpu_exec_init(env);
+
+ gen_intermediate_code_init(env);
+
+ if (cpu_sparc_register(env, cpu_model) < 0) {
+ cpu_sparc_close(env);
+ return NULL;
+ }
+ qemu_init_vcpu(env);
+
+ return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+ env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+ {
+ .name = "Fujitsu Sparc64",
+ .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 4,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 III",
+ .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 5,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 IV",
+ .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 V",
+ .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc I",
+ .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc II",
+ .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIi",
+ .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIe",
+ .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III",
+ .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III Cu",
+ .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IIIi",
+ .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV",
+ .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_4,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV+",
+ .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+ },
+ {
+ .name = "Sun UltraSparc IIIi+",
+ .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc T1",
+ /* defined in sparc_ifu_fdp.v and ctu.h */
+ .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "Sun UltraSparc T2",
+ /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
+ .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "NEC UltraSparc I",
+ .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+#else
+ {
+ .name = "Fujitsu MB86900",
+ .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Fujitsu MB86904",
+ .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu MB86907",
+ .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LSI L64811",
+ .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+ .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C601",
+ .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C611",
+ .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "TI MicroSparc I",
+ .iu_version = 0x41000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x41000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x0000003f,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+ CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FMUL,
+ },
+ {
+ .name = "TI MicroSparc II",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x02000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI MicroSparc IIep",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x04000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016bff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 40", /* STP1020NPGA */
+ .iu_version = 0x41000000, /* SuperSPARC 2.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 50", /* STP1020PGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 51",
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 60", /* STP1020APGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 61",
+ .iu_version = 0x44000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc II",
+ .iu_version = 0x40000000, /* SuperSPARC II 1.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT625",
+ .iu_version = 0x1e000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1e000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT620",
+ .iu_version = 0x1f000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1f000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "BIT B5010",
+ .iu_version = 0x20000000,
+ .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+ .mmu_version = 0x20000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Matsushita MN10501",
+ .iu_version = 0x50000000,
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x50000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Weitek W8601",
+ .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LEON2",
+ .iu_version = 0xf2000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf2000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+ },
+ {
+ .name = "LEON3",
+ .iu_version = 0xf3000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf3000000,
+ .mmu_bm = 0x00000000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+ CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+ },
+#endif
+};
+
+static const char * const feature_name[] = {
+ "float",
+ "float128",
+ "swap",
+ "mul",
+ "div",
+ "flush",
+ "fsqrt",
+ "fmul",
+ "vis1",
+ "vis2",
+ "fsmuld",
+ "hypv",
+ "cmt",
+ "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t features, const char *prefix)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && (features & (1 << i))) {
+ if (prefix) {
+ (*cpu_fprintf)(f, "%s", prefix);
+ }
+ (*cpu_fprintf)(f, "%s ", feature_name[i]);
+ }
+ }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+ *features |= 1 << i;
+ return;
+ }
+ }
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+ unsigned int i;
+ const sparc_def_t *def = NULL;
+ char *s = strdup(cpu_model);
+ char *featurestr, *name = strtok(s, ",");
+ uint32_t plus_features = 0;
+ uint32_t minus_features = 0;
+ uint64_t iu_version;
+ uint32_t fpu_version, mmu_version, nwindows;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ if (strcasecmp(name, sparc_defs[i].name) == 0) {
+ def = &sparc_defs[i];
+ }
+ }
+ if (!def) {
+ goto error;
+ }
+ memcpy(cpu_def, def, sizeof(*def));
+
+ featurestr = strtok(NULL, ",");
+ while (featurestr) {
+ char *val;
+
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+ } else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+ } else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "iu_version")) {
+ char *err;
+
+ iu_version = strtoll(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+ } else if (!strcmp(featurestr, "fpu_version")) {
+ char *err;
+
+ fpu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+ } else if (!strcmp(featurestr, "mmu_version")) {
+ char *err;
+
+ mmu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+ } else if (!strcmp(featurestr, "nwindows")) {
+ char *err;
+
+ nwindows = strtol(val, &err, 0);
+ if (!*val || *err || nwindows > MAX_NWINDOWS ||
+ nwindows < MIN_NWINDOWS) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+ } else {
+ fprintf(stderr, "unrecognized feature %s\n", featurestr);
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format "
+ "(+feature|-feature|feature=xyz)\n", featurestr);
+ goto error;
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ cpu_def->features |= plus_features;
+ cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+ print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+ free(s);
+ return 0;
+
+ error:
+ free(s);
+ return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
+ " FPU %08x MMU %08x NWINS %d ",
+ sparc_defs[i].name,
+ sparc_defs[i].iu_version,
+ sparc_defs[i].fpu_version,
+ sparc_defs[i].mmu_version,
+ sparc_defs[i].nwindows);
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+ ~sparc_defs[i].features, "-");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+ sparc_defs[i].features, "+");
+ (*cpu_fprintf)(f, "\n");
+ }
+ (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+ "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t cc)
+{
+ cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
+ cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
+ cc & PSR_CARRY ? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+ int flags)
+{
+ int i, x;
+
+ cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
+ env->npc);
+ cpu_fprintf(f, "General Registers:\n");
+
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ cpu_fprintf(f, "\nCurrent Register Window:\n");
+ for (x = 0; x < 3; x++) {
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%%c%d-%d: ",
+ x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+ i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ }
+ cpu_fprintf(f, "\nFloating Point Registers:\n");
+ for (i = 0; i < TARGET_FPREGS; i++) {
+ if ((i & 3) == 0) {
+ cpu_fprintf(f, "%%f%02d:", i);
+ }
+ cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
+ if ((i & 3) == 3) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+#ifdef TARGET_SPARC64
+ cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+ (unsigned)cpu_get_ccr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+ cpu_fprintf(f, " xcc: ");
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+ cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+ env->psrpil);
+ cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+ "cleanwin: %d cwp: %d\n",
+ env->cansave, env->canrestore, env->otherwin, env->wstate,
+ env->cleanwin, env->nwindows - 1 - env->cwp);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+ TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+ cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+ cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
+ env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
+ env->wim);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+ env->fsr, env->y);
+#endif
+}
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
new file mode 100644
index 0000000000..23502f3020
--- /dev/null
+++ b/target-sparc/fop_helper.c
@@ -0,0 +1,394 @@
+/*
+ * FPU op helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
+
+#define F_BINOP(name) \
+ float32 helper_f ## name ## s (CPUState * env, float32 src1,\
+ float32 src2) \
+ { \
+ return float32_ ## name (src1, src2, &env->fp_status); \
+ } \
+ F_HELPER(name, d) \
+ { \
+ DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
+ } \
+ F_HELPER(name, q) \
+ { \
+ QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
+ }
+
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
+
+void helper_fsmuld(CPUState *env, float32 src1, float32 src2)
+{
+ DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
+ float32_to_float64(src2, &env->fp_status),
+ &env->fp_status);
+}
+
+void helper_fdmulq(CPUState *env)
+{
+ QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
+ float64_to_float128(DT1, &env->fp_status),
+ &env->fp_status);
+}
+
+float32 helper_fnegs(float32 src)
+{
+ return float32_chs(src);
+}
+
+#ifdef TARGET_SPARC64
+F_HELPER(neg, d)
+{
+ DT0 = float64_chs(DT1);
+}
+
+F_HELPER(neg, q)
+{
+ QT0 = float128_chs(QT1);
+}
+#endif
+
+/* Integer to float conversion. */
+float32 helper_fitos(CPUState *env, int32_t src)
+{
+ return int32_to_float32(src, &env->fp_status);
+}
+
+void helper_fitod(CPUState *env, int32_t src)
+{
+ DT0 = int32_to_float64(src, &env->fp_status);
+}
+
+void helper_fitoq(CPUState *env, int32_t src)
+{
+ QT0 = int32_to_float128(src, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+float32 helper_fxtos(CPUState *env)
+{
+ return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, d)
+{
+ DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, q)
+{
+ QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+}
+#endif
+#undef F_HELPER
+
+/* floating point conversion */
+float32 helper_fdtos(CPUState *env)
+{
+ return float64_to_float32(DT1, &env->fp_status);
+}
+
+void helper_fstod(CPUState *env, float32 src)
+{
+ DT0 = float32_to_float64(src, &env->fp_status);
+}
+
+float32 helper_fqtos(CPUState *env)
+{
+ return float128_to_float32(QT1, &env->fp_status);
+}
+
+void helper_fstoq(CPUState *env, float32 src)
+{
+ QT0 = float32_to_float128(src, &env->fp_status);
+}
+
+void helper_fqtod(CPUState *env)
+{
+ DT0 = float128_to_float64(QT1, &env->fp_status);
+}
+
+void helper_fdtoq(CPUState *env)
+{
+ QT0 = float64_to_float128(DT1, &env->fp_status);
+}
+
+/* Float to integer conversion. */
+int32_t helper_fstoi(CPUState *env, float32 src)
+{
+ return float32_to_int32_round_to_zero(src, &env->fp_status);
+}
+
+int32_t helper_fdtoi(CPUState *env)
+{
+ return float64_to_int32_round_to_zero(DT1, &env->fp_status);
+}
+
+int32_t helper_fqtoi(CPUState *env)
+{
+ return float128_to_int32_round_to_zero(QT1, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fstox(CPUState *env, float32 src)
+{
+ *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
+}
+
+void helper_fdtox(CPUState *env)
+{
+ *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+}
+
+void helper_fqtox(CPUState *env)
+{
+ *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+}
+#endif
+
+float32 helper_fabss(float32 src)
+{
+ return float32_abs(src);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fabsd(CPUState *env)
+{
+ DT0 = float64_abs(DT1);
+}
+
+void helper_fabsq(CPUState *env)
+{
+ QT0 = float128_abs(QT1);
+}
+#endif
+
+float32 helper_fsqrts(CPUState *env, float32 src)
+{
+ return float32_sqrt(src, &env->fp_status);
+}
+
+void helper_fsqrtd(CPUState *env)
+{
+ DT0 = float64_sqrt(DT1, &env->fp_status);
+}
+
+void helper_fsqrtq(CPUState *env)
+{
+ QT0 = float128_sqrt(QT1, &env->fp_status);
+}
+
+#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
+ void glue(helper_, name) (CPUState *env) \
+ { \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(reg1) || \
+ glue(size, _is_any_nan)(reg2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } \
+ switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
+ case float_relation_unordered: \
+ if ((env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
+ env->fsr |= FSR_NVA; \
+ } \
+ break; \
+ case float_relation_less: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
+ break; \
+ case float_relation_greater: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
+ break; \
+ default: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ break; \
+ } \
+ }
+#define GEN_FCMPS(name, size, FS, E) \
+ void glue(helper_, name)(CPUState *env, float32 src1, float32 src2) \
+ { \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(src1) || \
+ glue(size, _is_any_nan)(src2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } \
+ switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
+ case float_relation_unordered: \
+ if ((env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
+ env->fsr |= FSR_NVA; \
+ } \
+ break; \
+ case float_relation_less: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
+ break; \
+ case float_relation_greater: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
+ break; \
+ default: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ break; \
+ } \
+ }
+
+GEN_FCMPS(fcmps, float32, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMPS(fcmpes, float32, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+
+#ifdef TARGET_SPARC64
+GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+
+GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+
+GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+
+GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+
+GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+
+GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
+#undef GEN_FCMPS
+
+void helper_check_ieee_exceptions(CPUState *env)
+{
+ target_ulong status;
+
+ status = get_float_exception_flags(&env->fp_status);
+ if (status) {
+ /* Copy IEEE 754 flags into FSR */
+ if (status & float_flag_invalid) {
+ env->fsr |= FSR_NVC;
+ }
+ if (status & float_flag_overflow) {
+ env->fsr |= FSR_OFC;
+ }
+ if (status & float_flag_underflow) {
+ env->fsr |= FSR_UFC;
+ }
+ if (status & float_flag_divbyzero) {
+ env->fsr |= FSR_DZC;
+ }
+ if (status & float_flag_inexact) {
+ env->fsr |= FSR_NXC;
+ }
+
+ if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+ /* Unmasked exception, generate a trap */
+ env->fsr |= FSR_FTT_IEEE_EXCP;
+ helper_raise_exception(env, TT_FP_EXCP);
+ } else {
+ /* Accumulate exceptions */
+ env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+ }
+ }
+}
+
+void helper_clear_float_exceptions(CPUState *env)
+{
+ set_float_exception_flags(0, &env->fp_status);
+}
+
+static inline void set_fsr(CPUState *env)
+{
+ int rnd_mode;
+
+ switch (env->fsr & FSR_RD_MASK) {
+ case FSR_RD_NEAREST:
+ rnd_mode = float_round_nearest_even;
+ break;
+ default:
+ case FSR_RD_ZERO:
+ rnd_mode = float_round_to_zero;
+ break;
+ case FSR_RD_POS:
+ rnd_mode = float_round_up;
+ break;
+ case FSR_RD_NEG:
+ rnd_mode = float_round_down;
+ break;
+ }
+ set_float_rounding_mode(rnd_mode, &env->fp_status);
+}
+
+void helper_ldfsr(CPUState *env, uint32_t new_fsr)
+{
+ env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
+ set_fsr(env);
+}
+
+#ifdef TARGET_SPARC64
+void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
+{
+ env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
+ set_fsr(env);
+}
+#endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index c80531a16c..7a25605fa7 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -16,17 +16,13 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
#include "cpu.h"
-#include "qemu-common.h"
+#include "host-utils.h"
+#include "helper.h"
+#include "sysemu.h"
//#define DEBUG_MMU
-//#define DEBUG_FEATURES
#ifdef DEBUG_MMU
#define DPRINTF_MMU(fmt, ...) \
@@ -35,8 +31,6 @@
#define DPRINTF_MMU(fmt, ...) do {} while (0)
#endif
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
-
/* Sparc MMU emulation */
#if defined(CONFIG_USER_ONLY)
@@ -358,8 +352,6 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
}
}
-#if !defined(CONFIG_USER_ONLY)
-
/* Gdb expects all registers windows to be flushed in ram. This function handles
* reads (and only reads) in stack frames as if windows were flushed. We assume
* that the sparc ABI is followed.
@@ -440,8 +432,6 @@ int target_memory_rw_debug(CPUState *env, target_ulong addr,
return cpu_memory_rw_debug(env, addr, buf, len, is_write);
}
-#endif /* !defined(CONFIG_USER_ONLY) */
-
#else /* !TARGET_SPARC64 */
// 41 bit physical address space
@@ -839,10 +829,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
}
#endif /* TARGET_SPARC64 */
-#endif /* !CONFIG_USER_ONLY */
-
-#if !defined(CONFIG_USER_ONLY)
static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
target_ulong addr, int rw, int mmu_idx)
{
@@ -883,1059 +870,52 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
}
#endif
-#ifdef TARGET_SPARC64
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
- [TT_TFAULT] = "Instruction Access Fault",
- [TT_TMISS] = "Instruction Access MMU Miss",
- [TT_CODE_ACCESS] = "Instruction Access Error",
- [TT_ILL_INSN] = "Illegal Instruction",
- [TT_PRIV_INSN] = "Privileged Instruction",
- [TT_NFPU_INSN] = "FPU Disabled",
- [TT_FP_EXCP] = "FPU Exception",
- [TT_TOVF] = "Tag Overflow",
- [TT_CLRWIN] = "Clean Windows",
- [TT_DIV_ZERO] = "Division By Zero",
- [TT_DFAULT] = "Data Access Fault",
- [TT_DMISS] = "Data Access MMU Miss",
- [TT_DATA_ACCESS] = "Data Access Error",
- [TT_DPROT] = "Data Protection Error",
- [TT_UNALIGNED] = "Unaligned Memory Access",
- [TT_PRIV_ACT] = "Privileged Action",
- [TT_EXTINT | 0x1] = "External Interrupt 1",
- [TT_EXTINT | 0x2] = "External Interrupt 2",
- [TT_EXTINT | 0x3] = "External Interrupt 3",
- [TT_EXTINT | 0x4] = "External Interrupt 4",
- [TT_EXTINT | 0x5] = "External Interrupt 5",
- [TT_EXTINT | 0x6] = "External Interrupt 6",
- [TT_EXTINT | 0x7] = "External Interrupt 7",
- [TT_EXTINT | 0x8] = "External Interrupt 8",
- [TT_EXTINT | 0x9] = "External Interrupt 9",
- [TT_EXTINT | 0xa] = "External Interrupt 10",
- [TT_EXTINT | 0xb] = "External Interrupt 11",
- [TT_EXTINT | 0xc] = "External Interrupt 12",
- [TT_EXTINT | 0xd] = "External Interrupt 13",
- [TT_EXTINT | 0xe] = "External Interrupt 14",
- [TT_EXTINT | 0xf] = "External Interrupt 15",
-};
-#endif
-
-void do_interrupt(CPUState *env)
-{
- int intno = env->exception_index;
- trap_state *tsptr;
-
-#ifdef DEBUG_PCALL
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- static int count;
- const char *name;
-
- if (intno < 0 || intno >= 0x180) {
- name = "Unknown";
- } else if (intno >= 0x100) {
- name = "Trap Instruction";
- } else if (intno >= 0xc0) {
- name = "Window Fill";
- } else if (intno >= 0x80) {
- name = "Window Spill";
- } else {
- name = excp_names[intno];
- if (!name) {
- name = "Unknown";
- }
- }
-
- qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
- " SP=%016" PRIx64 "\n",
- count, name, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- log_cpu_state(env, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- qemu_log(" code=");
- ptr = (uint8_t *)env->pc;
- for (i = 0; i < 16; i++) {
- qemu_log(" %02x", ldub(ptr + i));
- }
- qemu_log("\n");
- }
-#endif
- count++;
- }
-#endif
-#if !defined(CONFIG_USER_ONLY)
- if (env->tl >= env->maxtl) {
- cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
- " Error state", env->exception_index, env->tl, env->maxtl);
- return;
- }
-#endif
- if (env->tl < env->maxtl - 1) {
- env->tl++;
- } else {
- env->pstate |= PS_RED;
- if (env->tl < env->maxtl) {
- env->tl++;
- }
- }
- tsptr = cpu_tsptr(env);
-
- tsptr->tstate = (cpu_get_ccr(env) << 32) |
- ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
- cpu_get_cwp64(env);
- tsptr->tpc = env->pc;
- tsptr->tnpc = env->npc;
- tsptr->tt = intno;
-
- switch (intno) {
- case TT_IVEC:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- case TT_TMISS ... TT_TMISS + 3:
- case TT_DMISS ... TT_DMISS + 3:
- case TT_DPROT ... TT_DPROT + 3:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
- break;
- default:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
- break;
- }
-
- if (intno == TT_CLRWIN) {
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
- } else if ((intno & 0x1c0) == TT_SPILL) {
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
- } else if ((intno & 0x1c0) == TT_FILL) {
- cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
- }
- env->tbr &= ~0x7fffULL;
- env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = -1;
-}
-#else
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
- [TT_TFAULT] = "Instruction Access Fault",
- [TT_ILL_INSN] = "Illegal Instruction",
- [TT_PRIV_INSN] = "Privileged Instruction",
- [TT_NFPU_INSN] = "FPU Disabled",
- [TT_WIN_OVF] = "Window Overflow",
- [TT_WIN_UNF] = "Window Underflow",
- [TT_UNALIGNED] = "Unaligned Memory Access",
- [TT_FP_EXCP] = "FPU Exception",
- [TT_DFAULT] = "Data Access Fault",
- [TT_TOVF] = "Tag Overflow",
- [TT_EXTINT | 0x1] = "External Interrupt 1",
- [TT_EXTINT | 0x2] = "External Interrupt 2",
- [TT_EXTINT | 0x3] = "External Interrupt 3",
- [TT_EXTINT | 0x4] = "External Interrupt 4",
- [TT_EXTINT | 0x5] = "External Interrupt 5",
- [TT_EXTINT | 0x6] = "External Interrupt 6",
- [TT_EXTINT | 0x7] = "External Interrupt 7",
- [TT_EXTINT | 0x8] = "External Interrupt 8",
- [TT_EXTINT | 0x9] = "External Interrupt 9",
- [TT_EXTINT | 0xa] = "External Interrupt 10",
- [TT_EXTINT | 0xb] = "External Interrupt 11",
- [TT_EXTINT | 0xc] = "External Interrupt 12",
- [TT_EXTINT | 0xd] = "External Interrupt 13",
- [TT_EXTINT | 0xe] = "External Interrupt 14",
- [TT_EXTINT | 0xf] = "External Interrupt 15",
- [TT_TOVF] = "Tag Overflow",
- [TT_CODE_ACCESS] = "Instruction Access Error",
- [TT_DATA_ACCESS] = "Data Access Error",
- [TT_DIV_ZERO] = "Division By Zero",
- [TT_NCP_INSN] = "Coprocessor Disabled",
-};
-#endif
-
-void do_interrupt(CPUState *env)
-{
- int cwp, intno = env->exception_index;
-
-#ifdef DEBUG_PCALL
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- static int count;
- const char *name;
-
- if (intno < 0 || intno >= 0x100) {
- name = "Unknown";
- } else if (intno >= 0x80) {
- name = "Trap Instruction";
- } else {
- name = excp_names[intno];
- if (!name) {
- name = "Unknown";
- }
- }
-
- qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
- count, name, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- log_cpu_state(env, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- qemu_log(" code=");
- ptr = (uint8_t *)env->pc;
- for (i = 0; i < 16; i++) {
- qemu_log(" %02x", ldub(ptr + i));
- }
- qemu_log("\n");
- }
-#endif
- count++;
- }
-#endif
-#if !defined(CONFIG_USER_ONLY)
- if (env->psret == 0) {
- cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
- env->exception_index);
- return;
- }
-#endif
- env->psret = 0;
- cwp = cpu_cwp_dec(env, env->cwp - 1);
- cpu_set_cwp(env, cwp);
- env->regwptr[9] = env->pc;
- env->regwptr[10] = env->npc;
- env->psrps = env->psrs;
- env->psrs = 1;
- env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = -1;
-
-#if !defined(CONFIG_USER_ONLY)
- /* IRQ acknowledgment */
- if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
- env->qemu_irq_ack(env->irq_manager, intno);
- }
-#endif
-}
-#endif
-
-void cpu_reset(CPUSPARCState *env)
-{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- tlb_flush(env, 1);
- env->cwp = 0;
-#ifndef TARGET_SPARC64
- env->wim = 1;
-#endif
- env->regwptr = env->regbase + (env->cwp * 16);
- CC_OP = CC_OP_FLAGS;
-#if defined(CONFIG_USER_ONLY)
-#ifdef TARGET_SPARC64
- env->cleanwin = env->nwindows - 2;
- env->cansave = env->nwindows - 2;
- env->pstate = PS_RMO | PS_PEF | PS_IE;
- env->asi = 0x82; // Primary no-fault
-#endif
-#else
-#if !defined(TARGET_SPARC64)
- env->psret = 0;
- env->psrs = 1;
- env->psrps = 1;
-#endif
-#ifdef TARGET_SPARC64
- env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
- env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
- env->tl = env->maxtl;
- cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
- env->lsu = 0;
-#else
- env->mmuregs[0] &= ~(MMU_E | MMU_NF);
- env->mmuregs[0] |= env->def->mmu_bm;
-#endif
- env->pc = 0;
- env->npc = env->pc + 4;
-#endif
- env->cache_control = 0;
-}
-
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
-{
- sparc_def_t def1, *def = &def1;
-
- if (cpu_sparc_find_by_name(def, cpu_model) < 0)
- return -1;
-
- env->def = g_malloc0(sizeof(*def));
- memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
- if ((env->def->features & CPU_FEATURE_FLOAT))
- env->def->features |= CPU_FEATURE_FLOAT128;
-#endif
- env->cpu_model_str = cpu_model;
- env->version = def->iu_version;
- env->fsr = def->fpu_version;
- env->nwindows = def->nwindows;
-#if !defined(TARGET_SPARC64)
- env->mmuregs[0] |= def->mmu_version;
- cpu_sparc_set_id(env, 0);
- env->mxccregs[7] |= def->mxcc_version;
-#else
- env->mmu_version = def->mmu_version;
- env->maxtl = def->maxtl;
- env->version |= def->maxtl << 8;
- env->version |= def->nwindows - 1;
-#endif
- return 0;
-}
-
-static void cpu_sparc_close(CPUSPARCState *env)
+/* misc op helpers */
+void helper_raise_exception(CPUState *env, int tt)
{
- free(env->def);
- free(env);
+ env->exception_index = tt;
+ cpu_loop_exit(env);
}
-CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+void helper_debug(CPUState *env)
{
- CPUSPARCState *env;
-
- env = g_malloc0(sizeof(CPUSPARCState));
- cpu_exec_init(env);
-
- gen_intermediate_code_init(env);
-
- if (cpu_sparc_register(env, cpu_model) < 0) {
- cpu_sparc_close(env);
- return NULL;
- }
- qemu_init_vcpu(env);
-
- return env;
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(env);
}
-void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+void helper_shutdown(void)
{
-#if !defined(TARGET_SPARC64)
- env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#if !defined(CONFIG_USER_ONLY)
+ qemu_system_shutdown_request();
#endif
}
-static const sparc_def_t sparc_defs[] = {
#ifdef TARGET_SPARC64
- {
- .name = "Fujitsu Sparc64",
- .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 4,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 III",
- .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 5,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 IV",
- .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 V",
- .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc I",
- .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc II",
- .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIi",
- .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIe",
- .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III",
- .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III Cu",
- .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IIIi",
- .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV",
- .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_4,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV+",
- .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
- },
- {
- .name = "Sun UltraSparc IIIi+",
- .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc T1",
- // defined in sparc_ifu_fdp.v and ctu.h
- .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "Sun UltraSparc T2",
- // defined in tlu_asi_ctl.v and n2_revid_cust.v
- .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "NEC UltraSparc I",
- .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
-#else
- {
- .name = "Fujitsu MB86900",
- .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
- },
- {
- .name = "Fujitsu MB86904",
- .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu MB86907",
- .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LSI L64811",
- .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
- .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C601",
- .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C611",
- .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "TI MicroSparc I",
- .iu_version = 0x41000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x41000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x0000003f,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
- CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FMUL,
- },
- {
- .name = "TI MicroSparc II",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x02000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI MicroSparc IIep",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x04000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016bff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 40", // STP1020NPGA
- .iu_version = 0x41000000, // SuperSPARC 2.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 50", // STP1020PGA
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 51",
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 60", // STP1020APGA
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 61",
- .iu_version = 0x44000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc II",
- .iu_version = 0x40000000, // SuperSPARC II 1.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT625",
- .iu_version = 0x1e000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1e000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT620",
- .iu_version = 0x1f000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1f000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "BIT B5010",
- .iu_version = 0x20000000,
- .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
- .mmu_version = 0x20000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Matsushita MN10501",
- .iu_version = 0x50000000,
- .fpu_version = 0 << 17,
- .mmu_version = 0x50000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Weitek W8601",
- .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
- .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LEON2",
- .iu_version = 0xf2000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf2000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
- },
- {
- .name = "LEON3",
- .iu_version = 0xf3000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf3000000,
- .mmu_bm = 0x00000000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
- CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
- },
-#endif
-};
-
-static const char * const feature_name[] = {
- "float",
- "float128",
- "swap",
- "mul",
- "div",
- "flush",
- "fsqrt",
- "fmul",
- "vis1",
- "vis2",
- "fsmuld",
- "hypv",
- "cmt",
- "gl",
-};
-
-static void print_features(FILE *f, fprintf_function cpu_fprintf,
- uint32_t features, const char *prefix)
+target_ulong helper_popc(target_ulong val)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++)
- if (feature_name[i] && (features & (1 << i))) {
- if (prefix)
- (*cpu_fprintf)(f, "%s", prefix);
- (*cpu_fprintf)(f, "%s ", feature_name[i]);
- }
+ return ctpop64(val);
}
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+void helper_tick_set_count(void *opaque, uint64_t count)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++)
- if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
- *features |= 1 << i;
- return;
- }
- fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
-{
- unsigned int i;
- const sparc_def_t *def = NULL;
- char *s = strdup(cpu_model);
- char *featurestr, *name = strtok(s, ",");
- uint32_t plus_features = 0;
- uint32_t minus_features = 0;
- uint64_t iu_version;
- uint32_t fpu_version, mmu_version, nwindows;
-
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- if (strcasecmp(name, sparc_defs[i].name) == 0) {
- def = &sparc_defs[i];
- }
- }
- if (!def)
- goto error;
- memcpy(cpu_def, def, sizeof(*def));
-
- featurestr = strtok(NULL, ",");
- while (featurestr) {
- char *val;
-
- if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features);
- } else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- if (!strcmp(featurestr, "iu_version")) {
- char *err;
-
- iu_version = strtoll(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->iu_version = iu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
-#endif
- } else if (!strcmp(featurestr, "fpu_version")) {
- char *err;
-
- fpu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->fpu_version = fpu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "fpu_version %x\n", fpu_version);
-#endif
- } else if (!strcmp(featurestr, "mmu_version")) {
- char *err;
-
- mmu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->mmu_version = mmu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "mmu_version %x\n", mmu_version);
-#endif
- } else if (!strcmp(featurestr, "nwindows")) {
- char *err;
-
- nwindows = strtol(val, &err, 0);
- if (!*val || *err || nwindows > MAX_NWINDOWS ||
- nwindows < MIN_NWINDOWS) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->nwindows = nwindows;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "nwindows %d\n", nwindows);
-#endif
- } else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
- }
- } else {
- fprintf(stderr, "feature string `%s' not in format "
- "(+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
- }
- featurestr = strtok(NULL, ",");
- }
- cpu_def->features |= plus_features;
- cpu_def->features &= ~minus_features;
-#ifdef DEBUG_FEATURES
- print_features(stderr, fprintf, cpu_def->features, NULL);
+#if !defined(CONFIG_USER_ONLY)
+ cpu_tick_set_count(opaque, count);
#endif
- free(s);
- return 0;
-
- error:
- free(s);
- return -1;
-}
-
-void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
- sparc_defs[i].name,
- sparc_defs[i].iu_version,
- sparc_defs[i].fpu_version,
- sparc_defs[i].mmu_version,
- sparc_defs[i].nwindows);
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
- ~sparc_defs[i].features, "-");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
- sparc_defs[i].features, "+");
- (*cpu_fprintf)(f, "\n");
- }
- (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
- "fpu_version mmu_version nwindows\n");
}
-static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
- uint32_t cc)
+uint64_t helper_tick_get_count(void *opaque)
{
- cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
- cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
- cc & PSR_CARRY? 'C' : '-');
-}
-
-#ifdef TARGET_SPARC64
-#define REGS_PER_LINE 4
+#if !defined(CONFIG_USER_ONLY)
+ return cpu_tick_get_count(opaque);
#else
-#define REGS_PER_LINE 8
+ return 0;
#endif
+}
-void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
- int flags)
+void helper_tick_set_limit(void *opaque, uint64_t limit)
{
- int i, x;
-
- cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
- env->npc);
- cpu_fprintf(f, "General Registers:\n");
-
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- cpu_fprintf(f, "\nCurrent Register Window:\n");
- for (x = 0; x < 3; x++) {
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%%c%d-%d: ",
- x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
- i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- }
- cpu_fprintf(f, "\nFloating Point Registers:\n");
- for (i = 0; i < TARGET_FPREGS; i++) {
- if ((i & 3) == 0)
- cpu_fprintf(f, "%%f%02d:", i);
- cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
- if ((i & 3) == 3)
- cpu_fprintf(f, "\n");
- }
-#ifdef TARGET_SPARC64
- cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
- (unsigned)cpu_get_ccr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
- cpu_fprintf(f, " xcc: ");
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
- cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
- env->psrpil);
- cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
- "cleanwin: %d cwp: %d\n",
- env->cansave, env->canrestore, env->otherwin, env->wstate,
- env->cleanwin, env->nwindows - 1 - env->cwp);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
- TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
-#else
- cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
- cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
- env->psrps? 'P' : '-', env->psret? 'E' : '-',
- env->wim);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
- env->fsr, env->y);
+#if !defined(CONFIG_USER_ONLY)
+ cpu_tick_set_limit(opaque, limit);
#endif
}
+#endif
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 2d36af3a31..57d0073f2b 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -16,8 +16,8 @@ DEF_HELPER_0(rdccr, tl)
DEF_HELPER_1(wrccr, void, tl)
DEF_HELPER_0(rdcwp, tl)
DEF_HELPER_1(wrcwp, void, tl)
-DEF_HELPER_2(array8, tl, tl, tl)
-DEF_HELPER_2(alignaddr, tl, tl, tl)
+DEF_HELPER_3(array8, tl, env, tl, tl)
+DEF_HELPER_3(alignaddr, tl, env, tl, tl)
DEF_HELPER_1(popc, tl, tl)
DEF_HELPER_3(ldda_asi, void, tl, int, int)
DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
@@ -32,7 +32,7 @@ DEF_HELPER_1(tick_get_count, i64, ptr)
DEF_HELPER_2(tick_set_limit, void, ptr, i64)
#endif
DEF_HELPER_2(check_align, void, tl, i32)
-DEF_HELPER_0(debug, void)
+DEF_HELPER_1(debug, void, env)
DEF_HELPER_0(save, void)
DEF_HELPER_0(restore, void)
DEF_HELPER_2(udiv, tl, tl, tl)
@@ -47,119 +47,119 @@ DEF_HELPER_2(stqf, void, tl, int)
DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
DEF_HELPER_4(st_asi, void, tl, i64, int, int)
#endif
-DEF_HELPER_1(ldfsr, void, i32)
-DEF_HELPER_0(check_ieee_exceptions, void)
-DEF_HELPER_0(clear_float_exceptions, void)
+DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_1(check_ieee_exceptions, void, env)
+DEF_HELPER_1(clear_float_exceptions, void, env)
DEF_HELPER_1(fabss, f32, f32)
-DEF_HELPER_1(fsqrts, f32, f32)
-DEF_HELPER_0(fsqrtd, void)
-DEF_HELPER_2(fcmps, void, f32, f32)
-DEF_HELPER_0(fcmpd, void)
-DEF_HELPER_2(fcmpes, void, f32, f32)
-DEF_HELPER_0(fcmped, void)
-DEF_HELPER_0(fsqrtq, void)
-DEF_HELPER_0(fcmpq, void)
-DEF_HELPER_0(fcmpeq, void)
+DEF_HELPER_2(fsqrts, f32, env, f32)
+DEF_HELPER_1(fsqrtd, void, env)
+DEF_HELPER_3(fcmps, void, env, f32, f32)
+DEF_HELPER_1(fcmpd, void, env)
+DEF_HELPER_3(fcmpes, void, env, f32, f32)
+DEF_HELPER_1(fcmped, void, env)
+DEF_HELPER_1(fsqrtq, void, env)
+DEF_HELPER_1(fcmpq, void, env)
+DEF_HELPER_1(fcmpeq, void, env)
#ifdef TARGET_SPARC64
-DEF_HELPER_1(ldxfsr, void, i64)
-DEF_HELPER_0(fabsd, void)
-DEF_HELPER_2(fcmps_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmpd_fcc1, void)
-DEF_HELPER_0(fcmpd_fcc2, void)
-DEF_HELPER_0(fcmpd_fcc3, void)
-DEF_HELPER_2(fcmpes_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmped_fcc1, void)
-DEF_HELPER_0(fcmped_fcc2, void)
-DEF_HELPER_0(fcmped_fcc3, void)
-DEF_HELPER_0(fabsq, void)
-DEF_HELPER_0(fcmpq_fcc1, void)
-DEF_HELPER_0(fcmpq_fcc2, void)
-DEF_HELPER_0(fcmpq_fcc3, void)
-DEF_HELPER_0(fcmpeq_fcc1, void)
-DEF_HELPER_0(fcmpeq_fcc2, void)
-DEF_HELPER_0(fcmpeq_fcc3, void)
+DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_1(fabsd, void, env)
+DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmpd_fcc1, void, env)
+DEF_HELPER_1(fcmpd_fcc2, void, env)
+DEF_HELPER_1(fcmpd_fcc3, void, env)
+DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmped_fcc1, void, env)
+DEF_HELPER_1(fcmped_fcc2, void, env)
+DEF_HELPER_1(fcmped_fcc3, void, env)
+DEF_HELPER_1(fabsq, void, env)
+DEF_HELPER_1(fcmpq_fcc1, void, env)
+DEF_HELPER_1(fcmpq_fcc2, void, env)
+DEF_HELPER_1(fcmpq_fcc3, void, env)
+DEF_HELPER_1(fcmpeq_fcc1, void, env)
+DEF_HELPER_1(fcmpeq_fcc2, void, env)
+DEF_HELPER_1(fcmpeq_fcc3, void, env)
#endif
-DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_2(raise_exception, void, env, int)
DEF_HELPER_0(shutdown, void)
-#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
-#define F_HELPER_DQ_0_0(name) \
- F_HELPER_0_0(name ## d); \
- F_HELPER_0_0(name ## q)
+#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
+#define F_HELPER_DQ_0_1(name) \
+ F_HELPER_0_1(name ## d); \
+ F_HELPER_0_1(name ## q)
-F_HELPER_DQ_0_0(add);
-F_HELPER_DQ_0_0(sub);
-F_HELPER_DQ_0_0(mul);
-F_HELPER_DQ_0_0(div);
+F_HELPER_DQ_0_1(add);
+F_HELPER_DQ_0_1(sub);
+F_HELPER_DQ_0_1(mul);
+F_HELPER_DQ_0_1(div);
-DEF_HELPER_2(fadds, f32, f32, f32)
-DEF_HELPER_2(fsubs, f32, f32, f32)
-DEF_HELPER_2(fmuls, f32, f32, f32)
-DEF_HELPER_2(fdivs, f32, f32, f32)
+DEF_HELPER_3(fadds, f32, env, f32, f32)
+DEF_HELPER_3(fsubs, f32, env, f32, f32)
+DEF_HELPER_3(fmuls, f32, env, f32, f32)
+DEF_HELPER_3(fdivs, f32, env, f32, f32)
-DEF_HELPER_2(fsmuld, void, f32, f32)
-F_HELPER_0_0(dmulq);
+DEF_HELPER_3(fsmuld, void, env, f32, f32)
+F_HELPER_0_1(dmulq);
DEF_HELPER_1(fnegs, f32, f32)
-DEF_HELPER_1(fitod, void, s32)
-DEF_HELPER_1(fitoq, void, s32)
+DEF_HELPER_2(fitod, void, env, s32)
+DEF_HELPER_2(fitoq, void, env, s32)
-DEF_HELPER_1(fitos, f32, s32)
+DEF_HELPER_2(fitos, f32, env, s32)
#ifdef TARGET_SPARC64
-DEF_HELPER_0(fnegd, void)
-DEF_HELPER_0(fnegq, void)
-DEF_HELPER_0(fxtos, i32)
-F_HELPER_DQ_0_0(xto);
+DEF_HELPER_1(fnegd, void, env)
+DEF_HELPER_1(fnegq, void, env)
+DEF_HELPER_1(fxtos, i32, env)
+F_HELPER_DQ_0_1(xto);
#endif
-DEF_HELPER_0(fdtos, f32)
-DEF_HELPER_1(fstod, void, f32)
-DEF_HELPER_0(fqtos, f32)
-DEF_HELPER_1(fstoq, void, f32)
-F_HELPER_0_0(qtod);
-F_HELPER_0_0(dtoq);
-DEF_HELPER_1(fstoi, s32, f32)
-DEF_HELPER_0(fdtoi, s32)
-DEF_HELPER_0(fqtoi, s32)
+DEF_HELPER_1(fdtos, f32, env)
+DEF_HELPER_2(fstod, void, env, f32)
+DEF_HELPER_1(fqtos, f32, env)
+DEF_HELPER_2(fstoq, void, env, f32)
+F_HELPER_0_1(qtod);
+F_HELPER_0_1(dtoq);
+DEF_HELPER_2(fstoi, s32, env, f32)
+DEF_HELPER_1(fdtoi, s32, env)
+DEF_HELPER_1(fqtoi, s32, env)
#ifdef TARGET_SPARC64
-DEF_HELPER_1(fstox, void, i32)
-F_HELPER_0_0(dtox);
-F_HELPER_0_0(qtox);
-F_HELPER_0_0(aligndata);
+DEF_HELPER_2(fstox, void, env, i32)
+F_HELPER_0_1(dtox);
+F_HELPER_0_1(qtox);
+F_HELPER_0_1(aligndata);
-F_HELPER_0_0(pmerge);
-F_HELPER_0_0(mul8x16);
-F_HELPER_0_0(mul8x16al);
-F_HELPER_0_0(mul8x16au);
-F_HELPER_0_0(mul8sux16);
-F_HELPER_0_0(mul8ulx16);
-F_HELPER_0_0(muld8sux16);
-F_HELPER_0_0(muld8ulx16);
-F_HELPER_0_0(expand);
+F_HELPER_0_1(pmerge);
+F_HELPER_0_1(mul8x16);
+F_HELPER_0_1(mul8x16al);
+F_HELPER_0_1(mul8x16au);
+F_HELPER_0_1(mul8sux16);
+F_HELPER_0_1(mul8ulx16);
+F_HELPER_0_1(muld8sux16);
+F_HELPER_0_1(muld8ulx16);
+F_HELPER_0_1(expand);
#define VIS_HELPER(name) \
- F_HELPER_0_0(name##16); \
- DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \
- F_HELPER_0_0(name##32); \
- DEF_HELPER_2(f ## name ## 32s, i32, i32, i32)
+ F_HELPER_0_1(name##16); \
+ DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32) \
+ F_HELPER_0_1(name##32); \
+ DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32)
VIS_HELPER(padd);
VIS_HELPER(psub);
#define VIS_CMPHELPER(name) \
- DEF_HELPER_0(f##name##16, i64); \
- DEF_HELPER_0(f##name##32, i64)
+ DEF_HELPER_1(f##name##16, i64, env); \
+ DEF_HELPER_1(f##name##32, i64, env)
VIS_CMPHELPER(cmpgt);
VIS_CMPHELPER(cmpeq);
VIS_CMPHELPER(cmple);
VIS_CMPHELPER(cmpne);
#endif
-#undef F_HELPER_0_0
-#undef F_HELPER_DQ_0_0
+#undef F_HELPER_0_1
+#undef F_HELPER_DQ_0_1
#undef VIS_HELPER
#undef VIS_CMPHELPER
-DEF_HELPER_0(compute_psr, void);
-DEF_HELPER_0(compute_C_icc, i32);
+DEF_HELPER_1(compute_psr, void, env);
+DEF_HELPER_1(compute_C_icc, i32, env);
#include "def-helper.h"
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
new file mode 100644
index 0000000000..219a6c64cd
--- /dev/null
+++ b/target-sparc/int32_helper.c
@@ -0,0 +1,125 @@
+/*
+ * Sparc32 interrupt helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+ [TT_TFAULT] = "Instruction Access Fault",
+ [TT_ILL_INSN] = "Illegal Instruction",
+ [TT_PRIV_INSN] = "Privileged Instruction",
+ [TT_NFPU_INSN] = "FPU Disabled",
+ [TT_WIN_OVF] = "Window Overflow",
+ [TT_WIN_UNF] = "Window Underflow",
+ [TT_UNALIGNED] = "Unaligned Memory Access",
+ [TT_FP_EXCP] = "FPU Exception",
+ [TT_DFAULT] = "Data Access Fault",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_EXTINT | 0x1] = "External Interrupt 1",
+ [TT_EXTINT | 0x2] = "External Interrupt 2",
+ [TT_EXTINT | 0x3] = "External Interrupt 3",
+ [TT_EXTINT | 0x4] = "External Interrupt 4",
+ [TT_EXTINT | 0x5] = "External Interrupt 5",
+ [TT_EXTINT | 0x6] = "External Interrupt 6",
+ [TT_EXTINT | 0x7] = "External Interrupt 7",
+ [TT_EXTINT | 0x8] = "External Interrupt 8",
+ [TT_EXTINT | 0x9] = "External Interrupt 9",
+ [TT_EXTINT | 0xa] = "External Interrupt 10",
+ [TT_EXTINT | 0xb] = "External Interrupt 11",
+ [TT_EXTINT | 0xc] = "External Interrupt 12",
+ [TT_EXTINT | 0xd] = "External Interrupt 13",
+ [TT_EXTINT | 0xe] = "External Interrupt 14",
+ [TT_EXTINT | 0xf] = "External Interrupt 15",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_CODE_ACCESS] = "Instruction Access Error",
+ [TT_DATA_ACCESS] = "Data Access Error",
+ [TT_DIV_ZERO] = "Division By Zero",
+ [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+ int cwp, intno = env->exception_index;
+
+#ifdef DEBUG_PCALL
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name;
+
+ if (intno < 0 || intno >= 0x100) {
+ name = "Unknown";
+ } else if (intno >= 0x80) {
+ name = "Trap Instruction";
+ } else {
+ name = excp_names[intno];
+ if (!name) {
+ name = "Unknown";
+ }
+ }
+
+ qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+ count, name, intno,
+ env->pc,
+ env->npc, env->regwptr[6]);
+ log_cpu_state(env, 0);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+
+ qemu_log(" code=");
+ ptr = (uint8_t *)env->pc;
+ for (i = 0; i < 16; i++) {
+ qemu_log(" %02x", ldub(ptr + i));
+ }
+ qemu_log("\n");
+ }
+#endif
+ count++;
+ }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+ if (env->psret == 0) {
+ cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
+ env->exception_index);
+ return;
+ }
+#endif
+ env->psret = 0;
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
+ cpu_set_cwp(env, cwp);
+ env->regwptr[9] = env->pc;
+ env->regwptr[10] = env->npc;
+ env->psrps = env->psrs;
+ env->psrs = 1;
+ env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
+ env->pc = env->tbr;
+ env->npc = env->pc + 4;
+ env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+ /* IRQ acknowledgment */
+ if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+ env->qemu_irq_ack(env->irq_manager, intno);
+ }
+#endif
+}
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
new file mode 100644
index 0000000000..2bb1910ed9
--- /dev/null
+++ b/target-sparc/int64_helper.c
@@ -0,0 +1,164 @@
+/*
+ * Sparc64 interrupt helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+ [TT_TFAULT] = "Instruction Access Fault",
+ [TT_TMISS] = "Instruction Access MMU Miss",
+ [TT_CODE_ACCESS] = "Instruction Access Error",
+ [TT_ILL_INSN] = "Illegal Instruction",
+ [TT_PRIV_INSN] = "Privileged Instruction",
+ [TT_NFPU_INSN] = "FPU Disabled",
+ [TT_FP_EXCP] = "FPU Exception",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_CLRWIN] = "Clean Windows",
+ [TT_DIV_ZERO] = "Division By Zero",
+ [TT_DFAULT] = "Data Access Fault",
+ [TT_DMISS] = "Data Access MMU Miss",
+ [TT_DATA_ACCESS] = "Data Access Error",
+ [TT_DPROT] = "Data Protection Error",
+ [TT_UNALIGNED] = "Unaligned Memory Access",
+ [TT_PRIV_ACT] = "Privileged Action",
+ [TT_EXTINT | 0x1] = "External Interrupt 1",
+ [TT_EXTINT | 0x2] = "External Interrupt 2",
+ [TT_EXTINT | 0x3] = "External Interrupt 3",
+ [TT_EXTINT | 0x4] = "External Interrupt 4",
+ [TT_EXTINT | 0x5] = "External Interrupt 5",
+ [TT_EXTINT | 0x6] = "External Interrupt 6",
+ [TT_EXTINT | 0x7] = "External Interrupt 7",
+ [TT_EXTINT | 0x8] = "External Interrupt 8",
+ [TT_EXTINT | 0x9] = "External Interrupt 9",
+ [TT_EXTINT | 0xa] = "External Interrupt 10",
+ [TT_EXTINT | 0xb] = "External Interrupt 11",
+ [TT_EXTINT | 0xc] = "External Interrupt 12",
+ [TT_EXTINT | 0xd] = "External Interrupt 13",
+ [TT_EXTINT | 0xe] = "External Interrupt 14",
+ [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+ int intno = env->exception_index;
+ trap_state *tsptr;
+
+#ifdef DEBUG_PCALL
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name;
+
+ if (intno < 0 || intno >= 0x180) {
+ name = "Unknown";
+ } else if (intno >= 0x100) {
+ name = "Trap Instruction";
+ } else if (intno >= 0xc0) {
+ name = "Window Fill";
+ } else if (intno >= 0x80) {
+ name = "Window Spill";
+ } else {
+ name = excp_names[intno];
+ if (!name) {
+ name = "Unknown";
+ }
+ }
+
+ qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+ " SP=%016" PRIx64 "\n",
+ count, name, intno,
+ env->pc,
+ env->npc, env->regwptr[6]);
+ log_cpu_state(env, 0);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+
+ qemu_log(" code=");
+ ptr = (uint8_t *)env->pc;
+ for (i = 0; i < 16; i++) {
+ qemu_log(" %02x", ldub(ptr + i));
+ }
+ qemu_log("\n");
+ }
+#endif
+ count++;
+ }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+ if (env->tl >= env->maxtl) {
+ cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+ " Error state", env->exception_index, env->tl, env->maxtl);
+ return;
+ }
+#endif
+ if (env->tl < env->maxtl - 1) {
+ env->tl++;
+ } else {
+ env->pstate |= PS_RED;
+ if (env->tl < env->maxtl) {
+ env->tl++;
+ }
+ }
+ tsptr = cpu_tsptr(env);
+
+ tsptr->tstate = (cpu_get_ccr(env) << 32) |
+ ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+ cpu_get_cwp64(env);
+ tsptr->tpc = env->pc;
+ tsptr->tnpc = env->npc;
+ tsptr->tt = intno;
+
+ switch (intno) {
+ case TT_IVEC:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
+ break;
+ case TT_TFAULT:
+ case TT_DFAULT:
+ case TT_TMISS ... TT_TMISS + 3:
+ case TT_DMISS ... TT_DMISS + 3:
+ case TT_DPROT ... TT_DPROT + 3:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
+ break;
+ default:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
+ break;
+ }
+
+ if (intno == TT_CLRWIN) {
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
+ } else if ((intno & 0x1c0) == TT_SPILL) {
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
+ } else if ((intno & 0x1c0) == TT_FILL) {
+ cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+ }
+ env->tbr &= ~0x7fffULL;
+ env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
+ env->pc = env->tbr;
+ env->npc = env->pc + 4;
+ env->exception_index = -1;
+}
+
+trap_state *cpu_tsptr(CPUState* env)
+{
+ return &env->ts[env->tl & MAXTL_MASK];
+}
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 1cb0636c30..cb0bf2e2a6 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,8 +1,6 @@
#include "cpu.h"
#include "dyngen-exec.h"
-#include "host-utils.h"
#include "helper.h"
-#include "sysemu.h"
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
@@ -13,7 +11,6 @@
//#define DEBUG_UNALIGNED
//#define DEBUG_UNASSIGNED
//#define DEBUG_ASI
-//#define DEBUG_PCALL
//#define DEBUG_PSTATE
//#define DEBUG_CACHE_CONTROL
@@ -37,14 +34,14 @@
#endif
#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...) \
+#define DPRINTF_PSTATE(fmt, ...) \
do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
#endif
#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...) \
+#define DPRINTF_CACHE_CONTROL(fmt, ...) \
do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
@@ -95,7 +92,7 @@ static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
#endif
#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-// Calculates TSB pointer value for fault page size 8k or 64k
+/* Calculates TSB pointer value for fault page size 8k or 64k */
static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
uint64_t tag_access_register,
int page_size)
@@ -104,14 +101,14 @@ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
int tsb_size = tsb_register & 0xf;
- // discard lower 13 bits which hold tag access context
+ /* discard lower 13 bits which hold tag access context */
uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
- // now reorder bits
+ /* now reorder bits */
uint64_t tsb_base_mask = ~0x1fffULL;
uint64_t va = tag_access_va;
- // move va bits to correct position
+ /* move va bits to correct position */
if (page_size == 8*1024) {
va >>= 9;
} else if (page_size == 64*1024) {
@@ -122,7 +119,7 @@ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
tsb_base_mask <<= tsb_size;
}
- // calculate tsb_base mask and adjust va if split is in use
+ /* calculate tsb_base mask and adjust va if split is in use */
if (tsb_split) {
if (page_size == 8*1024) {
va &= ~(1ULL << (13 + tsb_size));
@@ -135,8 +132,8 @@ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
}
-// Calculates tag target register value by reordering bits
-// in tag access register
+/* Calculates tag target register value by reordering bits
+ in tag access register */
static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
{
return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
@@ -148,7 +145,7 @@ static void replace_tlb_entry(SparcTLBEntry *tlb,
{
target_ulong mask, size, va, offset;
- // flush page range if translation is valid
+ /* flush page range if translation is valid */
if (TTE_IS_VALID(tlb->tte)) {
mask = 0xffffffffffffe000ULL;
@@ -167,7 +164,7 @@ static void replace_tlb_entry(SparcTLBEntry *tlb,
}
static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
- const char* strmmu, CPUState *env1)
+ const char *strmmu, CPUState *env1)
{
unsigned int i;
target_ulong mask;
@@ -175,18 +172,18 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
int is_demap_context = (demap_addr >> 6) & 1;
- // demap context
+ /* demap context */
switch ((demap_addr >> 4) & 3) {
- case 0: // primary
+ case 0: /* primary */
context = env1->dmmu.mmu_primary_context;
break;
- case 1: // secondary
+ case 1: /* secondary */
context = env1->dmmu.mmu_secondary_context;
break;
- case 2: // nucleus
+ case 2: /* nucleus */
context = 0;
break;
- case 3: // reserved
+ case 3: /* reserved */
default:
return;
}
@@ -195,14 +192,14 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
if (TTE_IS_VALID(tlb[i].tte)) {
if (is_demap_context) {
- // will remove non-global entries matching context value
+ /* will remove non-global entries matching context value */
if (TTE_IS_GLOBAL(tlb[i].tte) ||
!tlb_compare_context(&tlb[i], context)) {
continue;
}
} else {
- // demap page
- // will remove any entry matching VA
+ /* demap page
+ will remove any entry matching VA */
mask = 0xffffffffffffe000ULL;
mask <<= 3 * ((tlb[i].tte >> 61) & 3);
@@ -210,7 +207,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
continue;
}
- // entry should be global or matching context value
+ /* entry should be global or matching context value */
if (!TTE_IS_GLOBAL(tlb[i].tte) &&
!tlb_compare_context(&tlb[i], context)) {
continue;
@@ -228,11 +225,11 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
uint64_t tlb_tag, uint64_t tlb_tte,
- const char* strmmu, CPUState *env1)
+ const char *strmmu, CPUState *env1)
{
unsigned int i, replace_used;
- // Try replacing invalid entry
+ /* Try replacing invalid entry */
for (i = 0; i < 64; i++) {
if (!TTE_IS_VALID(tlb[i].tte)) {
replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
@@ -244,11 +241,11 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
}
}
- // All entries are valid, try replacing unlocked entry
+ /* All entries are valid, try replacing unlocked entry */
for (replace_used = 0; replace_used < 2; ++replace_used) {
- // Used entries are not replaced on first pass
+ /* Used entries are not replaced on first pass */
for (i = 0; i < 64; i++) {
if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
@@ -256,14 +253,14 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
#ifdef DEBUG_MMU
DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
- strmmu, (replace_used?"used":"unused"), i);
+ strmmu, (replace_used ? "used" : "unused"), i);
dump_mmu(stdout, fprintf, env1);
#endif
return;
}
}
- // Now reset used bit and search for unused entries again
+ /* Now reset used bit and search for unused entries again */
for (i = 0; i < 64; i++) {
TTE_SET_UNUSED(tlb[i].tte);
@@ -273,7 +270,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
#ifdef DEBUG_MMU
DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
#endif
- // error state?
+ /* error state? */
}
#endif
@@ -281,8 +278,9 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
{
#ifdef TARGET_SPARC64
- if (AM_CHECK(env1))
+ if (AM_CHECK(env1)) {
addr &= 0xffffffffULL;
+ }
#endif
return addr;
}
@@ -294,7 +292,7 @@ static inline int is_translating_asi(int asi)
#ifdef TARGET_SPARC64
/* Ultrasparc IIi translating asi
- note this list is defined by cpu implementation
- */
+ */
switch (asi) {
case 0x04 ... 0x11:
case 0x16 ... 0x19:
@@ -324,1298 +322,18 @@ static inline target_ulong asi_address_mask(CPUState *env1,
}
}
-static void raise_exception(int tt)
-{
- env->exception_index = tt;
- cpu_loop_exit(env);
-}
-
-void HELPER(raise_exception)(int tt)
-{
- raise_exception(tt);
-}
-
-void helper_shutdown(void)
-{
-#if !defined(CONFIG_USER_ONLY)
- qemu_system_shutdown_request();
-#endif
-}
-
void helper_check_align(target_ulong addr, uint32_t align)
{
if (addr & align) {
#ifdef DEBUG_UNALIGNED
- printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
- "\n", addr, env->pc);
-#endif
- raise_exception(TT_UNALIGNED);
- }
-}
-
-#define F_HELPER(name, p) void helper_f##name##p(void)
-
-#define F_BINOP(name) \
- float32 helper_f ## name ## s (float32 src1, float32 src2) \
- { \
- return float32_ ## name (src1, src2, &env->fp_status); \
- } \
- F_HELPER(name, d) \
- { \
- DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
- } \
- F_HELPER(name, q) \
- { \
- QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
- }
-
-F_BINOP(add);
-F_BINOP(sub);
-F_BINOP(mul);
-F_BINOP(div);
-#undef F_BINOP
-
-void helper_fsmuld(float32 src1, float32 src2)
-{
- DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
- float32_to_float64(src2, &env->fp_status),
- &env->fp_status);
-}
-
-void helper_fdmulq(void)
-{
- QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
- float64_to_float128(DT1, &env->fp_status),
- &env->fp_status);
-}
-
-float32 helper_fnegs(float32 src)
-{
- return float32_chs(src);
-}
-
-#ifdef TARGET_SPARC64
-F_HELPER(neg, d)
-{
- DT0 = float64_chs(DT1);
-}
-
-F_HELPER(neg, q)
-{
- QT0 = float128_chs(QT1);
-}
-#endif
-
-/* Integer to float conversion. */
-float32 helper_fitos(int32_t src)
-{
- return int32_to_float32(src, &env->fp_status);
-}
-
-void helper_fitod(int32_t src)
-{
- DT0 = int32_to_float64(src, &env->fp_status);
-}
-
-void helper_fitoq(int32_t src)
-{
- QT0 = int32_to_float128(src, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-float32 helper_fxtos(void)
-{
- return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, d)
-{
- DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, q)
-{
- QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
-}
-#endif
-#undef F_HELPER
-
-/* floating point conversion */
-float32 helper_fdtos(void)
-{
- return float64_to_float32(DT1, &env->fp_status);
-}
-
-void helper_fstod(float32 src)
-{
- DT0 = float32_to_float64(src, &env->fp_status);
-}
-
-float32 helper_fqtos(void)
-{
- return float128_to_float32(QT1, &env->fp_status);
-}
-
-void helper_fstoq(float32 src)
-{
- QT0 = float32_to_float128(src, &env->fp_status);
-}
-
-void helper_fqtod(void)
-{
- DT0 = float128_to_float64(QT1, &env->fp_status);
-}
-
-void helper_fdtoq(void)
-{
- QT0 = float64_to_float128(DT1, &env->fp_status);
-}
-
-/* Float to integer conversion. */
-int32_t helper_fstoi(float32 src)
-{
- return float32_to_int32_round_to_zero(src, &env->fp_status);
-}
-
-int32_t helper_fdtoi(void)
-{
- return float64_to_int32_round_to_zero(DT1, &env->fp_status);
-}
-
-int32_t helper_fqtoi(void)
-{
- return float128_to_int32_round_to_zero(QT1, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fstox(float32 src)
-{
- *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
-}
-
-void helper_fdtox(void)
-{
- *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
-}
-
-void helper_fqtox(void)
-{
- *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-}
-
-void helper_faligndata(void)
-{
- uint64_t tmp;
-
- tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
- /* on many architectures a shift of 64 does nothing */
- if ((env->gsr & 7) != 0) {
- tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
- }
- *((uint64_t *)&DT0) = tmp;
-}
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define VIS_B64(n) b[7 - (n)]
-#define VIS_W64(n) w[3 - (n)]
-#define VIS_SW64(n) sw[3 - (n)]
-#define VIS_L64(n) l[1 - (n)]
-#define VIS_B32(n) b[3 - (n)]
-#define VIS_W32(n) w[1 - (n)]
-#else
-#define VIS_B64(n) b[n]
-#define VIS_W64(n) w[n]
-#define VIS_SW64(n) sw[n]
-#define VIS_L64(n) l[n]
-#define VIS_B32(n) b[n]
-#define VIS_W32(n) w[n]
-#endif
-
-typedef union {
- uint8_t b[8];
- uint16_t w[4];
- int16_t sw[4];
- uint32_t l[2];
- uint64_t ll;
- float64 d;
-} vis64;
-
-typedef union {
- uint8_t b[4];
- uint16_t w[2];
- uint32_t l;
- float32 f;
-} vis32;
-
-void helper_fpmerge(void)
-{
- vis64 s, d;
-
- s.d = DT0;
- d.d = DT1;
-
- // Reverse calculation order to handle overlap
- d.VIS_B64(7) = s.VIS_B64(3);
- d.VIS_B64(6) = d.VIS_B64(3);
- d.VIS_B64(5) = s.VIS_B64(2);
- d.VIS_B64(4) = d.VIS_B64(2);
- d.VIS_B64(3) = s.VIS_B64(1);
- d.VIS_B64(2) = d.VIS_B64(1);
- d.VIS_B64(1) = s.VIS_B64(0);
- //d.VIS_B64(0) = d.VIS_B64(0);
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16al(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16au(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8sux16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8ulx16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmuld8sux16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_L64(r) = tmp;
-
- // Reverse calculation order to handle overlap
- PMUL(1);
- PMUL(0);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmuld8ulx16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_L64(r) = tmp;
-
- // Reverse calculation order to handle overlap
- PMUL(1);
- PMUL(0);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fexpand(void)
-{
- vis32 s;
- vis64 d;
-
- s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
- d.d = DT1;
- d.VIS_W64(0) = s.VIS_B32(0) << 4;
- d.VIS_W64(1) = s.VIS_B32(1) << 4;
- d.VIS_W64(2) = s.VIS_B32(2) << 4;
- d.VIS_W64(3) = s.VIS_B32(3) << 4;
-
- DT0 = d.d;
-}
-
-#define VIS_HELPER(name, F) \
- void name##16(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
- d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
- d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
- d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
- \
- DT0 = d.d; \
- } \
- \
- uint32_t name##16s(uint32_t src1, uint32_t src2) \
- { \
- vis32 s, d; \
- \
- s.l = src1; \
- d.l = src2; \
- \
- d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
- d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
- \
- return d.l; \
- } \
- \
- void name##32(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
- d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
- \
- DT0 = d.d; \
- } \
- \
- uint32_t name##32s(uint32_t src1, uint32_t src2) \
- { \
- vis32 s, d; \
- \
- s.l = src1; \
- d.l = src2; \
- \
- d.l = F(d.l, s.l); \
- \
- return d.l; \
- }
-
-#define FADD(a, b) ((a) + (b))
-#define FSUB(a, b) ((a) - (b))
-VIS_HELPER(helper_fpadd, FADD)
-VIS_HELPER(helper_fpsub, FSUB)
-
-#define VIS_CMPHELPER(name, F) \
- uint64_t name##16(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
- d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
- \
- return d.ll; \
- } \
- \
- uint64_t name##32(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
- d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
- d.VIS_L64(1) = 0; \
- \
- return d.ll; \
- }
-
-#define FCMPGT(a, b) ((a) > (b))
-#define FCMPEQ(a, b) ((a) == (b))
-#define FCMPLE(a, b) ((a) <= (b))
-#define FCMPNE(a, b) ((a) != (b))
-
-VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
-VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
-VIS_CMPHELPER(helper_fcmple, FCMPLE)
-VIS_CMPHELPER(helper_fcmpne, FCMPNE)
-#endif
-
-void helper_check_ieee_exceptions(void)
-{
- target_ulong status;
-
- status = get_float_exception_flags(&env->fp_status);
- if (status) {
- /* Copy IEEE 754 flags into FSR */
- if (status & float_flag_invalid)
- env->fsr |= FSR_NVC;
- if (status & float_flag_overflow)
- env->fsr |= FSR_OFC;
- if (status & float_flag_underflow)
- env->fsr |= FSR_UFC;
- if (status & float_flag_divbyzero)
- env->fsr |= FSR_DZC;
- if (status & float_flag_inexact)
- env->fsr |= FSR_NXC;
-
- if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
- /* Unmasked exception, generate a trap */
- env->fsr |= FSR_FTT_IEEE_EXCP;
- raise_exception(TT_FP_EXCP);
- } else {
- /* Accumulate exceptions */
- env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
- }
- }
-}
-
-void helper_clear_float_exceptions(void)
-{
- set_float_exception_flags(0, &env->fp_status);
-}
-
-float32 helper_fabss(float32 src)
-{
- return float32_abs(src);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fabsd(void)
-{
- DT0 = float64_abs(DT1);
-}
-
-void helper_fabsq(void)
-{
- QT0 = float128_abs(QT1);
-}
-#endif
-
-float32 helper_fsqrts(float32 src)
-{
- return float32_sqrt(src, &env->fp_status);
-}
-
-void helper_fsqrtd(void)
-{
- DT0 = float64_sqrt(DT1, &env->fp_status);
-}
-
-void helper_fsqrtq(void)
-{
- QT0 = float128_sqrt(QT1, &env->fp_status);
-}
-
-#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
- void glue(helper_, name) (void) \
- { \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(reg1) || \
- glue(size, _is_any_nan)(reg2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } \
- switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
- case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
- break; \
- case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC0 << FS; \
- break; \
- case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC1 << FS; \
- break; \
- default: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- break; \
- } \
- }
-#define GEN_FCMPS(name, size, FS, E) \
- void glue(helper_, name)(float32 src1, float32 src2) \
- { \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(src1) || \
- glue(size, _is_any_nan)(src2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } \
- switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
- case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
- break; \
- case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC0 << FS; \
- break; \
- case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC1 << FS; \
- break; \
- default: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- break; \
- } \
- }
-
-GEN_FCMPS(fcmps, float32, 0, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
-
-GEN_FCMPS(fcmpes, float32, 0, 1);
-GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
-
-GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
-GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
-
-static uint32_t compute_all_flags(void)
-{
- return env->psr & PSR_ICC;
-}
-
-static uint32_t compute_C_flags(void)
-{
- return env->psr & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_icc(int32_t dst)
-{
- uint32_t ret = 0;
-
- if (dst == 0) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_flags_xcc(void)
-{
- return env->xcc & PSR_ICC;
-}
-
-static uint32_t compute_C_flags_xcc(void)
-{
- return env->xcc & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_xcc(target_long dst)
-{
- uint32_t ret = 0;
-
- if (!dst) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-#endif
-
-static inline uint32_t get_V_div_icc(target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src2 != 0) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_div(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_V_div_icc(CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_div(void)
-{
- return 0;
-}
-
-static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_add_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_add_xcc(CC_DST, CC_SRC);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_add_xcc(void)
-{
- return get_C_add_xcc(CC_DST, CC_SRC);
-}
-#endif
-
-static uint32_t compute_all_add(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_add(void)
-{
- return get_C_add_icc(CC_DST, CC_SRC);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_addx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-#endif
-
-static uint32_t compute_all_addx(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx(void)
-{
- uint32_t ret;
-
- ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if ((src1 | src2) & 0x3) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_tadd(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_taddtv(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- return ret;
-}
-
-static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_sub_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_sub_xcc(void)
-{
- return get_C_sub_xcc(CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_sub(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_sub(void)
-{
- return get_C_sub_icc(CC_SRC, CC_SRC2);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_subx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-#endif
-
-static uint32_t compute_all_subx(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx(void)
-{
- uint32_t ret;
-
- ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_tsub(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_tsubtv(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_logic(void)
-{
- return get_NZ_icc(CC_DST);
-}
-
-static uint32_t compute_C_logic(void)
-{
- return 0;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_logic_xcc(void)
-{
- return get_NZ_xcc(CC_DST);
-}
-#endif
-
-typedef struct CCTable {
- uint32_t (*compute_all)(void); /* return all the flags */
- uint32_t (*compute_c)(void); /* return the C flag */
-} CCTable;
-
-static const CCTable icc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
- [CC_OP_DIV] = { compute_all_div, compute_C_div },
- [CC_OP_ADD] = { compute_all_add, compute_C_add },
- [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
- [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
- [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
- [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
- [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
- [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
- [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
- [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
-};
-
-#ifdef TARGET_SPARC64
-static const CCTable xcc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
- [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
- [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
- [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
- [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
-};
-#endif
-
-void helper_compute_psr(void)
-{
- uint32_t new_psr;
-
- new_psr = icc_table[CC_OP].compute_all();
- env->psr = new_psr;
-#ifdef TARGET_SPARC64
- new_psr = xcc_table[CC_OP].compute_all();
- env->xcc = new_psr;
+ printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+ "\n", addr, env->pc);
#endif
- CC_OP = CC_OP_FLAGS;
-}
-
-uint32_t helper_compute_C_icc(void)
-{
- uint32_t ret;
-
- ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
- return ret;
-}
-
-static inline void memcpy32(target_ulong *dst, const target_ulong *src)
-{
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst[3] = src[3];
- dst[4] = src[4];
- dst[5] = src[5];
- dst[6] = src[6];
- dst[7] = src[7];
-}
-
-static void set_cwp(int new_cwp)
-{
- /* put the modified wrap registers at their proper location */
- if (env->cwp == env->nwindows - 1) {
- memcpy32(env->regbase, env->regbase + env->nwindows * 16);
- }
- env->cwp = new_cwp;
-
- /* put the wrap registers at their temporary location */
- if (new_cwp == env->nwindows - 1) {
- memcpy32(env->regbase + env->nwindows * 16, env->regbase);
- }
- env->regwptr = env->regbase + (new_cwp * 16);
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- set_cwp(new_cwp);
- env = saved_env;
-}
-
-static target_ulong get_psr(void)
-{
- helper_compute_psr();
-
-#if !defined (TARGET_SPARC64)
- return env->version | (env->psr & PSR_ICC) |
- (env->psref? PSR_EF : 0) |
- (env->psrpil << 8) |
- (env->psrs? PSR_S : 0) |
- (env->psrps? PSR_PS : 0) |
- (env->psret? PSR_ET : 0) | env->cwp;
-#else
- return env->psr & PSR_ICC;
-#endif
-}
-
-target_ulong cpu_get_psr(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_psr();
- env = saved_env;
- return ret;
-}
-
-static void put_psr(target_ulong val)
-{
- env->psr = val & PSR_ICC;
-#if !defined (TARGET_SPARC64)
- env->psref = (val & PSR_EF)? 1 : 0;
- env->psrpil = (val & PSR_PIL) >> 8;
-#endif
-#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
- cpu_check_irqs(env);
-#endif
-#if !defined (TARGET_SPARC64)
- env->psrs = (val & PSR_S)? 1 : 0;
- env->psrps = (val & PSR_PS)? 1 : 0;
- env->psret = (val & PSR_ET)? 1 : 0;
- set_cwp(val & PSR_CWP);
-#endif
- env->cc_op = CC_OP_FLAGS;
-}
-
-void cpu_put_psr(CPUState *env1, target_ulong val)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_psr(val);
- env = saved_env;
-}
-
-static int cwp_inc(int cwp)
-{
- if (unlikely(cwp >= env->nwindows)) {
- cwp -= env->nwindows;
+ helper_raise_exception(env, TT_UNALIGNED);
}
- return cwp;
}
-int cpu_cwp_inc(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = cwp_inc(cwp);
- env = saved_env;
- return ret;
-}
-
-static int cwp_dec(int cwp)
-{
- if (unlikely(cwp < 0)) {
- cwp += env->nwindows;
- }
- return cwp;
-}
-
-int cpu_cwp_dec(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = cwp_dec(cwp);
- env = saved_env;
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
-
-GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
-
-GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
-GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
-
-GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
-GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
-GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
-
-GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
-GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
-GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
-
-GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
-GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
-GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
-#endif
-#undef GEN_FCMPS
-
-#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
defined(DEBUG_MXCC)
static void dump_mxcc(CPUState *env)
{
@@ -1634,13 +352,12 @@ static void dump_mxcc(CPUState *env)
}
#endif
-#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
&& defined(DEBUG_ASI)
static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
uint64_t r1)
{
- switch (size)
- {
+ switch (size) {
case 1:
DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
addr, asi, r1 & 0xff);
@@ -1785,33 +502,37 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
case 0x01c00a00: /* MXCC control register */
- if (size == 8)
+ if (size == 8) {
ret = env->mxccregs[3];
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00a04: /* MXCC control register */
- if (size == 4)
+ if (size == 4) {
ret = env->mxccregs[3];
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00c00: /* Module reset register */
if (size == 8) {
ret = env->mxccregs[5];
- // should we do something here?
- } else
+ /* should we do something here? */
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00f00: /* MBus port address register */
- if (size == 8)
+ if (size == 8) {
ret = env->mxccregs[7];
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
default:
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
@@ -1830,10 +551,11 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
int mmulev;
mmulev = (addr >> 8) & 15;
- if (mmulev > 4)
+ if (mmulev > 4) {
ret = 0;
- else
+ } else {
ret = mmu_probe(env, addr, mmulev);
+ }
DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
addr, mmulev, ret);
}
@@ -1843,21 +565,22 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
int reg = (addr >> 8) & 0x1f;
ret = env->mmuregs[reg];
- if (reg == 3) /* Fault status cleared on read */
+ if (reg == 3) { /* Fault status cleared on read */
env->mmuregs[3] = 0;
- else if (reg == 0x13) /* Fault status read */
+ } else if (reg == 0x13) { /* Fault status read */
ret = env->mmuregs[3];
- else if (reg == 0x14) /* Fault address read */
+ } else if (reg == 0x14) { /* Fault address read */
ret = env->mmuregs[4];
+ }
DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
}
break;
- case 5: // Turbosparc ITLB Diagnostic
- case 6: // Turbosparc DTLB Diagnostic
- case 7: // Turbosparc IOTLB Diagnostic
+ case 5: /* Turbosparc ITLB Diagnostic */
+ case 6: /* Turbosparc DTLB Diagnostic */
+ case 7: /* Turbosparc IOTLB Diagnostic */
break;
case 9: /* Supervisor code access */
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_code(addr);
break;
@@ -1874,7 +597,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
case 0xa: /* User data access */
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_user(addr);
break;
@@ -1891,7 +614,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
case 0xb: /* Supervisor data access */
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_kernel(addr);
break;
@@ -1913,7 +636,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
case 0xf: /* D-cache data */
break;
case 0x20: /* MMU passthrough */
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_phys(addr);
break;
@@ -1930,7 +653,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_phys((target_phys_addr_t)addr
| ((target_phys_addr_t)(asi & 0xf) << 32));
@@ -1950,9 +673,9 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
break;
}
break;
- case 0x30: // Turbosparc secondary cache diagnostic
- case 0x31: // Turbosparc RAM snoop
- case 0x32: // Turbosparc page table descriptor diagnostic
+ case 0x30: /* Turbosparc secondary cache diagnostic */
+ case 0x31: /* Turbosparc RAM snoop */
+ case 0x32: /* Turbosparc page table descriptor diagnostic */
case 0x39: /* data cache diagnostic register */
ret = 0;
break;
@@ -1960,7 +683,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
int reg = (addr >> 8) & 3;
- switch(reg) {
+ switch (reg) {
case 0: /* Breakpoint Value (Addr) */
ret = env->mmubpregs[reg];
break;
@@ -1998,7 +721,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
break;
}
if (sign) {
- switch(size) {
+ switch (size) {
case 1:
ret = (int8_t) ret;
break;
@@ -2021,7 +744,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
{
helper_check_align(addr, size - 1);
- switch(asi) {
+ switch (asi) {
case 2: /* SuperSparc MXCC registers and Leon3 cache control */
switch (addr) {
case 0x00: /* Leon3 Cache Control */
@@ -2033,39 +756,44 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
break;
case 0x01c00000: /* MXCC stream data register 0 */
- if (size == 8)
+ if (size == 8) {
env->mxccdata[0] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00008: /* MXCC stream data register 1 */
- if (size == 8)
+ if (size == 8) {
env->mxccdata[1] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00010: /* MXCC stream data register 2 */
- if (size == 8)
+ if (size == 8) {
env->mxccdata[2] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00018: /* MXCC stream data register 3 */
- if (size == 8)
+ if (size == 8) {
env->mxccdata[3] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00100: /* MXCC stream source */
- if (size == 8)
+ if (size == 8) {
env->mxccregs[0] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
0);
env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
@@ -2076,11 +804,12 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
24);
break;
case 0x01c00200: /* MXCC stream destination */
- if (size == 8)
+ if (size == 8) {
env->mxccregs[1] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0,
env->mxccdata[0]);
stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8,
@@ -2091,34 +820,38 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
env->mxccdata[3]);
break;
case 0x01c00a00: /* MXCC control register */
- if (size == 8)
+ if (size == 8) {
env->mxccregs[3] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00a04: /* MXCC control register */
- if (size == 4)
+ if (size == 4) {
env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
| val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00e00: /* MXCC error register */
- // writing a 1 bit clears the error
- if (size == 8)
+ /* writing a 1 bit clears the error */
+ if (size == 8) {
env->mxccregs[6] &= ~val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
case 0x01c00f00: /* MBus port address register */
- if (size == 8)
+ if (size == 8) {
env->mxccregs[7] = val;
- else
+ } else {
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
size);
+ }
break;
default:
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
@@ -2138,13 +871,13 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
mmulev = (addr >> 8) & 15;
DPRINTF_MMU("mmu flush level %d\n", mmulev);
switch (mmulev) {
- case 0: // flush page
+ case 0: /* flush page */
tlb_flush_page(env, addr & 0xfffff000);
break;
- case 1: // flush segment (256k)
- case 2: // flush region (16M)
- case 3: // flush context (4G)
- case 4: // flush entire
+ case 1: /* flush segment (256k) */
+ case 2: /* flush region (16M) */
+ case 3: /* flush context (4G) */
+ case 4: /* flush entire */
tlb_flush(env, 1);
break;
default:
@@ -2161,20 +894,21 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
uint32_t oldreg;
oldreg = env->mmuregs[reg];
- switch(reg) {
- case 0: // Control Register
+ switch (reg) {
+ case 0: /* Control Register */
env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
- (val & 0x00ffffff);
- // Mappings generated during no-fault mode or MMU
- // disabled mode are invalid in normal mode
+ (val & 0x00ffffff);
+ /* Mappings generated during no-fault mode or MMU
+ disabled mode are invalid in normal mode */
if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
- (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
+ (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
tlb_flush(env, 1);
+ }
break;
- case 1: // Context Table Pointer Register
+ case 1: /* Context Table Pointer Register */
env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
break;
- case 2: // Context Register
+ case 2: /* Context Register */
env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
if (oldreg != env->mmuregs[reg]) {
/* we flush when the MMU context changes because
@@ -2182,16 +916,17 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
tlb_flush(env, 1);
}
break;
- case 3: // Synchronous Fault Status Register with Clear
- case 4: // Synchronous Fault Address Register
+ case 3: /* Synchronous Fault Status Register with Clear */
+ case 4: /* Synchronous Fault Address Register */
break;
- case 0x10: // TLB Replacement Control Register
+ case 0x10: /* TLB Replacement Control Register */
env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
break;
- case 0x13: // Synchronous Fault Status Register with Read and Clear
+ case 0x13: /* Synchronous Fault Status Register with Read
+ and Clear */
env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
break;
- case 0x14: // Synchronous Fault Address Register
+ case 0x14: /* Synchronous Fault Address Register */
env->mmuregs[4] = val;
break;
default:
@@ -2207,12 +942,12 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
#endif
}
break;
- case 5: // Turbosparc ITLB Diagnostic
- case 6: // Turbosparc DTLB Diagnostic
- case 7: // Turbosparc IOTLB Diagnostic
+ case 5: /* Turbosparc ITLB Diagnostic */
+ case 6: /* Turbosparc DTLB Diagnostic */
+ case 7: /* Turbosparc IOTLB Diagnostic */
break;
case 0xa: /* User data access */
- switch(size) {
+ switch (size) {
case 1:
stb_user(addr, val);
break;
@@ -2229,7 +964,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
}
break;
case 0xb: /* Supervisor data access */
- switch(size) {
+ switch (size) {
case 1:
stb_kernel(addr, val);
break;
@@ -2257,9 +992,9 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
break;
case 0x17: /* Block copy, sta access */
{
- // val = src
- // addr = dst
- // copy 32 bytes
+ /* val = src
+ addr = dst
+ copy 32 bytes */
unsigned int i;
uint32_t src = val & ~3, dst = addr & ~3, temp;
@@ -2271,18 +1006,19 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
break;
case 0x1f: /* Block fill, stda access */
{
- // addr = dst
- // fill 32 bytes with val
+ /* addr = dst
+ fill 32 bytes with val */
unsigned int i;
uint32_t dst = addr & 7;
- for (i = 0; i < 32; i += 8, dst += 8)
+ for (i = 0; i < 32; i += 8, dst += 8) {
stq_kernel(dst, val);
+ }
}
break;
case 0x20: /* MMU passthrough */
{
- switch(size) {
+ switch (size) {
case 1:
stb_phys(addr, val);
break;
@@ -2301,7 +1037,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
break;
case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
{
- switch(size) {
+ switch (size) {
case 1:
stb_phys((target_phys_addr_t)addr
| ((target_phys_addr_t)(asi & 0xf) << 32), val);
@@ -2322,11 +1058,11 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
}
}
break;
- case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
- case 0x31: // store buffer data, Ross RT620 I-cache flush or
- // Turbosparc snoop RAM
- case 0x32: // store buffer control or Turbosparc page table
- // descriptor diagnostic
+ case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
+ case 0x31: /* store buffer data, Ross RT620 I-cache flush or
+ Turbosparc snoop RAM */
+ case 0x32: /* store buffer control or Turbosparc page table
+ descriptor diagnostic */
case 0x36: /* I-cache flash clear */
case 0x37: /* D-cache flash clear */
break;
@@ -2334,7 +1070,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
{
int reg = (addr >> 8) & 3;
- switch(reg) {
+ switch (reg) {
case 0: /* Breakpoint Value (Addr) */
env->mmubpregs[reg] = (val & 0xfffffffffULL);
break;
@@ -2386,26 +1122,27 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
target_ulong last_addr = addr;
#endif
- if (asi < 0x80)
- raise_exception(TT_PRIV_ACT);
+ if (asi < 0x80) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
helper_check_align(addr, size - 1);
addr = asi_address_mask(env, asi, addr);
switch (asi) {
- case 0x82: // Primary no-fault
- case 0x8a: // Primary no-fault LE
+ case 0x82: /* Primary no-fault */
+ case 0x8a: /* Primary no-fault LE */
if (page_check_range(addr, size, PAGE_READ) == -1) {
#ifdef DEBUG_ASI
dump_asi("read ", last_addr, asi, size, ret);
#endif
return 0;
}
- // Fall through
- case 0x80: // Primary
- case 0x88: // Primary LE
+ /* Fall through */
+ case 0x80: /* Primary */
+ case 0x88: /* Primary LE */
{
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_raw(addr);
break;
@@ -2422,18 +1159,18 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
}
break;
- case 0x83: // Secondary no-fault
- case 0x8b: // Secondary no-fault LE
+ case 0x83: /* Secondary no-fault */
+ case 0x8b: /* Secondary no-fault LE */
if (page_check_range(addr, size, PAGE_READ) == -1) {
#ifdef DEBUG_ASI
dump_asi("read ", last_addr, asi, size, ret);
#endif
return 0;
}
- // Fall through
- case 0x81: // Secondary
- case 0x89: // Secondary LE
- // XXX
+ /* Fall through */
+ case 0x81: /* Secondary */
+ case 0x89: /* Secondary LE */
+ /* XXX */
break;
default:
break;
@@ -2441,11 +1178,11 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
/* Convert from little endian */
switch (asi) {
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0x8a: // Primary no-fault LE
- case 0x8b: // Secondary no-fault LE
- switch(size) {
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0x8a: /* Primary no-fault LE */
+ case 0x8b: /* Secondary no-fault LE */
+ switch (size) {
case 2:
ret = bswap16(ret);
break;
@@ -2464,7 +1201,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
/* Convert to signed number */
if (sign) {
- switch(size) {
+ switch (size) {
case 1:
ret = (int8_t) ret;
break;
@@ -2489,17 +1226,18 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
#ifdef DEBUG_ASI
dump_asi("write", addr, asi, size, val);
#endif
- if (asi < 0x80)
- raise_exception(TT_PRIV_ACT);
+ if (asi < 0x80) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
helper_check_align(addr, size - 1);
addr = asi_address_mask(env, asi, addr);
/* Convert to little endian */
switch (asi) {
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- switch(size) {
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ switch (size) {
case 2:
val = bswap16(val);
break;
@@ -2516,11 +1254,11 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
break;
}
- switch(asi) {
- case 0x80: // Primary
- case 0x88: // Primary LE
+ switch (asi) {
+ case 0x80: /* Primary */
+ case 0x88: /* Primary LE */
{
- switch(size) {
+ switch (size) {
case 1:
stb_raw(addr, val);
break;
@@ -2537,15 +1275,15 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
}
}
break;
- case 0x81: // Secondary
- case 0x89: // Secondary LE
- // XXX
+ case 0x81: /* Secondary */
+ case 0x89: /* Secondary LE */
+ /* XXX */
return;
- case 0x82: // Primary no-fault, RO
- case 0x83: // Secondary no-fault, RO
- case 0x8a: // Primary no-fault LE, RO
- case 0x8b: // Secondary no-fault LE, RO
+ case 0x82: /* Primary no-fault, RO */
+ case 0x83: /* Secondary no-fault, RO */
+ case 0x8a: /* Primary no-fault LE, RO */
+ case 0x8b: /* Secondary no-fault LE, RO */
default:
do_unassigned_access(addr, 1, 0, 1, size);
return;
@@ -2566,8 +1304,9 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
helper_check_align(addr, size - 1);
addr = asi_address_mask(env, asi, addr);
@@ -2588,7 +1327,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
dump_asi("read ", last_addr, asi, size, ret);
#endif
/* env->exception_index is set in get_physical_address_data(). */
- raise_exception(env->exception_index);
+ helper_raise_exception(env, env->exception_index);
}
/* convert nonfaulting load ASIs to normal load ASIs */
@@ -2596,19 +1335,19 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
switch (asi) {
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x80: // Primary
- case 0x81: // Secondary
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0xe2: // UA2007 Primary block init
- case 0xe3: // UA2007 Secondary block init
+ case 0x10: /* As if user primary */
+ case 0x11: /* As if user secondary */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x80: /* Primary */
+ case 0x81: /* Secondary */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0xe2: /* UA2007 Primary block init */
+ case 0xe3: /* UA2007 Secondary block init */
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
if (cpu_hypervisor_mode(env)) {
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_hypv(addr);
break;
@@ -2626,7 +1365,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
} else {
/* secondary space access has lowest asi bit equal to 1 */
if (asi & 1) {
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_kernel_secondary(addr);
break;
@@ -2642,7 +1381,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
break;
}
} else {
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_kernel(addr);
break;
@@ -2662,7 +1401,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
} else {
/* secondary space access has lowest asi bit equal to 1 */
if (asi & 1) {
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_user_secondary(addr);
break;
@@ -2678,7 +1417,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
break;
}
} else {
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_user(addr);
break;
@@ -2696,12 +1435,12 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
}
break;
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
+ case 0x14: /* Bypass */
+ case 0x15: /* Bypass, non-cacheable */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
{
- switch(size) {
+ switch (size) {
case 1:
ret = ldub_phys(addr);
break;
@@ -2718,43 +1457,43 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
}
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
- // Only ldda allowed
- raise_exception(TT_ILL_INSN);
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+ Only ldda allowed */
+ helper_raise_exception(env, TT_ILL_INSN);
return 0;
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- {
- switch(size) {
- case 1:
- ret = ldub_nucleus(addr);
- break;
- case 2:
- ret = lduw_nucleus(addr);
- break;
- case 4:
- ret = ldl_nucleus(addr);
- break;
- default:
- case 8:
- ret = ldq_nucleus(addr);
+ case 0x04: /* Nucleus */
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ {
+ switch (size) {
+ case 1:
+ ret = ldub_nucleus(addr);
+ break;
+ case 2:
+ ret = lduw_nucleus(addr);
+ break;
+ case 4:
+ ret = ldl_nucleus(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_nucleus(addr);
+ break;
+ }
break;
}
+ case 0x4a: /* UPA config */
+ /* XXX */
break;
- }
- case 0x4a: // UPA config
- // XXX
- break;
- case 0x45: // LSU
+ case 0x45: /* LSU */
ret = env->lsu;
break;
- case 0x50: // I-MMU regs
+ case 0x50: /* I-MMU regs */
{
int reg = (addr >> 3) & 0xf;
if (reg == 0) {
- // I-TSB Tag Target register
+ /* I-TSB Tag Target register */
ret = ultrasparc_tag_target(env->immu.tag_access);
} else {
ret = env->immuregs[reg];
@@ -2762,102 +1501,102 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
break;
}
- case 0x51: // I-MMU 8k TSB pointer
+ case 0x51: /* I-MMU 8k TSB pointer */
{
- // env->immuregs[5] holds I-MMU TSB register value
- // env->immuregs[6] holds I-MMU Tag Access register value
+ /* env->immuregs[5] holds I-MMU TSB register value
+ env->immuregs[6] holds I-MMU Tag Access register value */
ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
8*1024);
break;
}
- case 0x52: // I-MMU 64k TSB pointer
+ case 0x52: /* I-MMU 64k TSB pointer */
{
- // env->immuregs[5] holds I-MMU TSB register value
- // env->immuregs[6] holds I-MMU Tag Access register value
+ /* env->immuregs[5] holds I-MMU TSB register value
+ env->immuregs[6] holds I-MMU Tag Access register value */
ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
64*1024);
break;
}
- case 0x55: // I-MMU data access
+ case 0x55: /* I-MMU data access */
{
int reg = (addr >> 3) & 0x3f;
ret = env->itlb[reg].tte;
break;
}
- case 0x56: // I-MMU tag read
+ case 0x56: /* I-MMU tag read */
{
int reg = (addr >> 3) & 0x3f;
ret = env->itlb[reg].tag;
break;
}
- case 0x58: // D-MMU regs
+ case 0x58: /* D-MMU regs */
{
int reg = (addr >> 3) & 0xf;
if (reg == 0) {
- // D-TSB Tag Target register
+ /* D-TSB Tag Target register */
ret = ultrasparc_tag_target(env->dmmu.tag_access);
} else {
ret = env->dmmuregs[reg];
}
break;
}
- case 0x59: // D-MMU 8k TSB pointer
+ case 0x59: /* D-MMU 8k TSB pointer */
{
- // env->dmmuregs[5] holds D-MMU TSB register value
- // env->dmmuregs[6] holds D-MMU Tag Access register value
+ /* env->dmmuregs[5] holds D-MMU TSB register value
+ env->dmmuregs[6] holds D-MMU Tag Access register value */
ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
8*1024);
break;
}
- case 0x5a: // D-MMU 64k TSB pointer
+ case 0x5a: /* D-MMU 64k TSB pointer */
{
- // env->dmmuregs[5] holds D-MMU TSB register value
- // env->dmmuregs[6] holds D-MMU Tag Access register value
+ /* env->dmmuregs[5] holds D-MMU TSB register value
+ env->dmmuregs[6] holds D-MMU Tag Access register value */
ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
64*1024);
break;
}
- case 0x5d: // D-MMU data access
+ case 0x5d: /* D-MMU data access */
{
int reg = (addr >> 3) & 0x3f;
ret = env->dtlb[reg].tte;
break;
}
- case 0x5e: // D-MMU tag read
+ case 0x5e: /* D-MMU tag read */
{
int reg = (addr >> 3) & 0x3f;
ret = env->dtlb[reg].tag;
break;
}
- case 0x46: // D-cache data
- case 0x47: // D-cache tag access
- case 0x4b: // E-cache error enable
- case 0x4c: // E-cache asynchronous fault status
- case 0x4d: // E-cache asynchronous fault address
- case 0x4e: // E-cache tag data
- case 0x66: // I-cache instruction access
- case 0x67: // I-cache tag access
- case 0x6e: // I-cache predecode
- case 0x6f: // I-cache LRU etc.
- case 0x76: // E-cache tag
- case 0x7e: // E-cache tag
- break;
- case 0x5b: // D-MMU data pointer
- case 0x48: // Interrupt dispatch, RO
- case 0x49: // Interrupt data receive
- case 0x7f: // Incoming interrupt vector, RO
- // XXX
- break;
- case 0x54: // I-MMU data in, WO
- case 0x57: // I-MMU demap, WO
- case 0x5c: // D-MMU data in, WO
- case 0x5f: // D-MMU demap, WO
- case 0x77: // Interrupt vector, WO
+ case 0x46: /* D-cache data */
+ case 0x47: /* D-cache tag access */
+ case 0x4b: /* E-cache error enable */
+ case 0x4c: /* E-cache asynchronous fault status */
+ case 0x4d: /* E-cache asynchronous fault address */
+ case 0x4e: /* E-cache tag data */
+ case 0x66: /* I-cache instruction access */
+ case 0x67: /* I-cache tag access */
+ case 0x6e: /* I-cache predecode */
+ case 0x6f: /* I-cache LRU etc. */
+ case 0x76: /* E-cache tag */
+ case 0x7e: /* E-cache tag */
+ break;
+ case 0x5b: /* D-MMU data pointer */
+ case 0x48: /* Interrupt dispatch, RO */
+ case 0x49: /* Interrupt data receive */
+ case 0x7f: /* Incoming interrupt vector, RO */
+ /* XXX */
+ break;
+ case 0x54: /* I-MMU data in, WO */
+ case 0x57: /* I-MMU demap, WO */
+ case 0x5c: /* D-MMU data in, WO */
+ case 0x5f: /* D-MMU demap, WO */
+ case 0x77: /* Interrupt vector, WO */
default:
do_unassigned_access(addr, 0, 0, 1, size);
ret = 0;
@@ -2866,13 +1605,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
/* Convert from little endian */
switch (asi) {
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
switch(size) {
case 2:
ret = bswap16(ret);
@@ -2892,7 +1631,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
/* Convert to signed number */
if (sign) {
- switch(size) {
+ switch (size) {
case 1:
ret = (int8_t) ret;
break;
@@ -2923,22 +1662,23 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
helper_check_align(addr, size - 1);
addr = asi_address_mask(env, asi, addr);
/* Convert to little endian */
switch (asi) {
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- switch(size) {
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ switch (size) {
case 2:
val = bswap16(val);
break;
@@ -2955,20 +1695,20 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
break;
}
- switch(asi) {
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x80: // Primary
- case 0x81: // Secondary
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0xe2: // UA2007 Primary block init
- case 0xe3: // UA2007 Secondary block init
+ switch (asi) {
+ case 0x10: /* As if user primary */
+ case 0x11: /* As if user secondary */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x80: /* Primary */
+ case 0x81: /* Secondary */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0xe2: /* UA2007 Primary block init */
+ case 0xe3: /* UA2007 Secondary block init */
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
if (cpu_hypervisor_mode(env)) {
- switch(size) {
+ switch (size) {
case 1:
stb_hypv(addr, val);
break;
@@ -2986,7 +1726,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
} else {
/* secondary space access has lowest asi bit equal to 1 */
if (asi & 1) {
- switch(size) {
+ switch (size) {
case 1:
stb_kernel_secondary(addr, val);
break;
@@ -3002,7 +1742,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
break;
}
} else {
- switch(size) {
+ switch (size) {
case 1:
stb_kernel(addr, val);
break;
@@ -3022,7 +1762,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
} else {
/* secondary space access has lowest asi bit equal to 1 */
if (asi & 1) {
- switch(size) {
+ switch (size) {
case 1:
stb_user_secondary(addr, val);
break;
@@ -3038,7 +1778,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
break;
}
} else {
- switch(size) {
+ switch (size) {
case 1:
stb_user(addr, val);
break;
@@ -3056,12 +1796,12 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
}
}
break;
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
+ case 0x14: /* Bypass */
+ case 0x15: /* Bypass, non-cacheable */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
{
- switch(size) {
+ switch (size) {
case 1:
stb_phys(addr, val);
break;
@@ -3078,43 +1818,43 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
}
}
return;
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
- // Only ldda allowed
- raise_exception(TT_ILL_INSN);
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+ Only ldda allowed */
+ helper_raise_exception(env, TT_ILL_INSN);
return;
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- {
- switch(size) {
- case 1:
- stb_nucleus(addr, val);
- break;
- case 2:
- stw_nucleus(addr, val);
- break;
- case 4:
- stl_nucleus(addr, val);
- break;
- default:
- case 8:
- stq_nucleus(addr, val);
+ case 0x04: /* Nucleus */
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ {
+ switch (size) {
+ case 1:
+ stb_nucleus(addr, val);
+ break;
+ case 2:
+ stw_nucleus(addr, val);
+ break;
+ case 4:
+ stl_nucleus(addr, val);
+ break;
+ default:
+ case 8:
+ stq_nucleus(addr, val);
+ break;
+ }
break;
}
- break;
- }
- case 0x4a: // UPA config
- // XXX
+ case 0x4a: /* UPA config */
+ /* XXX */
return;
- case 0x45: // LSU
+ case 0x45: /* LSU */
{
uint64_t oldreg;
oldreg = env->lsu;
env->lsu = val & (DMMU_E | IMMU_E);
- // Mappings generated during D/I MMU disabled mode are
- // invalid in normal mode
+ /* Mappings generated during D/I MMU disabled mode are
+ invalid in normal mode */
if (oldreg != env->lsu) {
DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
oldreg, env->lsu);
@@ -3125,31 +1865,32 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
}
return;
}
- case 0x50: // I-MMU regs
+ case 0x50: /* I-MMU regs */
{
int reg = (addr >> 3) & 0xf;
uint64_t oldreg;
oldreg = env->immuregs[reg];
- switch(reg) {
- case 0: // RO
+ switch (reg) {
+ case 0: /* RO */
return;
- case 1: // Not in I-MMU
+ case 1: /* Not in I-MMU */
case 2:
return;
- case 3: // SFSR
- if ((val & 1) == 0)
- val = 0; // Clear SFSR
+ case 3: /* SFSR */
+ if ((val & 1) == 0) {
+ val = 0; /* Clear SFSR */
+ }
env->immu.sfsr = val;
break;
- case 4: // RO
+ case 4: /* RO */
return;
- case 5: // TSB access
+ case 5: /* TSB access */
DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
PRIx64 "\n", env->immu.tsb, val);
env->immu.tsb = val;
break;
- case 6: // Tag access
+ case 6: /* Tag access */
env->immu.tag_access = val;
break;
case 7:
@@ -3168,12 +1909,12 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
#endif
return;
}
- case 0x54: // I-MMU data in
+ case 0x54: /* I-MMU data in */
replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
return;
- case 0x55: // I-MMU data access
+ case 0x55: /* I-MMU data access */
{
- // TODO: auto demap
+ /* TODO: auto demap */
unsigned int i = (addr >> 3) & 0x3f;
@@ -3185,48 +1926,48 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
#endif
return;
}
- case 0x57: // I-MMU demap
+ case 0x57: /* I-MMU demap */
demap_tlb(env->itlb, addr, "immu", env);
return;
- case 0x58: // D-MMU regs
+ case 0x58: /* D-MMU regs */
{
int reg = (addr >> 3) & 0xf;
uint64_t oldreg;
oldreg = env->dmmuregs[reg];
- switch(reg) {
- case 0: // RO
+ switch (reg) {
+ case 0: /* RO */
case 4:
return;
- case 3: // SFSR
+ case 3: /* SFSR */
if ((val & 1) == 0) {
- val = 0; // Clear SFSR, Fault address
+ val = 0; /* Clear SFSR, Fault address */
env->dmmu.sfar = 0;
}
env->dmmu.sfsr = val;
break;
- case 1: // Primary context
+ case 1: /* Primary context */
env->dmmu.mmu_primary_context = val;
/* can be optimized to only flush MMU_USER_IDX
and MMU_KERNEL_IDX entries */
tlb_flush(env, 1);
break;
- case 2: // Secondary context
+ case 2: /* Secondary context */
env->dmmu.mmu_secondary_context = val;
/* can be optimized to only flush MMU_USER_SECONDARY_IDX
and MMU_KERNEL_SECONDARY_IDX entries */
tlb_flush(env, 1);
break;
- case 5: // TSB access
+ case 5: /* TSB access */
DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
PRIx64 "\n", env->dmmu.tsb, val);
env->dmmu.tsb = val;
break;
- case 6: // Tag access
+ case 6: /* Tag access */
env->dmmu.tag_access = val;
break;
- case 7: // Virtual Watchpoint
- case 8: // Physical Watchpoint
+ case 7: /* Virtual Watchpoint */
+ case 8: /* Physical Watchpoint */
default:
env->dmmuregs[reg] = val;
break;
@@ -3241,10 +1982,10 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
#endif
return;
}
- case 0x5c: // D-MMU data in
+ case 0x5c: /* D-MMU data in */
replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
return;
- case 0x5d: // D-MMU data access
+ case 0x5d: /* D-MMU data access */
{
unsigned int i = (addr >> 3) & 0x3f;
@@ -3256,38 +1997,38 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
#endif
return;
}
- case 0x5f: // D-MMU demap
+ case 0x5f: /* D-MMU demap */
demap_tlb(env->dtlb, addr, "dmmu", env);
return;
- case 0x49: // Interrupt data receive
- // XXX
+ case 0x49: /* Interrupt data receive */
+ /* XXX */
return;
- case 0x46: // D-cache data
- case 0x47: // D-cache tag access
- case 0x4b: // E-cache error enable
- case 0x4c: // E-cache asynchronous fault status
- case 0x4d: // E-cache asynchronous fault address
- case 0x4e: // E-cache tag data
- case 0x66: // I-cache instruction access
- case 0x67: // I-cache tag access
- case 0x6e: // I-cache predecode
- case 0x6f: // I-cache LRU etc.
- case 0x76: // E-cache tag
- case 0x7e: // E-cache tag
+ case 0x46: /* D-cache data */
+ case 0x47: /* D-cache tag access */
+ case 0x4b: /* E-cache error enable */
+ case 0x4c: /* E-cache asynchronous fault status */
+ case 0x4d: /* E-cache asynchronous fault address */
+ case 0x4e: /* E-cache tag data */
+ case 0x66: /* I-cache instruction access */
+ case 0x67: /* I-cache tag access */
+ case 0x6e: /* I-cache predecode */
+ case 0x6f: /* I-cache LRU etc. */
+ case 0x76: /* E-cache tag */
+ case 0x7e: /* E-cache tag */
return;
- case 0x51: // I-MMU 8k TSB pointer, RO
- case 0x52: // I-MMU 64k TSB pointer, RO
- case 0x56: // I-MMU tag read, RO
- case 0x59: // D-MMU 8k TSB pointer, RO
- case 0x5a: // D-MMU 64k TSB pointer, RO
- case 0x5b: // D-MMU data pointer, RO
- case 0x5e: // D-MMU tag read, RO
- case 0x48: // Interrupt dispatch, RO
- case 0x7f: // Incoming interrupt vector, RO
- case 0x82: // Primary no-fault, RO
- case 0x83: // Secondary no-fault, RO
- case 0x8a: // Primary no-fault LE, RO
- case 0x8b: // Secondary no-fault LE, RO
+ case 0x51: /* I-MMU 8k TSB pointer, RO */
+ case 0x52: /* I-MMU 64k TSB pointer, RO */
+ case 0x56: /* I-MMU tag read, RO */
+ case 0x59: /* D-MMU 8k TSB pointer, RO */
+ case 0x5a: /* D-MMU 64k TSB pointer, RO */
+ case 0x5b: /* D-MMU data pointer, RO */
+ case 0x5e: /* D-MMU tag read, RO */
+ case 0x48: /* Interrupt dispatch, RO */
+ case 0x7f: /* Incoming interrupt vector, RO */
+ case 0x82: /* Primary no-fault, RO */
+ case 0x83: /* Secondary no-fault, RO */
+ case 0x8a: /* Primary no-fault LE, RO */
+ case 0x8b: /* Secondary no-fault LE, RO */
default:
do_unassigned_access(addr, 1, 0, 1, size);
return;
@@ -3300,20 +2041,22 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd)
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
|| (cpu_has_hypervisor(env)
&& asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
addr = asi_address_mask(env, asi, addr);
switch (asi) {
#if !defined(CONFIG_USER_ONLY)
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
helper_check_align(addr, 0xf);
if (rd == 0) {
env->gregs[1] = ldq_nucleus(addr + 8);
- if (asi == 0x2c)
+ if (asi == 0x2c) {
bswap64s(&env->gregs[1]);
+ }
} else if (rd < 8) {
env->gregs[rd] = ldq_nucleus(addr);
env->gregs[rd + 1] = ldq_nucleus(addr + 8);
@@ -3333,9 +2076,9 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd)
#endif
default:
helper_check_align(addr, 0x3);
- if (rd == 0)
+ if (rd == 0) {
env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
- else if (rd < 8) {
+ } else if (rd < 8) {
env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
} else {
@@ -3360,7 +2103,7 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
case 0xf8: /* UA2007/JPS1 Block load primary LE */
case 0xf9: /* UA2007/JPS1 Block load secondary LE */
if (rd & 7) {
- raise_exception(TT_ILL_INSN);
+ helper_raise_exception(env, TT_ILL_INSN);
return;
}
helper_check_align(addr, 0x3f);
@@ -3380,7 +2123,7 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
case 0x78: /* JPS1 Block load primary LE, user privilege */
case 0x79: /* JPS1 Block load secondary LE, user privilege */
if (rd & 7) {
- raise_exception(TT_ILL_INSN);
+ helper_raise_exception(env, TT_ILL_INSN);
return;
}
helper_check_align(addr, 0x3f);
@@ -3395,7 +2138,7 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
break;
}
- switch(size) {
+ switch (size) {
default:
case 4:
*((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
@@ -3433,7 +2176,7 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
case 0xf8: /* UA2007/JPS1 Block store primary LE */
case 0xf9: /* UA2007/JPS1 Block store secondary LE */
if (rd & 7) {
- raise_exception(TT_ILL_INSN);
+ helper_raise_exception(env, TT_ILL_INSN);
return;
}
helper_check_align(addr, 0x3f);
@@ -3453,7 +2196,7 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
case 0x78: /* JPS1 Block load primary LE, user privilege */
case 0x79: /* JPS1 Block load secondary LE, user privilege */
if (rd & 7) {
- raise_exception(TT_ILL_INSN);
+ helper_raise_exception(env, TT_ILL_INSN);
return;
}
helper_check_align(addr, 0x3f);
@@ -3468,7 +2211,7 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
break;
}
- switch(size) {
+ switch (size) {
default:
case 4:
helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
@@ -3497,8 +2240,9 @@ target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
val2 &= 0xffffffffUL;
ret = helper_ld_asi(addr, asi, 4, 0);
ret &= 0xffffffffUL;
- if (val2 == ret)
+ if (val2 == ret) {
helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+ }
return ret;
}
@@ -3508,30 +2252,13 @@ target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
target_ulong ret;
ret = helper_ld_asi(addr, asi, 8, 0);
- if (val2 == ret)
+ if (val2 == ret) {
helper_st_asi(addr, val1, asi, 8);
+ }
return ret;
}
#endif /* TARGET_SPARC64 */
-#ifndef TARGET_SPARC64
-void helper_rett(void)
-{
- unsigned int cwp;
-
- if (env->psret == 1)
- raise_exception(TT_ILL_INSN);
-
- env->psret = 1;
- cwp = cwp_inc(env->cwp + 1) ;
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
- env->psrs = env->psrps;
-}
-#endif
-
static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
{
int overflow = 0;
@@ -3542,7 +2269,7 @@ static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
x1 = (b & 0xffffffff);
if (x1 == 0) {
- raise_exception(TT_DIV_ZERO);
+ helper_raise_exception(env, TT_DIV_ZERO);
}
x0 = x0 / x1;
@@ -3579,12 +2306,12 @@ static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
x1 = (b & 0xffffffff);
if (x1 == 0) {
- raise_exception(TT_DIV_ZERO);
+ helper_raise_exception(env, TT_DIV_ZERO);
}
x0 = x0 / x1;
if ((int32_t) x0 != x0) {
- x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
+ x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
overflow = 1;
}
@@ -3658,7 +2385,7 @@ void helper_lddf(target_ulong addr, int mem_idx)
void helper_ldqf(target_ulong addr, int mem_idx)
{
- // XXX add 128 bit load
+ /* XXX add 128 bit load */
CPU_QuadU u;
helper_check_align(addr, 7);
@@ -3694,7 +2421,7 @@ void helper_ldqf(target_ulong addr, int mem_idx)
void helper_stqf(target_ulong addr, int mem_idx)
{
- // XXX add 128 bit store
+ /* XXX add 128 bit store */
CPU_QuadU u;
helper_check_align(addr, 7);
@@ -3728,415 +2455,8 @@ void helper_stqf(target_ulong addr, int mem_idx)
#endif
}
-static inline void set_fsr(void)
-{
- int rnd_mode;
-
- switch (env->fsr & FSR_RD_MASK) {
- case FSR_RD_NEAREST:
- rnd_mode = float_round_nearest_even;
- break;
- default:
- case FSR_RD_ZERO:
- rnd_mode = float_round_to_zero;
- break;
- case FSR_RD_POS:
- rnd_mode = float_round_up;
- break;
- case FSR_RD_NEG:
- rnd_mode = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_mode, &env->fp_status);
-}
-
-void helper_ldfsr(uint32_t new_fsr)
-{
- env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
- set_fsr();
-}
-
#ifdef TARGET_SPARC64
-void helper_ldxfsr(uint64_t new_fsr)
-{
- env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
- set_fsr();
-}
-#endif
-
-void helper_debug(void)
-{
- env->exception_index = EXCP_DEBUG;
- cpu_loop_exit(env);
-}
-
-#ifndef TARGET_SPARC64
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void helper_save(void)
-{
- uint32_t cwp;
-
- cwp = cwp_dec(env->cwp - 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_OVF);
- }
- set_cwp(cwp);
-}
-
-void helper_restore(void)
-{
- uint32_t cwp;
-
- cwp = cwp_inc(env->cwp + 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
-}
-
-void helper_wrpsr(target_ulong new_psr)
-{
- if ((new_psr & PSR_CWP) >= env->nwindows) {
- raise_exception(TT_ILL_INSN);
- } else {
- cpu_put_psr(env, new_psr);
- }
-}
-
-target_ulong helper_rdpsr(void)
-{
- return get_psr();
-}
-
-#else
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void helper_save(void)
-{
- uint32_t cwp;
-
- cwp = cwp_dec(env->cwp - 1);
- if (env->cansave == 0) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- if (env->cleanwin - env->canrestore == 0) {
- // XXX Clean windows without trap
- raise_exception(TT_CLRWIN);
- } else {
- env->cansave--;
- env->canrestore++;
- set_cwp(cwp);
- }
- }
-}
-
-void helper_restore(void)
-{
- uint32_t cwp;
-
- cwp = cwp_inc(env->cwp + 1);
- if (env->canrestore == 0) {
- raise_exception(TT_FILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- env->cansave++;
- env->canrestore--;
- set_cwp(cwp);
- }
-}
-
-void helper_flushw(void)
-{
- if (env->cansave != env->nwindows - 2) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- }
-}
-
-void helper_saved(void)
-{
- env->cansave++;
- if (env->otherwin == 0)
- env->canrestore--;
- else
- env->otherwin--;
-}
-
-void helper_restored(void)
-{
- env->canrestore++;
- if (env->cleanwin < env->nwindows - 1)
- env->cleanwin++;
- if (env->otherwin == 0)
- env->cansave--;
- else
- env->otherwin--;
-}
-
-static target_ulong get_ccr(void)
-{
- target_ulong psr;
-
- psr = get_psr();
-
- return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
-}
-
-target_ulong cpu_get_ccr(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_ccr();
- env = saved_env;
- return ret;
-}
-
-static void put_ccr(target_ulong val)
-{
- env->xcc = (val >> 4) << 20;
- env->psr = (val & 0xf) << 20;
- CC_OP = CC_OP_FLAGS;
-}
-
-void cpu_put_ccr(CPUState *env1, target_ulong val)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_ccr(val);
- env = saved_env;
-}
-
-static target_ulong get_cwp64(void)
-{
- return env->nwindows - 1 - env->cwp;
-}
-
-target_ulong cpu_get_cwp64(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_cwp64();
- env = saved_env;
- return ret;
-}
-
-static void put_cwp64(int cwp)
-{
- if (unlikely(cwp >= env->nwindows || cwp < 0)) {
- cwp %= env->nwindows;
- }
- set_cwp(env->nwindows - 1 - cwp);
-}
-
-void cpu_put_cwp64(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_cwp64(cwp);
- env = saved_env;
-}
-
-target_ulong helper_rdccr(void)
-{
- return get_ccr();
-}
-
-void helper_wrccr(target_ulong new_ccr)
-{
- put_ccr(new_ccr);
-}
-
-// CWP handling is reversed in V9, but we still use the V8 register
-// order.
-target_ulong helper_rdcwp(void)
-{
- return get_cwp64();
-}
-
-void helper_wrcwp(target_ulong new_cwp)
-{
- put_cwp64(new_cwp);
-}
-
-// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO) \
- ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
-
-// This function uses the order in the manuals, i.e. bit 0 is 2^0
-#define GET_FIELD_SP(X, FROM, TO) \
- GET_FIELD(X, 63 - (TO), 63 - (FROM))
-
-target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
-{
- return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
- (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
- (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
- (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
- (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
- (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
- (((pixel_addr >> 55) & 1) << 4) |
- (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
- GET_FIELD_SP(pixel_addr, 11, 12);
-}
-
-target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
-{
- uint64_t tmp;
-
- tmp = addr + offset;
- env->gsr &= ~7ULL;
- env->gsr |= tmp & 7ULL;
- return tmp & ~7ULL;
-}
-
-target_ulong helper_popc(target_ulong val)
-{
- return ctpop64(val);
-}
-
-static inline uint64_t *get_gregset(uint32_t pstate)
-{
- switch (pstate) {
- default:
- DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
- pstate,
- (pstate & PS_IG) ? " IG" : "",
- (pstate & PS_MG) ? " MG" : "",
- (pstate & PS_AG) ? " AG" : "");
- /* pass through to normal set of global registers */
- case 0:
- return env->bgregs;
- case PS_AG:
- return env->agregs;
- case PS_MG:
- return env->mgregs;
- case PS_IG:
- return env->igregs;
- }
-}
-
-static inline void change_pstate(uint32_t new_pstate)
-{
- uint32_t pstate_regs, new_pstate_regs;
- uint64_t *src, *dst;
-
- if (env->def->features & CPU_FEATURE_GL) {
- // PS_AG is not implemented in this case
- new_pstate &= ~PS_AG;
- }
-
- pstate_regs = env->pstate & 0xc01;
- new_pstate_regs = new_pstate & 0xc01;
-
- if (new_pstate_regs != pstate_regs) {
- DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
- pstate_regs, new_pstate_regs);
- // Switch global register bank
- src = get_gregset(new_pstate_regs);
- dst = get_gregset(pstate_regs);
- memcpy32(dst, env->gregs);
- memcpy32(env->gregs, src);
- }
- else {
- DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
- new_pstate_regs);
- }
- env->pstate = new_pstate;
-}
-
-void helper_wrpstate(target_ulong new_state)
-{
- change_pstate(new_state & 0xf3f);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- change_pstate(new_pstate);
- env = saved_env;
-}
-
-void helper_wrpil(target_ulong new_pil)
-{
-#if !defined(CONFIG_USER_ONLY)
- DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
- env->psrpil, (uint32_t)new_pil);
-
- env->psrpil = new_pil;
-
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void helper_done(void)
-{
- trap_state* tsptr = cpu_tsptr(env);
-
- env->pc = tsptr->tnpc;
- env->npc = tsptr->tnpc + 4;
- put_ccr(tsptr->tstate >> 32);
- env->asi = (tsptr->tstate >> 24) & 0xff;
- change_pstate((tsptr->tstate >> 8) & 0xf3f);
- put_cwp64(tsptr->tstate & 0xff);
- env->tl--;
-
- DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void helper_retry(void)
-{
- trap_state* tsptr = cpu_tsptr(env);
-
- env->pc = tsptr->tpc;
- env->npc = tsptr->tnpc;
- put_ccr(tsptr->tstate >> 32);
- env->asi = (tsptr->tstate >> 24) & 0xff;
- change_pstate((tsptr->tstate >> 8) & 0xf3f);
- put_cwp64(tsptr->tstate & 0xff);
- env->tl--;
-
- DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-static void do_modify_softint(const char* operation, uint32_t value)
+static void do_modify_softint(const char *operation, uint32_t value)
{
if (env->softint != value) {
env->softint = value;
@@ -4165,13 +2485,6 @@ void helper_write_softint(uint64_t value)
}
#endif
-#ifdef TARGET_SPARC64
-trap_state* cpu_tsptr(CPUState* env)
-{
- return &env->ts[env->tl & MAXTL_MASK];
-}
-#endif
-
#if !defined(CONFIG_USER_ONLY)
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
@@ -4218,7 +2531,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
"\n", addr, env->pc);
#endif
cpu_restore_state2(retaddr);
- raise_exception(TT_UNALIGNED);
+ helper_raise_exception(env, TT_UNALIGNED);
}
/* try to fill the TLB and return an exception if error. If retaddr is
@@ -4252,29 +2565,34 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
int fault_type;
#ifdef DEBUG_UNASSIGNED
- if (is_asi)
+ if (is_asi) {
printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
" asi 0x%02x from " TARGET_FMT_lx "\n",
is_exec ? "exec" : is_write ? "write" : "read", size,
size == 1 ? "" : "s", addr, is_asi, env->pc);
- else
+ } else {
printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
" from " TARGET_FMT_lx "\n",
is_exec ? "exec" : is_write ? "write" : "read", size,
size == 1 ? "" : "s", addr, env->pc);
+ }
#endif
/* Don't overwrite translation and access faults */
fault_type = (env->mmuregs[3] & 0x1c) >> 2;
if ((fault_type > 4) || (fault_type == 0)) {
env->mmuregs[3] = 0; /* Fault status register */
- if (is_asi)
+ if (is_asi) {
env->mmuregs[3] |= 1 << 16;
- if (env->psrs)
+ }
+ if (env->psrs) {
env->mmuregs[3] |= 1 << 5;
- if (is_exec)
+ }
+ if (is_exec) {
env->mmuregs[3] |= 1 << 6;
- if (is_write)
+ }
+ if (is_write) {
env->mmuregs[3] |= 1 << 7;
+ }
env->mmuregs[3] |= (5 << 2) | 2;
/* SuperSPARC will never place instruction fault addresses in the FAR */
if (!is_exec) {
@@ -4287,10 +2605,11 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
}
if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
- if (is_exec)
- raise_exception(TT_CODE_ACCESS);
- else
- raise_exception(TT_DATA_ACCESS);
+ if (is_exec) {
+ helper_raise_exception(env, TT_CODE_ACCESS);
+ } else {
+ helper_raise_exception(env, TT_DATA_ACCESS);
+ }
}
/* flush neverland mappings created during no-fault mode,
@@ -4303,7 +2622,7 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
#else
#if defined(CONFIG_USER_ONLY)
static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
- int is_asi, int size)
+ int is_asi, int size)
#else
static void do_unassigned_access(target_phys_addr_t addr, int is_write,
int is_exec, int is_asi, int size)
@@ -4314,36 +2633,11 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
"\n", addr, env->pc);
#endif
- if (is_exec)
- raise_exception(TT_CODE_ACCESS);
- else
- raise_exception(TT_DATA_ACCESS);
-}
-#endif
-
-
-#ifdef TARGET_SPARC64
-void helper_tick_set_count(void *opaque, uint64_t count)
-{
-#if !defined(CONFIG_USER_ONLY)
- cpu_tick_set_count(opaque, count);
-#endif
-}
-
-uint64_t helper_tick_get_count(void *opaque)
-{
-#if !defined(CONFIG_USER_ONLY)
- return cpu_tick_get_count(opaque);
-#else
- return 0;
-#endif
-}
-
-void helper_tick_set_limit(void *opaque, uint64_t limit)
-{
-#if !defined(CONFIG_USER_ONLY)
- cpu_tick_set_limit(opaque, limit);
-#endif
+ if (is_exec) {
+ helper_raise_exception(env, TT_CODE_ACCESS);
+ } else {
+ helper_raise_exception(env, TT_DATA_ACCESS);
+ }
}
#endif
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index dee67b334f..528ca920de 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -294,7 +294,7 @@ static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
tcg_temp_free(r_temp);
@@ -310,7 +310,7 @@ static inline void gen_tag_tv(TCGv src1, TCGv src2)
tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
}
@@ -428,7 +428,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
default:
/* We need external help to produce the carry. */
carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32);
+ gen_helper_compute_C_icc(carry_32, cpu_env);
break;
}
@@ -492,7 +492,7 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
tcg_temp_free(r_temp);
@@ -567,7 +567,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
default:
/* We need external help to produce the carry. */
carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32);
+ gen_helper_compute_C_icc(carry_32, cpu_env);
break;
}
@@ -719,7 +719,7 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor)
l1 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1);
r_const = tcg_const_i32(TT_DIV_ZERO);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
}
@@ -1091,7 +1091,7 @@ static inline void save_state(DisasContext *dc, TCGv cond)
/* flush pending conditional evaluations before exposing cpu state */
if (dc->cc_op != CC_OP_FLAGS) {
dc->cc_op = CC_OP_FLAGS;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
}
save_npc(dc, cond);
}
@@ -1133,7 +1133,7 @@ static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond,
case CC_OP_FLAGS:
break;
default:
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
dc->cc_op = CC_OP_FLAGS;
break;
}
@@ -1405,16 +1405,16 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
- gen_helper_fcmps(r_rs1, r_rs2);
+ gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
break;
case 1:
- gen_helper_fcmps_fcc1(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
break;
case 2:
- gen_helper_fcmps_fcc2(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
break;
case 3:
- gen_helper_fcmps_fcc3(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
break;
}
}
@@ -1423,16 +1423,16 @@ static inline void gen_op_fcmpd(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpd();
+ gen_helper_fcmpd(cpu_env);
break;
case 1:
- gen_helper_fcmpd_fcc1();
+ gen_helper_fcmpd_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpd_fcc2();
+ gen_helper_fcmpd_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpd_fcc3();
+ gen_helper_fcmpd_fcc3(cpu_env);
break;
}
}
@@ -1441,16 +1441,16 @@ static inline void gen_op_fcmpq(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpq();
+ gen_helper_fcmpq(cpu_env);
break;
case 1:
- gen_helper_fcmpq_fcc1();
+ gen_helper_fcmpq_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpq_fcc2();
+ gen_helper_fcmpq_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpq_fcc3();
+ gen_helper_fcmpq_fcc3(cpu_env);
break;
}
}
@@ -1459,16 +1459,16 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
- gen_helper_fcmpes(r_rs1, r_rs2);
+ gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
break;
case 1:
- gen_helper_fcmpes_fcc1(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
break;
case 2:
- gen_helper_fcmpes_fcc2(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
break;
case 3:
- gen_helper_fcmpes_fcc3(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
break;
}
}
@@ -1477,16 +1477,16 @@ static inline void gen_op_fcmped(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmped();
+ gen_helper_fcmped(cpu_env);
break;
case 1:
- gen_helper_fcmped_fcc1();
+ gen_helper_fcmped_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmped_fcc2();
+ gen_helper_fcmped_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmped_fcc3();
+ gen_helper_fcmped_fcc3(cpu_env);
break;
}
}
@@ -1495,16 +1495,16 @@ static inline void gen_op_fcmpeq(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpeq();
+ gen_helper_fcmpeq(cpu_env);
break;
case 1:
- gen_helper_fcmpeq_fcc1();
+ gen_helper_fcmpeq_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpeq_fcc2();
+ gen_helper_fcmpeq_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpeq_fcc3();
+ gen_helper_fcmpeq_fcc3(cpu_env);
break;
}
}
@@ -1513,32 +1513,32 @@ static inline void gen_op_fcmpeq(int fccno)
static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
{
- gen_helper_fcmps(r_rs1, r_rs2);
+ gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
}
static inline void gen_op_fcmpd(int fccno)
{
- gen_helper_fcmpd();
+ gen_helper_fcmpd(cpu_env);
}
static inline void gen_op_fcmpq(int fccno)
{
- gen_helper_fcmpq();
+ gen_helper_fcmpq(cpu_env);
}
static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
{
- gen_helper_fcmpes(r_rs1, r_rs2);
+ gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
}
static inline void gen_op_fcmped(int fccno)
{
- gen_helper_fcmped();
+ gen_helper_fcmped(cpu_env);
}
static inline void gen_op_fcmpeq(int fccno)
{
- gen_helper_fcmpeq();
+ gen_helper_fcmpeq(cpu_env);
}
#endif
@@ -1549,7 +1549,7 @@ static inline void gen_op_fpexception_im(int fsr_flags)
tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
r_const = tcg_const_i32(TT_FP_EXCP);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
}
@@ -1561,7 +1561,7 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
save_state(dc, r_cond);
r_const = tcg_const_i32(TT_NFPU_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
return 1;
@@ -1584,7 +1584,7 @@ static inline void gen_op_clear_ieee_excp_and_FTT(void)
static inline void gen_clear_float_exceptions(void)
{
- gen_helper_clear_float_exceptions();
+ gen_helper_clear_float_exceptions(cpu_env);
}
/* asi moves */
@@ -2038,7 +2038,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_helper_shutdown();
} else {
- gen_helper_raise_exception(cpu_tmp32);
+ gen_helper_raise_exception(cpu_env, cpu_tmp32);
}
} else if (cond != 0) {
TCGv r_cond = tcg_temp_new();
@@ -2068,7 +2068,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
- gen_helper_raise_exception(cpu_tmp32);
+ gen_helper_raise_exception(cpu_env, cpu_tmp32);
gen_set_label(l1);
tcg_temp_free(r_cond);
@@ -2106,7 +2106,7 @@ static void disas_sparc_insn(DisasContext * dc)
break;
#ifdef TARGET_SPARC64
case 0x2: /* V9 rdccr */
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
gen_helper_rdccr(cpu_dst);
gen_movl_TN_reg(rd, cpu_dst);
break;
@@ -2182,7 +2182,7 @@ static void disas_sparc_insn(DisasContext * dc)
#ifndef TARGET_SPARC64
if (!supervisor(dc))
goto priv_insn;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
dc->cc_op = CC_OP_FLAGS;
gen_helper_rdpsr(cpu_dst);
#else
@@ -2383,8 +2383,8 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x29: /* fsqrts */
CHECK_FPU_FEATURE(dc, FSQRT);
gen_clear_float_exceptions();
- gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrts(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2392,8 +2392,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FSQRT);
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsqrtd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrtd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2401,15 +2401,16 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsqrtq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrtq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x41: /* fadds */
gen_clear_float_exceptions();
- gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fadds(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2417,8 +2418,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_faddd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_faddd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2427,15 +2428,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_faddq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_faddq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x45: /* fsubs */
gen_clear_float_exceptions();
- gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2443,8 +2445,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsubd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2453,16 +2455,17 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsubq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x49: /* fmuls */
CHECK_FPU_FEATURE(dc, FMUL);
gen_clear_float_exceptions();
- gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmuls(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2471,8 +2474,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fmuld();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmuld(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2482,15 +2485,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fmulq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmulq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x4d: /* fdivs */
gen_clear_float_exceptions();
- gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2498,8 +2502,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdivd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2508,16 +2512,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdivq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x69: /* fsmuld */
CHECK_FPU_FEATURE(dc, FSMULD);
gen_clear_float_exceptions();
- gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsmuld(cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2526,23 +2530,23 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdmulq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdmulq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xc4: /* fitos */
gen_clear_float_exceptions();
- gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fitos(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xc6: /* fdtos */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2550,18 +2554,18 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xc8: /* fitod */
- gen_helper_fitod(cpu_fpr[rs2]);
+ gen_helper_fitod(cpu_env, cpu_fpr[rs2]);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xc9: /* fstod */
- gen_helper_fstod(cpu_fpr[rs2]);
+ gen_helper_fstod(cpu_env, cpu_fpr[rs2]);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2569,42 +2573,42 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtod();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtod(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xcc: /* fitoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fitoq(cpu_fpr[rs2]);
+ gen_helper_fitoq(cpu_env, cpu_fpr[rs2]);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xcd: /* fstoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fstoq(cpu_fpr[rs2]);
+ gen_helper_fstoq(cpu_env, cpu_fpr[rs2]);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xce: /* fdtoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fdtoq();
+ gen_helper_fdtoq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xd1: /* fstoi */
gen_clear_float_exceptions();
- gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fstoi(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xd2: /* fdtoi */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtoi(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2612,8 +2616,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtoi(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2637,42 +2641,42 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x6: /* V9 fnegd */
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fnegd();
+ gen_helper_fnegd(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x7: /* V9 fnegq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fnegq();
+ gen_helper_fnegq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xa: /* V9 fabsd */
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fabsd();
+ gen_helper_fabsd(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xb: /* V9 fabsq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fabsq();
+ gen_helper_fabsq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x81: /* V9 fstox */
gen_clear_float_exceptions();
- gen_helper_fstox(cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fstox(cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x82: /* V9 fdtox */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtox();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtox(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2680,24 +2684,24 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtox();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtox(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x84: /* V9 fxtos */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0x88: /* V9 fxtod */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtod();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtod(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2705,8 +2709,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtoq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtoq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
@@ -3317,7 +3321,7 @@ static void disas_sparc_insn(DisasContext * dc)
dc->cc_op = CC_OP_TSUBTV;
break;
case 0x24: /* mulscc */
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
@@ -3828,14 +3832,14 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x012: /* VIS I array16 */
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
tcg_gen_shli_i64(cpu_dst, cpu_dst, 1);
gen_movl_TN_reg(rd, cpu_dst);
break;
@@ -3843,7 +3847,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
tcg_gen_shli_i64(cpu_dst, cpu_dst, 2);
gen_movl_TN_reg(rd, cpu_dst);
break;
@@ -3851,7 +3855,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_alignaddr(cpu_dst, cpu_env, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x019: /* VIS II bmask */
@@ -3862,63 +3866,63 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmple16(cpu_dst);
+ gen_helper_fcmple16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x022: /* VIS I fcmpne16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpne16(cpu_dst);
+ gen_helper_fcmpne16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x024: /* VIS I fcmple32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmple32(cpu_dst);
+ gen_helper_fcmple32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x026: /* VIS I fcmpne32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpne32(cpu_dst);
+ gen_helper_fcmpne32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x028: /* VIS I fcmpgt16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpgt16(cpu_dst);
+ gen_helper_fcmpgt16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02a: /* VIS I fcmpeq16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpeq16(cpu_dst);
+ gen_helper_fcmpeq16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02c: /* VIS I fcmpgt32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpgt32(cpu_dst);
+ gen_helper_fcmpgt32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02e: /* VIS I fcmpeq32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpeq32(cpu_dst);
+ gen_helper_fcmpeq32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x031: /* VIS I fmul8x16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16();
+ gen_helper_fmul8x16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3926,7 +3930,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16au();
+ gen_helper_fmul8x16au(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3934,7 +3938,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16al();
+ gen_helper_fmul8x16al(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3942,7 +3946,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8sux16();
+ gen_helper_fmul8sux16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3950,7 +3954,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8ulx16();
+ gen_helper_fmul8ulx16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3958,7 +3962,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmuld8sux16();
+ gen_helper_fmuld8sux16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3966,7 +3970,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmuld8ulx16();
+ gen_helper_fmuld8ulx16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3980,7 +3984,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_faligndata();
+ gen_helper_faligndata(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3988,7 +3992,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpmerge();
+ gen_helper_fpmerge(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3999,7 +4003,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fexpand();
+ gen_helper_fexpand(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -4007,13 +4011,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpadd16();
+ gen_helper_fpadd16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x051: /* VIS I fpadd16s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpadd16s(cpu_fpr[rd],
+ gen_helper_fpadd16s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4021,13 +4025,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpadd32();
+ gen_helper_fpadd32(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x053: /* VIS I fpadd32s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpadd32s(cpu_fpr[rd],
+ gen_helper_fpadd32s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4035,13 +4039,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpsub16();
+ gen_helper_fpsub16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x055: /* VIS I fpsub16s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpsub16s(cpu_fpr[rd],
+ gen_helper_fpsub16s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4049,13 +4053,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpsub32();
+ gen_helper_fpsub32(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x057: /* VIS I fpsub32s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpsub32s(cpu_fpr[rd],
+ gen_helper_fpsub32s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4413,7 +4417,7 @@ static void disas_sparc_insn(DisasContext * dc)
cpu state */
if (dc->cc_op != CC_OP_FLAGS) {
dc->cc_op = CC_OP_FLAGS;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
}
cpu_src1 = get_src1(insn, cpu_src1);
if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa
@@ -4659,16 +4663,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_address_mask(dc, cpu_addr);
if (rd == 1) {
tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
- gen_helper_ldxfsr(cpu_tmp64);
+ gen_helper_ldxfsr(cpu_env, cpu_tmp64);
} else {
tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
- gen_helper_ldfsr(cpu_tmp32);
+ gen_helper_ldfsr(cpu_env, cpu_tmp32);
}
#else
{
tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
- gen_helper_ldfsr(cpu_tmp32);
+ gen_helper_ldfsr(cpu_env, cpu_tmp32);
}
#endif
break;
@@ -4931,7 +4935,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_ILL_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4942,7 +4946,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_UNIMP_FLUSH);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4954,7 +4958,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_PRIV_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4979,7 +4983,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_NCP_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free(r_const);
dc->is_br = 1;
}
@@ -5036,7 +5040,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
if (bp->pc == dc->pc) {
if (dc->pc != pc_start)
save_state(dc, cpu_cond);
- gen_helper_debug();
+ gen_helper_debug(cpu_env);
tcg_gen_exit_tb(0);
dc->is_br = 1;
goto exit_gen_loop;
@@ -5265,6 +5269,6 @@ void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
/* flush pending conditional evaluations before exposing cpu state */
if (CC_OP != CC_OP_FLAGS) {
- helper_compute_psr();
+ helper_compute_psr(env);
}
}
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
new file mode 100644
index 0000000000..a22c10bb43
--- /dev/null
+++ b/target-sparc/vis_helper.c
@@ -0,0 +1,406 @@
+/*
+ * VIS op helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+/* This function uses non-native bit order */
+#define GET_FIELD(X, FROM, TO) \
+ ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
+#define GET_FIELD_SP(X, FROM, TO) \
+ GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+target_ulong helper_array8(CPUState *env, target_ulong pixel_addr,
+ target_ulong cubesize)
+{
+ return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
+ (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
+ (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
+ (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
+ (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
+ (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
+ (((pixel_addr >> 55) & 1) << 4) |
+ (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
+ GET_FIELD_SP(pixel_addr, 11, 12);
+}
+
+target_ulong helper_alignaddr(CPUState *env, target_ulong addr,
+ target_ulong offset)
+{
+ uint64_t tmp;
+
+ tmp = addr + offset;
+ env->gsr &= ~7ULL;
+ env->gsr |= tmp & 7ULL;
+ return tmp & ~7ULL;
+}
+
+void helper_faligndata(CPUState *env)
+{
+ uint64_t tmp;
+
+ tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+ /* on many architectures a shift of 64 does nothing */
+ if ((env->gsr & 7) != 0) {
+ tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+ }
+ *((uint64_t *)&DT0) = tmp;
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+ uint8_t b[8];
+ uint16_t w[4];
+ int16_t sw[4];
+ uint32_t l[2];
+ uint64_t ll;
+ float64 d;
+} VIS64;
+
+typedef union {
+ uint8_t b[4];
+ uint16_t w[2];
+ uint32_t l;
+ float32 f;
+} VIS32;
+
+void helper_fpmerge(CPUState *env)
+{
+ VIS64 s, d;
+
+ s.d = DT0;
+ d.d = DT1;
+
+ /* Reverse calculation order to handle overlap */
+ d.VIS_B64(7) = s.VIS_B64(3);
+ d.VIS_B64(6) = d.VIS_B64(3);
+ d.VIS_B64(5) = s.VIS_B64(2);
+ d.VIS_B64(4) = d.VIS_B64(2);
+ d.VIS_B64(3) = s.VIS_B64(1);
+ d.VIS_B64(2) = d.VIS_B64(1);
+ d.VIS_B64(1) = s.VIS_B64(0);
+ /* d.VIS_B64(0) = d.VIS_B64(0); */
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16al(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16au(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8sux16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8ulx16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmuld8sux16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_L64(r) = tmp;
+
+ /* Reverse calculation order to handle overlap */
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmuld8ulx16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_L64(r) = tmp;
+
+ /* Reverse calculation order to handle overlap */
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fexpand(CPUState *env)
+{
+ VIS32 s;
+ VIS64 d;
+
+ s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+ d.d = DT1;
+ d.VIS_W64(0) = s.VIS_B32(0) << 4;
+ d.VIS_W64(1) = s.VIS_B32(1) << 4;
+ d.VIS_W64(2) = s.VIS_B32(2) << 4;
+ d.VIS_W64(3) = s.VIS_B32(3) << 4;
+
+ DT0 = d.d;
+}
+
+#define VIS_HELPER(name, F) \
+ void name##16(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
+ d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
+ d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
+ d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ uint32_t name##16s(CPUState *env, uint32_t src1, \
+ uint32_t src2) \
+ { \
+ VIS32 s, d; \
+ \
+ s.l = src1; \
+ d.l = src2; \
+ \
+ d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
+ d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
+ \
+ return d.l; \
+ } \
+ \
+ void name##32(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
+ d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ uint32_t name##32s(CPUState *env, uint32_t src1, \
+ uint32_t src2) \
+ { \
+ VIS32 s, d; \
+ \
+ s.l = src1; \
+ d.l = src2; \
+ \
+ d.l = F(d.l, s.l); \
+ \
+ return d.l; \
+ }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_HELPER(helper_fpadd, FADD)
+VIS_HELPER(helper_fpsub, FSUB)
+
+#define VIS_CMPHELPER(name, F) \
+ uint64_t name##16(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
+ d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
+ \
+ return d.ll; \
+ } \
+ \
+ uint64_t name##32(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
+ d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
+ d.VIS_L64(1) = 0; \
+ \
+ return d.ll; \
+ }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
+VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
+VIS_CMPHELPER(helper_fcmple, FCMPLE)
+VIS_CMPHELPER(helper_fcmpne, FCMPNE)
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
new file mode 100644
index 0000000000..8bf2123e9c
--- /dev/null
+++ b/target-sparc/win_helper.c
@@ -0,0 +1,518 @@
+/*
+ * Helpers for CWP and PSTATE handling
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+//#define DEBUG_PSTATE
+
+#ifdef DEBUG_PSTATE
+#define DPRINTF_PSTATE(fmt, ...) \
+ do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
+#endif
+
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+
+static void set_cwp(int new_cwp)
+{
+ /* put the modified wrap registers at their proper location */
+ if (env->cwp == env->nwindows - 1) {
+ memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+ }
+ env->cwp = new_cwp;
+
+ /* put the wrap registers at their temporary location */
+ if (new_cwp == env->nwindows - 1) {
+ memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+ }
+ env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+void cpu_set_cwp(CPUState *env1, int new_cwp)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ set_cwp(new_cwp);
+ env = saved_env;
+}
+
+static target_ulong get_psr(void)
+{
+ helper_compute_psr(env);
+
+#if !defined(TARGET_SPARC64)
+ return env->version | (env->psr & PSR_ICC) |
+ (env->psref ? PSR_EF : 0) |
+ (env->psrpil << 8) |
+ (env->psrs ? PSR_S : 0) |
+ (env->psrps ? PSR_PS : 0) |
+ (env->psret ? PSR_ET : 0) | env->cwp;
+#else
+ return env->psr & PSR_ICC;
+#endif
+}
+
+target_ulong cpu_get_psr(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_psr();
+ env = saved_env;
+ return ret;
+}
+
+static void put_psr(target_ulong val)
+{
+ env->psr = val & PSR_ICC;
+#if !defined(TARGET_SPARC64)
+ env->psref = (val & PSR_EF) ? 1 : 0;
+ env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+ cpu_check_irqs(env);
+#endif
+#if !defined(TARGET_SPARC64)
+ env->psrs = (val & PSR_S) ? 1 : 0;
+ env->psrps = (val & PSR_PS) ? 1 : 0;
+ env->psret = (val & PSR_ET) ? 1 : 0;
+ set_cwp(val & PSR_CWP);
+#endif
+ env->cc_op = CC_OP_FLAGS;
+}
+
+void cpu_put_psr(CPUState *env1, target_ulong val)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_psr(val);
+ env = saved_env;
+}
+
+static int cwp_inc(int cwp)
+{
+ if (unlikely(cwp >= env->nwindows)) {
+ cwp -= env->nwindows;
+ }
+ return cwp;
+}
+
+int cpu_cwp_inc(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = cwp_inc(cwp);
+ env = saved_env;
+ return ret;
+}
+
+static int cwp_dec(int cwp)
+{
+ if (unlikely(cwp < 0)) {
+ cwp += env->nwindows;
+ }
+ return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = cwp_dec(cwp);
+ env = saved_env;
+ return ret;
+}
+
+#ifndef TARGET_SPARC64
+void helper_rett(void)
+{
+ unsigned int cwp;
+
+ if (env->psret == 1) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ }
+
+ env->psret = 1;
+ cwp = cwp_inc(env->cwp + 1) ;
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_UNF);
+ }
+ set_cwp(cwp);
+ env->psrs = env->psrps;
+}
+
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+ handling ? */
+void helper_save(void)
+{
+ uint32_t cwp;
+
+ cwp = cwp_dec(env->cwp - 1);
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_OVF);
+ }
+ set_cwp(cwp);
+}
+
+void helper_restore(void)
+{
+ uint32_t cwp;
+
+ cwp = cwp_inc(env->cwp + 1);
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_UNF);
+ }
+ set_cwp(cwp);
+}
+
+void helper_wrpsr(target_ulong new_psr)
+{
+ if ((new_psr & PSR_CWP) >= env->nwindows) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ } else {
+ cpu_put_psr(env, new_psr);
+ }
+}
+
+target_ulong helper_rdpsr(void)
+{
+ return get_psr();
+}
+
+#else
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+ handling ? */
+void helper_save(void)
+{
+ uint32_t cwp;
+
+ cwp = cwp_dec(env->cwp - 1);
+ if (env->cansave == 0) {
+ helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ } else {
+ if (env->cleanwin - env->canrestore == 0) {
+ /* XXX Clean windows without trap */
+ helper_raise_exception(env, TT_CLRWIN);
+ } else {
+ env->cansave--;
+ env->canrestore++;
+ set_cwp(cwp);
+ }
+ }
+}
+
+void helper_restore(void)
+{
+ uint32_t cwp;
+
+ cwp = cwp_inc(env->cwp + 1);
+ if (env->canrestore == 0) {
+ helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ } else {
+ env->cansave++;
+ env->canrestore--;
+ set_cwp(cwp);
+ }
+}
+
+void helper_flushw(void)
+{
+ if (env->cansave != env->nwindows - 2) {
+ helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ }
+}
+
+void helper_saved(void)
+{
+ env->cansave++;
+ if (env->otherwin == 0) {
+ env->canrestore--;
+ } else {
+ env->otherwin--;
+ }
+}
+
+void helper_restored(void)
+{
+ env->canrestore++;
+ if (env->cleanwin < env->nwindows - 1) {
+ env->cleanwin++;
+ }
+ if (env->otherwin == 0) {
+ env->cansave--;
+ } else {
+ env->otherwin--;
+ }
+}
+
+static target_ulong get_ccr(void)
+{
+ target_ulong psr;
+
+ psr = get_psr();
+
+ return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+target_ulong cpu_get_ccr(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_ccr();
+ env = saved_env;
+ return ret;
+}
+
+static void put_ccr(target_ulong val)
+{
+ env->xcc = (val >> 4) << 20;
+ env->psr = (val & 0xf) << 20;
+ CC_OP = CC_OP_FLAGS;
+}
+
+void cpu_put_ccr(CPUState *env1, target_ulong val)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_ccr(val);
+ env = saved_env;
+}
+
+static target_ulong get_cwp64(void)
+{
+ return env->nwindows - 1 - env->cwp;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env1)
+{
+ CPUState *saved_env;
+ target_ulong ret;
+
+ saved_env = env;
+ env = env1;
+ ret = get_cwp64();
+ env = saved_env;
+ return ret;
+}
+
+static void put_cwp64(int cwp)
+{
+ if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+ cwp %= env->nwindows;
+ }
+ set_cwp(env->nwindows - 1 - cwp);
+}
+
+void cpu_put_cwp64(CPUState *env1, int cwp)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ put_cwp64(cwp);
+ env = saved_env;
+}
+
+target_ulong helper_rdccr(void)
+{
+ return get_ccr();
+}
+
+void helper_wrccr(target_ulong new_ccr)
+{
+ put_ccr(new_ccr);
+}
+
+/* CWP handling is reversed in V9, but we still use the V8 register
+ order. */
+target_ulong helper_rdcwp(void)
+{
+ return get_cwp64();
+}
+
+void helper_wrcwp(target_ulong new_cwp)
+{
+ put_cwp64(new_cwp);
+}
+
+static inline uint64_t *get_gregset(uint32_t pstate)
+{
+ switch (pstate) {
+ default:
+ DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
+ pstate,
+ (pstate & PS_IG) ? " IG" : "",
+ (pstate & PS_MG) ? " MG" : "",
+ (pstate & PS_AG) ? " AG" : "");
+ /* pass through to normal set of global registers */
+ case 0:
+ return env->bgregs;
+ case PS_AG:
+ return env->agregs;
+ case PS_MG:
+ return env->mgregs;
+ case PS_IG:
+ return env->igregs;
+ }
+}
+
+static inline void change_pstate(uint32_t new_pstate)
+{
+ uint32_t pstate_regs, new_pstate_regs;
+ uint64_t *src, *dst;
+
+ if (env->def->features & CPU_FEATURE_GL) {
+ /* PS_AG is not implemented in this case */
+ new_pstate &= ~PS_AG;
+ }
+
+ pstate_regs = env->pstate & 0xc01;
+ new_pstate_regs = new_pstate & 0xc01;
+
+ if (new_pstate_regs != pstate_regs) {
+ DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
+ pstate_regs, new_pstate_regs);
+ /* Switch global register bank */
+ src = get_gregset(new_pstate_regs);
+ dst = get_gregset(pstate_regs);
+ memcpy32(dst, env->gregs);
+ memcpy32(env->gregs, src);
+ } else {
+ DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
+ new_pstate_regs);
+ }
+ env->pstate = new_pstate;
+}
+
+void helper_wrpstate(target_ulong new_state)
+{
+ change_pstate(new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ change_pstate(new_pstate);
+ env = saved_env;
+}
+
+void helper_wrpil(target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+ DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
+ env->psrpil, (uint32_t)new_pil);
+
+ env->psrpil = new_pil;
+
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void helper_done(void)
+{
+ trap_state *tsptr = cpu_tsptr(env);
+
+ env->pc = tsptr->tnpc;
+ env->npc = tsptr->tnpc + 4;
+ put_ccr(tsptr->tstate >> 32);
+ env->asi = (tsptr->tstate >> 24) & 0xff;
+ change_pstate((tsptr->tstate >> 8) & 0xf3f);
+ put_cwp64(tsptr->tstate & 0xff);
+ env->tl--;
+
+ DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void helper_retry(void)
+{
+ trap_state *tsptr = cpu_tsptr(env);
+
+ env->pc = tsptr->tpc;
+ env->npc = tsptr->tnpc;
+ put_ccr(tsptr->tstate >> 32);
+ env->asi = (tsptr->tstate >> 24) & 0xff;
+ change_pstate((tsptr->tstate >> 8) & 0xf3f);
+ put_cwp64(tsptr->tstate & 0xff);
+ env->tl--;
+
+ DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+#endif
diff --git a/vl.c b/vl.c
index 66f70fb6ae..1ddb17bfd9 100644
--- a/vl.c
+++ b/vl.c
@@ -148,6 +148,7 @@ int main(int argc, char **argv)
#include "qemu-objects.h"
#include "qemu-options.h"
#include "qmp-commands.h"
+#include "main-loop.h"
#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
@@ -1425,142 +1426,51 @@ void qemu_system_vmstop_request(RunState state)
qemu_notify_event();
}
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-static int n_poll_fds;
-static int max_priority;
+qemu_irq qemu_system_powerdown;
-static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, struct timeval *tv)
+static bool main_loop_should_exit(void)
{
- GMainContext *context = g_main_context_default();
- int i;
- int timeout = 0, cur_timeout;
-
- g_main_context_prepare(context, &max_priority);
-
- n_poll_fds = g_main_context_query(context, max_priority, &timeout,
- poll_fds, ARRAY_SIZE(poll_fds));
- g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN)) {
- FD_SET(p->fd, rfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_OUT)) {
- FD_SET(p->fd, wfds);
- *max_fd = MAX(*max_fd, p->fd);
- }
- if ((p->events & G_IO_ERR)) {
- FD_SET(p->fd, xfds);
- *max_fd = MAX(*max_fd, p->fd);
+ RunState r;
+ if (qemu_debug_requested()) {
+ vm_stop(RUN_STATE_DEBUG);
+ }
+ if (qemu_shutdown_requested()) {
+ qemu_kill_report();
+ monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
+ if (no_shutdown) {
+ vm_stop(RUN_STATE_SHUTDOWN);
+ } else {
+ return true;
}
}
-
- cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
- if (timeout >= 0 && timeout < cur_timeout) {
- tv->tv_sec = timeout / 1000;
- tv->tv_usec = (timeout % 1000) * 1000;
- }
-}
-
-static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
- bool err)
-{
- GMainContext *context = g_main_context_default();
-
- if (!err) {
- int i;
-
- for (i = 0; i < n_poll_fds; i++) {
- GPollFD *p = &poll_fds[i];
-
- if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
- p->revents |= G_IO_IN;
- }
- if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
- p->revents |= G_IO_OUT;
- }
- if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
- p->revents |= G_IO_ERR;
- }
+ if (qemu_reset_requested()) {
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ qemu_system_reset(VMRESET_REPORT);
+ resume_all_vcpus();
+ if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+ runstate_check(RUN_STATE_SHUTDOWN)) {
+ runstate_set(RUN_STATE_PAUSED);
}
}
-
- if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
- g_main_context_dispatch(context);
- }
-}
-
-int main_loop_wait(int nonblocking)
-{
- fd_set rfds, wfds, xfds;
- int ret, nfds;
- struct timeval tv;
- int timeout;
-
- if (nonblocking)
- timeout = 0;
- else {
- timeout = qemu_calculate_timeout();
- qemu_bh_update_timeout(&timeout);
- }
-
- os_host_main_loop_wait(&timeout);
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
- /* poll any events */
- /* XXX: separate device handlers from system ones */
- nfds = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
-
- qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
- glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
-
- if (timeout > 0) {
- qemu_mutex_unlock_iothread();
+ if (qemu_powerdown_requested()) {
+ monitor_protocol_event(QEVENT_POWERDOWN, NULL);
+ qemu_irq_raise(qemu_system_powerdown);
}
-
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-
- if (timeout > 0) {
- qemu_mutex_lock_iothread();
+ if (qemu_vmstop_requested(&r)) {
+ vm_stop(r);
}
-
- qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
- slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
- glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
-
- qemu_run_all_timers();
-
- /* Check bottom-halves last in case any of the earlier events triggered
- them. */
- qemu_bh_poll();
-
- return ret;
+ return false;
}
-qemu_irq qemu_system_powerdown;
-
static void main_loop(void)
{
bool nonblocking;
- int last_io __attribute__ ((unused)) = 0;
+ int last_io = 0;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
- RunState r;
-
- qemu_main_loop_start();
-
- for (;;) {
+ do {
nonblocking = !kvm_enabled() && last_io > 0;
#ifdef CONFIG_PROFILER
ti = profile_getclock();
@@ -1569,38 +1479,7 @@ static void main_loop(void)
#ifdef CONFIG_PROFILER
dev_time += profile_getclock() - ti;
#endif
-
- if (qemu_debug_requested()) {
- vm_stop(RUN_STATE_DEBUG);
- }
- if (qemu_shutdown_requested()) {
- qemu_kill_report();
- monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
- if (no_shutdown) {
- vm_stop(RUN_STATE_SHUTDOWN);
- } else
- break;
- }
- if (qemu_reset_requested()) {
- pause_all_vcpus();
- cpu_synchronize_all_states();
- qemu_system_reset(VMRESET_REPORT);
- resume_all_vcpus();
- if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
- runstate_check(RUN_STATE_SHUTDOWN)) {
- runstate_set(RUN_STATE_PAUSED);
- }
- }
- if (qemu_powerdown_requested()) {
- monitor_protocol_event(QEVENT_POWERDOWN, NULL);
- qemu_irq_raise(qemu_system_powerdown);
- }
- if (qemu_vmstop_requested(&r)) {
- vm_stop(r);
- }
- }
- bdrv_close_all();
- pause_all_vcpus();
+ } while (!main_loop_should_exit());
}
static void version(void)
@@ -2311,6 +2190,7 @@ int main(int argc, char **argv, char **envp)
runstate_init();
init_clocks();
+ rtc_clock = host_clock;
qemu_cache_utils_init(envp);
@@ -3298,6 +3178,7 @@ int main(int argc, char **argv, char **envp)
configure_accelerator();
+ qemu_init_cpu_loop();
if (qemu_init_main_loop()) {
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
@@ -3564,8 +3445,10 @@ int main(int argc, char **argv, char **envp)
os_setup_post();
+ resume_all_vcpus();
main_loop();
- quit_timers();
+ bdrv_close_all();
+ pause_all_vcpus();
net_cleanup();
res_free();