diff options
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. @@ -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 @@ -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 */ @@ -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 @@ -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) { @@ -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 @@ -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 @@ -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(); |