aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2008-07-10 12:22:20 +0300
committerAvi Kivity <avi@qumranet.com>2008-07-10 12:22:20 +0300
commit9c2e8d239627662b3e0f2e7c5ea7ba2877101426 (patch)
tree9c4b887eef0450f2647cd981e492440b0a284cd8
parentf0be35452b5710f14c0710244d050d1ba6778764 (diff)
parentadf7d8fb44a47e3b4d7cdbf1f1c229b853ad97ed (diff)
Merge branch 'qemu-cvs'kvm-71rc2
Conflicts: qemu/block-raw-posix.c qemu/configure qemu/exec.c qemu/hw/pc.c qemu/sysemu.h qemu/vl.c Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--Makefile20
-rw-r--r--Makefile.target3
-rw-r--r--arm-semi.c1
-rw-r--r--audio/alsaaudio.c18
-rw-r--r--audio/audio.c22
-rw-r--r--audio/audio_int.h1
-rw-r--r--audio/ossaudio.c2
-rw-r--r--audio/paaudio.c515
-rw-r--r--block-nbd.c194
-rw-r--r--block-raw-posix.c22
-rw-r--r--block-vvfat.c14
-rw-r--r--block.c1
-rw-r--r--block.h1
-rwxr-xr-xconfigure226
-rw-r--r--console.c35
-rw-r--r--console.h1
-rw-r--r--cpu-all.h4
-rw-r--r--cpu-defs.h39
-rw-r--r--cpu-exec.c103
-rw-r--r--exec-all.h37
-rw-r--r--exec.c183
-rw-r--r--gdbstub.c20
-rw-r--r--gen-icount.h56
-rw-r--r--hw/ads7846.c5
-rw-r--r--hw/arm_gic.c74
-rw-r--r--hw/arm_timer.c49
-rw-r--r--hw/armv7m_nvic.c26
-rw-r--r--hw/blizzard.c9
-rw-r--r--hw/cirrus_vga.c4
-rw-r--r--hw/dma.c2
-rw-r--r--hw/esp.c1
-rw-r--r--hw/etraxfs.c1
-rw-r--r--hw/etraxfs_dma.c66
-rw-r--r--hw/etraxfs_eth.c13
-rw-r--r--hw/etraxfs_ser.c9
-rw-r--r--hw/etraxfs_timer.c16
-rw-r--r--hw/g364fb.c17
-rw-r--r--hw/gus.c26
-rw-r--r--hw/i2c.c49
-rw-r--r--hw/i2c.h3
-rw-r--r--hw/ide.c187
-rw-r--r--hw/iommu.c4
-rw-r--r--hw/jazz_led.c11
-rw-r--r--hw/lm832x.c5
-rw-r--r--hw/max111x.c5
-rw-r--r--hw/max7310.c5
-rw-r--r--hw/mips_jazz.c1
-rw-r--r--hw/mips_malta.c1
-rw-r--r--hw/mips_mipssim.c5
-rw-r--r--hw/mips_r4k.c3
-rw-r--r--hw/mips_timer.c5
-rw-r--r--hw/musicpal.c15
-rw-r--r--hw/nand.c4
-rw-r--r--hw/nseries.c4
-rw-r--r--hw/omap_lcdc.c10
-rw-r--r--hw/palm.c3
-rw-r--r--hw/pc.c1
-rw-r--r--hw/pl011.c53
-rw-r--r--hw/pl022.c51
-rw-r--r--hw/pl061.c58
-rw-r--r--hw/pl110.c11
-rw-r--r--hw/ppc4xx_devs.c1
-rw-r--r--hw/ppc_chrp.c1
-rw-r--r--hw/ppc_oldworld.c1
-rw-r--r--hw/ppc_prep.c1
-rw-r--r--hw/pxa2xx.c14
-rw-r--r--hw/pxa2xx_lcd.c10
-rw-r--r--hw/scsi-disk.c71
-rw-r--r--hw/slavio_serial.c7
-rw-r--r--hw/ssd0303.c146
-rw-r--r--hw/ssd0323.c173
-rw-r--r--hw/ssi-sd.c38
-rw-r--r--hw/stellaris.c243
-rw-r--r--hw/stellaris_enet.c63
-rw-r--r--hw/stellaris_input.c27
-rw-r--r--hw/sun4m.c3
-rw-r--r--hw/sun4u.c1
-rw-r--r--hw/tcx.c18
-rw-r--r--hw/tmp105.c5
-rw-r--r--hw/tsc2005.c5
-rw-r--r--hw/tsc210x.c7
-rw-r--r--hw/twl92230.c5
-rw-r--r--hw/vga.c20
-rw-r--r--hw/vga_int.h1
-rw-r--r--hw/vmware_vga.c10
-rw-r--r--hw/wm8750.c4
-rw-r--r--keymaps/ja1
-rw-r--r--linux-user/main.c26
-rw-r--r--linux-user/mips/target_signal.h2
-rw-r--r--linux-user/mips64/target_signal.h2
-rw-r--r--linux-user/mipsn32/target_signal.h2
-rw-r--r--linux-user/signal.c34
-rw-r--r--linux-user/syscall.c2
-rw-r--r--monitor.c2
-rw-r--r--nbd.c290
-rw-r--r--nbd.h34
-rw-r--r--osdep.c6
-rw-r--r--qemu-common.h5
-rw-r--r--qemu-doc.texi56
-rw-r--r--qemu-nbd.c270
-rw-r--r--qemu-nbd.texi14
-rw-r--r--softmmu_header.h12
-rw-r--r--softmmu_template.h22
-rw-r--r--sysemu.h6
-rw-r--r--target-alpha/cpu.h4
-rw-r--r--target-alpha/translate.c33
-rw-r--r--target-arm/cpu.h8
-rw-r--r--target-arm/helper.c2
-rw-r--r--target-arm/machine.c2
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-arm/translate.c50
-rw-r--r--target-cris/cpu.h7
-rw-r--r--target-cris/mmu.c6
-rw-r--r--target-cris/op_helper.c6
-rw-r--r--target-cris/translate.c34
-rw-r--r--target-i386/cpu.h6
-rw-r--r--target-i386/helper.c6
-rw-r--r--target-i386/machine.c7
-rw-r--r--target-i386/translate.c81
-rw-r--r--target-m68k/cpu.h6
-rw-r--r--target-m68k/op_helper.c2
-rw-r--r--target-m68k/translate.c27
-rw-r--r--target-mips/cpu.h93
-rw-r--r--target-mips/exec.h23
-rw-r--r--target-mips/helper.c30
-rw-r--r--target-mips/helper.h128
-rw-r--r--target-mips/machine.c4
-rw-r--r--target-mips/op_helper.c1292
-rw-r--r--target-mips/translate.c2065
-rw-r--r--target-mips/translate_init.c2
-rw-r--r--target-ppc/cpu.h7
-rw-r--r--target-ppc/helper.c1
-rw-r--r--target-ppc/translate.c32
-rw-r--r--target-sh4/cpu.h7
-rw-r--r--target-sh4/translate.c31
-rw-r--r--target-sparc/cpu.h9
-rw-r--r--target-sparc/helper.c2
-rw-r--r--target-sparc/op_helper.c20
-rw-r--r--target-sparc/translate.c20
-rw-r--r--tcg/i386/tcg-target.c8
-rw-r--r--tcg/ppc/tcg-target.c13
-rw-r--r--tcg/sparc/tcg-target.c10
-rw-r--r--tcg/tcg.h3
-rw-r--r--translate-all.c9
-rw-r--r--vl.c281
-rw-r--r--vnc_keysym.h7
146 files changed, 6077 insertions, 2300 deletions
diff --git a/Makefile b/Makefile
index 024ddfc71..8ca17f760 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ VPATH=$(SRC_PATH):$(SRC_PATH)/hw
CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS)
-CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP
+CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS=
ifdef CONFIG_STATIC
@@ -42,7 +42,7 @@ recurse-all: $(SUBDIR_RULES)
BLOCK_OBJS=cutils.o qemu-malloc.o
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
-BLOCK_OBJS+=block-qcow2.o block-parallels.o
+BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
######################################################################
# libqemu_common.a: Target independent part of system emulation. The
@@ -50,7 +50,7 @@ BLOCK_OBJS+=block-qcow2.o block-parallels.o
# system emulation, i.e. a single QEMU executable should support all
# CPUs and machines.
-OBJS=$(BLOCK_OBJS)
+OBJS=nbd.o $(BLOCK_OBJS)
OBJS+=readline.o console.o
OBJS+=block.o
@@ -98,6 +98,11 @@ AUDIO_PT = yes
AUDIO_PT_INT = yes
AUDIO_OBJS += esdaudio.o
endif
+ifdef CONFIG_PA
+AUDIO_PT = yes
+AUDIO_PT_INT = yes
+AUDIO_OBJS += paaudio.o
+endif
ifdef AUDIO_PT
LDFLAGS += -pthread
endif
@@ -154,7 +159,7 @@ libqemu_user.a: $(USER_OBJS)
rm -f $@
$(AR) rcs $@ $(USER_OBJS)
-QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS)
+QEMU_IMG_BLOCK_OBJS = nbd.o $(BLOCK_OBJS)
ifdef CONFIG_WIN32
QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o
else
@@ -172,8 +177,11 @@ qemu-img-%.o: %.c
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
-qemu-nbd$(EXESUF): qemu-nbd.o nbd.o qemu-img-block.o \
- $(QEMU_IMG_BLOCK_OBJS)
+qemu-nbd-%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_NBD -c -o $@ $<
+
+qemu-nbd$(EXESUF): qemu-nbd.o qemu-nbd-nbd.o qemu-img-block.o \
+ osdep.o qemu-nbd-block-raw-posix.o $(BLOCK_OBJS)
$(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
# dyngen host tool
diff --git a/Makefile.target b/Makefile.target
index 77b230119..7a51cd00f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -535,6 +535,9 @@ endif
ifdef CONFIG_ESD
LIBS += -lesd
endif
+ifdef CONFIG_PA
+LIBS += -lpulse-simple
+endif
ifdef CONFIG_DSOUND
LIBS += -lole32 -ldxguid
endif
diff --git a/arm-semi.c b/arm-semi.c
index 1cf220388..cd77d1da0 100644
--- a/arm-semi.c
+++ b/arm-semi.c
@@ -362,6 +362,7 @@ uint32_t do_arm_semihosting(CPUState *env)
return (uint32_t)-1;
ret = set_swi_errno(ts, system(s));
unlock_user(s, ARG(0), 0);
+ return ret;
}
case SYS_ERRNO:
#ifdef CONFIG_USER_ONLY
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index c926cae38..a79cc403c 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -58,6 +58,7 @@ static struct {
int period_size_out_overridden;
int verbose;
} conf = {
+ .buffer_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
@@ -67,6 +68,7 @@ struct alsa_params_req {
snd_pcm_format_t fmt;
int nchannels;
int size_in_usec;
+ int override_mask;
unsigned int buffer_size;
unsigned int period_size;
};
@@ -364,7 +366,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if (obt - req->buffer_size)
+ if ((req->override_mask & 2) && (obt - req->buffer_size))
dolog ("Requested buffer %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->buffer_size, obt);
}
@@ -385,12 +387,14 @@ static int alsa_open (int in, struct alsa_params_req *req,
obt = ptime;
}
else {
+ int dir = 0;
snd_pcm_uframes_t psize = req->period_size;
- err = snd_pcm_hw_params_set_buffer_size_near (
+ err = snd_pcm_hw_params_set_period_size_near (
handle,
hw_params,
- &psize
+ &psize,
+ &dir
);
obt = psize;
}
@@ -401,7 +405,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if (obt - req->period_size)
+ if ((req->override_mask & 1) && (obt - req->period_size))
dolog ("Requested period %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->period_size, obt);
}
@@ -621,7 +625,9 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
req.nchannels = as->nchannels;
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
- req.size_in_usec = conf.size_in_usec_in;
+ req.size_in_usec = conf.size_in_usec_out;
+ req.override_mask = !!conf.period_size_out_overridden
+ | (!!conf.buffer_size_out_overridden << 1);
if (alsa_open (0, &req, &obt, &handle)) {
return -1;
@@ -700,6 +706,8 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
req.size_in_usec = conf.size_in_usec_in;
+ req.override_mask = !!conf.period_size_in_overridden
+ | (!!conf.buffer_size_in_overridden << 1);
if (alsa_open (1, &req, &obt, &handle)) {
return -1;
diff --git a/audio/audio.c b/audio/audio.c
index 46b39df76..84eaa8359 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -38,27 +38,7 @@
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
static struct audio_driver *drvtab[] = {
-#ifdef CONFIG_OSS
- &oss_audio_driver,
-#endif
-#ifdef CONFIG_ALSA
- &alsa_audio_driver,
-#endif
-#ifdef CONFIG_COREAUDIO
- &coreaudio_audio_driver,
-#endif
-#ifdef CONFIG_DSOUND
- &dsound_audio_driver,
-#endif
-#ifdef CONFIG_FMOD
- &fmod_audio_driver,
-#endif
-#ifdef CONFIG_SDL
- &sdl_audio_driver,
-#endif
-#ifdef CONFIG_ESD
- &esd_audio_driver,
-#endif
+ AUDIO_DRIVERS
&no_audio_driver,
&wav_audio_driver
};
diff --git a/audio/audio_int.h b/audio/audio_int.h
index f96960201..d4cefb34a 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -203,6 +203,7 @@ extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
+extern struct audio_driver pa_audio_driver;
extern volume_t nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index a29b4bc17..613e189db 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -237,7 +237,7 @@ static int oss_open (int in, struct oss_params *req,
goto err;
}
- if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
+ if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
goto err;
}
diff --git a/audio/paaudio.c b/audio/paaudio.c
new file mode 100644
index 000000000..b5d390c2d
--- /dev/null
+++ b/audio/paaudio.c
@@ -0,0 +1,515 @@
+/* public domain */
+#include "qemu-common.h"
+#include "audio.h"
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+#define AUDIO_CAP "pulseaudio"
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+typedef struct {
+ HWVoiceOut hw;
+ int done;
+ int live;
+ int decr;
+ int rpos;
+ pa_simple *s;
+ void *pcm_buf;
+ struct audio_pt pt;
+} PAVoiceOut;
+
+typedef struct {
+ HWVoiceIn hw;
+ int done;
+ int dead;
+ int incr;
+ int wpos;
+ pa_simple *s;
+ void *pcm_buf;
+ struct audio_pt pt;
+} PAVoiceIn;
+
+static struct {
+ int samples;
+ int divisor;
+ char *server;
+ char *sink;
+ char *source;
+} conf = {
+ 1024,
+ 2,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ AUD_vlog (AUDIO_CAP, fmt, ap);
+ va_end (ap);
+
+ AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
+}
+
+static void *qpa_thread_out (void *arg)
+{
+ PAVoiceOut *pa = arg;
+ HWVoiceOut *hw = &pa->hw;
+ int threshold;
+
+ threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ for (;;) {
+ int decr, to_mix, rpos;
+
+ for (;;) {
+ if (pa->done) {
+ goto exit;
+ }
+
+ if (pa->live > threshold) {
+ break;
+ }
+
+ if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
+ goto exit;
+ }
+ }
+
+ decr = to_mix = pa->live;
+ rpos = hw->rpos;
+
+ if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ while (to_mix) {
+ int error;
+ int chunk = audio_MIN (to_mix, hw->samples - rpos);
+ st_sample_t *src = hw->mix_buf + rpos;
+
+ hw->clip (pa->pcm_buf, src, chunk);
+
+ if (pa_simple_write (pa->s, pa->pcm_buf,
+ chunk << hw->info.shift, &error) < 0) {
+ qpa_logerr (error, "pa_simple_write failed\n");
+ return NULL;
+ }
+
+ rpos = (rpos + chunk) % hw->samples;
+ to_mix -= chunk;
+ }
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ pa->rpos = rpos;
+ pa->live -= decr;
+ pa->decr += decr;
+ }
+
+ exit:
+ audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+static int qpa_run_out (HWVoiceOut *hw)
+{
+ int live, decr;
+ PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return 0;
+ }
+
+ live = audio_pcm_hw_get_live_out (hw);
+ decr = audio_MIN (live, pa->decr);
+ pa->decr -= decr;
+ pa->live = live - decr;
+ hw->rpos = pa->rpos;
+ if (pa->live > 0) {
+ audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+ }
+ else {
+ audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+ }
+ return decr;
+}
+
+static int qpa_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+/* capture */
+static void *qpa_thread_in (void *arg)
+{
+ PAVoiceIn *pa = arg;
+ HWVoiceIn *hw = &pa->hw;
+ int threshold;
+
+ threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ for (;;) {
+ int incr, to_grab, wpos;
+
+ for (;;) {
+ if (pa->done) {
+ goto exit;
+ }
+
+ if (pa->dead > threshold) {
+ break;
+ }
+
+ if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
+ goto exit;
+ }
+ }
+
+ incr = to_grab = pa->dead;
+ wpos = hw->wpos;
+
+ if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ while (to_grab) {
+ int error;
+ int chunk = audio_MIN (to_grab, hw->samples - wpos);
+ void *buf = advance (pa->pcm_buf, wpos);
+
+ if (pa_simple_read (pa->s, buf,
+ chunk << hw->info.shift, &error) < 0) {
+ qpa_logerr (error, "pa_simple_read failed\n");
+ return NULL;
+ }
+
+ hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
+ wpos = (wpos + chunk) % hw->samples;
+ to_grab -= chunk;
+ }
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ pa->wpos = wpos;
+ pa->dead -= incr;
+ pa->incr += incr;
+ }
+
+ exit:
+ audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+static int qpa_run_in (HWVoiceIn *hw)
+{
+ int live, incr, dead;
+ PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+ if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
+ return 0;
+ }
+
+ live = audio_pcm_hw_get_live_in (hw);
+ dead = hw->samples - live;
+ incr = audio_MIN (dead, pa->incr);
+ pa->incr -= incr;
+ pa->dead = dead - incr;
+ hw->wpos = pa->wpos;
+ if (pa->dead > 0) {
+ audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+ }
+ else {
+ audio_pt_unlock (&pa->pt, AUDIO_FUNC);
+ }
+ return incr;
+}
+
+static int qpa_read (SWVoiceIn *sw, void *buf, int len)
+{
+ return audio_pcm_sw_read (sw, buf, len);
+}
+
+static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
+{
+ int format;
+
+ switch (afmt) {
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
+ format = PA_SAMPLE_U8;
+ break;
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
+ format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
+ break;
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
+ break;
+ default:
+ dolog ("Internal logic error: Bad audio format %d\n", afmt);
+ format = PA_SAMPLE_U8;
+ break;
+ }
+ return format;
+}
+
+static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
+{
+ switch (fmt) {
+ case PA_SAMPLE_U8:
+ return AUD_FMT_U8;
+ case PA_SAMPLE_S16BE:
+ *endianness = 1;
+ return AUD_FMT_S16;
+ case PA_SAMPLE_S16LE:
+ *endianness = 0;
+ return AUD_FMT_S16;
+ case PA_SAMPLE_S32BE:
+ *endianness = 1;
+ return AUD_FMT_S32;
+ case PA_SAMPLE_S32LE:
+ *endianness = 0;
+ return AUD_FMT_S32;
+ default:
+ dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
+ return AUD_FMT_U8;
+ }
+}
+
+static int qpa_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+ int error;
+ static pa_sample_spec ss;
+ audsettings_t obt_as = *as;
+ PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+ ss.format = audfmt_to_pa (as->fmt, as->endianness);
+ ss.channels = as->nchannels;
+ ss.rate = as->freq;
+
+ obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
+
+ pa->s = pa_simple_new (
+ conf.server,
+ "qemu",
+ PA_STREAM_PLAYBACK,
+ conf.sink,
+ "pcm.playback",
+ &ss,
+ NULL, /* channel map */
+ NULL, /* buffering attributes */
+ &error
+ );
+ if (!pa->s) {
+ qpa_logerr (error, "pa_simple_new for playback failed\n");
+ goto fail1;
+ }
+
+ audio_pcm_init_info (&hw->info, &obt_as);
+ hw->samples = conf.samples;
+ pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!pa->pcm_buf) {
+ dolog ("Could not allocate buffer (%d bytes)\n",
+ hw->samples << hw->info.shift);
+ goto fail2;
+ }
+
+ if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail3;
+ }
+
+ return 0;
+
+ fail3:
+ free (pa->pcm_buf);
+ pa->pcm_buf = NULL;
+ fail2:
+ pa_simple_free (pa->s);
+ pa->s = NULL;
+ fail1:
+ return -1;
+}
+
+static int qpa_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+ int error;
+ static pa_sample_spec ss;
+ audsettings_t obt_as = *as;
+ PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+ ss.format = audfmt_to_pa (as->fmt, as->endianness);
+ ss.channels = as->nchannels;
+ ss.rate = as->freq;
+
+ obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
+
+ pa->s = pa_simple_new (
+ conf.server,
+ "qemu",
+ PA_STREAM_RECORD,
+ conf.source,
+ "pcm.capture",
+ &ss,
+ NULL, /* channel map */
+ NULL, /* buffering attributes */
+ &error
+ );
+ if (!pa->s) {
+ qpa_logerr (error, "pa_simple_new for capture failed\n");
+ goto fail1;
+ }
+
+ audio_pcm_init_info (&hw->info, &obt_as);
+ hw->samples = conf.samples;
+ pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!pa->pcm_buf) {
+ dolog ("Could not allocate buffer (%d bytes)\n",
+ hw->samples << hw->info.shift);
+ goto fail2;
+ }
+
+ if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail3;
+ }
+
+ return 0;
+
+ fail3:
+ free (pa->pcm_buf);
+ pa->pcm_buf = NULL;
+ fail2:
+ pa_simple_free (pa->s);
+ pa->s = NULL;
+ fail1:
+ return -1;
+}
+
+static void qpa_fini_out (HWVoiceOut *hw)
+{
+ void *ret;
+ PAVoiceOut *pa = (PAVoiceOut *) hw;
+
+ audio_pt_lock (&pa->pt, AUDIO_FUNC);
+ pa->done = 1;
+ audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+ audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
+
+ if (pa->s) {
+ pa_simple_free (pa->s);
+ pa->s = NULL;
+ }
+
+ audio_pt_fini (&pa->pt, AUDIO_FUNC);
+ qemu_free (pa->pcm_buf);
+ pa->pcm_buf = NULL;
+}
+
+static void qpa_fini_in (HWVoiceIn *hw)
+{
+ void *ret;
+ PAVoiceIn *pa = (PAVoiceIn *) hw;
+
+ audio_pt_lock (&pa->pt, AUDIO_FUNC);
+ pa->done = 1;
+ audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
+ audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
+
+ if (pa->s) {
+ pa_simple_free (pa->s);
+ pa->s = NULL;
+ }
+
+ audio_pt_fini (&pa->pt, AUDIO_FUNC);
+ qemu_free (pa->pcm_buf);
+ pa->pcm_buf = NULL;
+}
+
+static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+ (void) hw;
+ (void) cmd;
+ return 0;
+}
+
+static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+ (void) hw;
+ (void) cmd;
+ return 0;
+}
+
+/* common */
+static void *qpa_audio_init (void)
+{
+ return &conf;
+}
+
+static void qpa_audio_fini (void *opaque)
+{
+ (void) opaque;
+}
+
+struct audio_option qpa_options[] = {
+ {"SAMPLES", AUD_OPT_INT, &conf.samples,
+ "buffer size in samples", NULL, 0},
+
+ {"DIVISOR", AUD_OPT_INT, &conf.divisor,
+ "threshold divisor", NULL, 0},
+
+ {"SERVER", AUD_OPT_STR, &conf.server,
+ "server address", NULL, 0},
+
+ {"SINK", AUD_OPT_STR, &conf.sink,
+ "sink device name", NULL, 0},
+
+ {"SOURCE", AUD_OPT_STR, &conf.source,
+ "source device name", NULL, 0},
+
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+struct audio_pcm_ops qpa_pcm_ops = {
+ qpa_init_out,
+ qpa_fini_out,
+ qpa_run_out,
+ qpa_write,
+ qpa_ctl_out,
+ qpa_init_in,
+ qpa_fini_in,
+ qpa_run_in,
+ qpa_read,
+ qpa_ctl_in
+};
+
+struct audio_driver pa_audio_driver = {
+ INIT_FIELD (name = ) "pa",
+ INIT_FIELD (descr = ) "http://www.pulseaudio.org/",
+ INIT_FIELD (options = ) qpa_options,
+ INIT_FIELD (init = ) qpa_audio_init,
+ INIT_FIELD (fini = ) qpa_audio_fini,
+ INIT_FIELD (pcm_ops = ) &qpa_pcm_ops,
+ INIT_FIELD (can_be_default = ) 0,
+ INIT_FIELD (max_voices_out = ) INT_MAX,
+ INIT_FIELD (max_voices_in = ) INT_MAX,
+ INIT_FIELD (voice_size_out = ) sizeof (PAVoiceOut),
+ INIT_FIELD (voice_size_in = ) sizeof (PAVoiceIn)
+};
diff --git a/block-nbd.c b/block-nbd.c
new file mode 100644
index 000000000..88b61999f
--- /dev/null
+++ b/block-nbd.c
@@ -0,0 +1,194 @@
+/*
+ * QEMU Block driver for NBD
+ *
+ * Copyright (C) 2008 Bull S.A.S.
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * Some parts:
+ * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
+ *
+ * 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 "nbd.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+
+typedef struct BDRVNBDState {
+ int sock;
+ off_t size;
+ size_t blocksize;
+} BDRVNBDState;
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+ BDRVNBDState *s = bs->opaque;
+ const char *host;
+ const char *unixpath;
+ int sock;
+ off_t size;
+ size_t blocksize;
+ int ret;
+
+ if ((flags & BDRV_O_CREAT))
+ return -EINVAL;
+
+ if (!strstart(filename, "nbd:", &host))
+ return -EINVAL;
+
+ if (strstart(host, "unix:", &unixpath)) {
+
+ if (unixpath[0] != '/')
+ return -EINVAL;
+
+ sock = unix_socket_outgoing(unixpath);
+
+ } else {
+ uint16_t port;
+ char *p, *r;
+ char hostname[128];
+
+ pstrcpy(hostname, 128, host);
+
+ p = strchr(hostname, ':');
+ if (p == NULL)
+ return -EINVAL;
+
+ *p = '\0';
+ p++;
+
+ port = strtol(p, &r, 0);
+ if (r == p)
+ return -EINVAL;
+ sock = tcp_socket_outgoing(hostname, port);
+ }
+
+ if (sock == -1)
+ return -errno;
+
+ ret = nbd_receive_negotiate(sock, &size, &blocksize);
+ if (ret == -1)
+ return -errno;
+
+ s->sock = sock;
+ s->size = size;
+ s->blocksize = blocksize;
+
+ return 0;
+}
+
+static int nbd_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ BDRVNBDState *s = bs->opaque;
+ struct nbd_request request;
+ struct nbd_reply reply;
+
+ request.type = NBD_CMD_READ;
+ request.handle = (uint64_t)(intptr_t)bs;
+ request.from = sector_num * 512;;
+ request.len = nb_sectors * 512;
+
+ if (nbd_send_request(s->sock, &request) == -1)
+ return -errno;
+
+ if (nbd_receive_reply(s->sock, &reply) == -1)
+ return -errno;
+
+ if (reply.error !=0)
+ return -reply.error;
+
+ if (reply.handle != request.handle)
+ return -EIO;
+
+ if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
+ return -EIO;
+
+ return 0;
+}
+
+static int nbd_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BDRVNBDState *s = bs->opaque;
+ struct nbd_request request;
+ struct nbd_reply reply;
+
+ request.type = NBD_CMD_WRITE;
+ request.handle = (uint64_t)(intptr_t)bs;
+ request.from = sector_num * 512;;
+ request.len = nb_sectors * 512;
+
+ if (nbd_send_request(s->sock, &request) == -1)
+ return -errno;
+
+ if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
+ return -EIO;
+
+ if (nbd_receive_reply(s->sock, &reply) == -1)
+ return -errno;
+
+ if (reply.error !=0)
+ return -reply.error;
+
+ if (reply.handle != request.handle)
+ return -EIO;
+
+ return 0;
+}
+
+static void nbd_close(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+ struct nbd_request request;
+
+ request.type = NBD_CMD_DISC;
+ request.handle = (uint64_t)(intptr_t)bs;
+ request.from = 0;
+ request.len = 0;
+ nbd_send_request(s->sock, &request);
+
+ close(s->sock);
+}
+
+static int64_t nbd_getlength(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+
+ return s->size;
+}
+
+BlockDriver bdrv_nbd = {
+ "nbd",
+ sizeof(BDRVNBDState),
+ NULL, /* no probe for protocols */
+ nbd_open,
+ nbd_read,
+ nbd_write,
+ nbd_close,
+ .bdrv_getlength = nbd_getlength,
+ .protocol_name = "nbd",
+};
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 7fd85bccb..47fd21ebf 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -22,10 +22,16 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
#include "qemu-kvm.h"
#include "qemu-timer.h"
#include "exec-all.h"
+#else
+#define kvm_enabled() 0
+#define qemu_kvm_aio_start() ((void)0)
+#define qemu_kvm_aio_end() ((void)0)
+#define qemu_kvm_aio_wait() ((void)0)
+#define qemu_kvm_aio_poll() ((void)0)
#endif
#include "block_int.h"
#include <assert.h>
@@ -60,7 +66,7 @@
//#define DEBUG_FLOPPY
//#define DEBUG_BLOCK
-#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG)
+#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
{ fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
#else
@@ -435,7 +441,7 @@ static int aio_initialized = 0;
static void aio_signal_handler(int signum)
{
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
CPUState *env = cpu_single_env;
if (env) {
/* stop the currently executing cpu because a timer occured */
@@ -551,7 +557,7 @@ void qemu_aio_wait(void)
sigset_t set;
int nb_sigs;
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
if (qemu_bh_poll())
return;
if (kvm_enabled()) {
@@ -604,7 +610,7 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
return acb;
}
-#ifndef QEMU_IMG
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
static void raw_aio_em_cb(void* opaque)
{
RawAIOCB *acb = opaque;
@@ -623,7 +629,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
* If O_DIRECT is used and the buffer is not aligned fall back
* to synchronous IO.
*/
-#if defined(O_DIRECT) && !defined(QEMU_IMG)
+#if defined(O_DIRECT) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
BDRVRawState *s = bs->opaque;
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
@@ -656,7 +662,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
* If O_DIRECT is used and the buffer is not aligned fall back
* to synchronous IO.
*/
-#if defined(O_DIRECT) && !defined(QEMU_IMG)
+#if defined(O_DIRECT) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
BDRVRawState *s = bs->opaque;
if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
@@ -959,7 +965,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
return 0;
}
-#if defined(__linux__) && !defined(QEMU_IMG)
+#if defined(__linux__) && !defined(QEMU_IMG) && !defined(QEMU_NBD)
/* Note: we do not have a reliable method to detect if the floppy is
present. The current method is to try to open the floppy at every
diff --git a/block-vvfat.c b/block-vvfat.c
index a93fde970..9394fbd69 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -93,7 +93,6 @@ static inline void array_free(array_t* array)
/* does not automatically grow */
static inline void* array_get(array_t* array,unsigned int index) {
- assert(index >= 0);
assert(index < array->next);
return array->pointer + index * array->item_size;
}
@@ -195,7 +194,6 @@ static int array_remove(array_t* array,int index)
static int array_index(array_t* array, void* pointer)
{
size_t offset = (char*)pointer - array->pointer;
- assert(offset >= 0);
assert((offset % array->item_size) == 0);
assert(offset/array->item_size < array->next);
return offset/array->item_size;
@@ -454,8 +452,7 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
static char is_free(const direntry_t* direntry)
{
- /* return direntry->name[0]==0 ; */
- return direntry->attributes == 0 || direntry->name[0]==0xe5;
+ return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
}
static char is_volume_label(const direntry_t* direntry)
@@ -1411,7 +1408,12 @@ static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
}
typedef struct {
- unsigned char name[1024];
+ /*
+ * Since the sequence number is at most 0x3f, and the filename
+ * length is at most 13 times the sequence number, the maximal
+ * filename length is 0x3f * 13 bytes.
+ */
+ unsigned char name[0x3f * 13 + 1];
int checksum, len;
int sequence_number;
} long_file_name;
@@ -1436,6 +1438,7 @@ static int parse_long_name(long_file_name* lfn,
lfn->sequence_number = pointer[0] & 0x3f;
lfn->checksum = pointer[13];
lfn->name[0] = 0;
+ lfn->name[lfn->sequence_number * 13] = 0;
} else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
return -1;
else if (pointer[13] != lfn->checksum)
@@ -2233,7 +2236,6 @@ static int commit_one_file(BDRVVVFATState* s,
assert((size - offset == 0 && fat_eof(s, c)) ||
(size > offset && c >=2 && !fat_eof(s, c)));
- assert(size >= 0);
ret = vvfat_read(s->bs, cluster2sector(s, c),
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
diff --git a/block.c b/block.c
index b438f1db1..f4f9c97fe 100644
--- a/block.c
+++ b/block.c
@@ -1472,6 +1472,7 @@ void bdrv_init(void)
bdrv_register(&bdrv_vvfat);
bdrv_register(&bdrv_qcow2);
bdrv_register(&bdrv_parallels);
+ bdrv_register(&bdrv_nbd);
}
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
diff --git a/block.h b/block.h
index 79f91e2c6..81587efc1 100644
--- a/block.h
+++ b/block.h
@@ -16,6 +16,7 @@ extern BlockDriver bdrv_vpc;
extern BlockDriver bdrv_vvfat;
extern BlockDriver bdrv_qcow2;
extern BlockDriver bdrv_parallels;
+extern BlockDriver bdrv_nbd;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
diff --git a/configure b/configure
index d047a6445..60e849391 100755
--- a/configure
+++ b/configure
@@ -24,6 +24,8 @@ cross_prefix=""
cc="gcc"
gcc3_search="yes"
gcc3_list="gcc-3.4.6 gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32"
+audio_drv_list=""
+audio_card_list=""
host_cc="gcc"
ar="ar"
make="make"
@@ -87,16 +89,6 @@ mingw32="no"
EXESUF=""
gdbstub="yes"
slirp="yes"
-adlib="no"
-ac97="no"
-gus="no"
-cs4231a="no"
-oss="no"
-dsound="no"
-coreaudio="no"
-alsa="no"
-esd="no"
-fmod="no"
fmod_lib=""
fmod_inc=""
vnc_tls="yes"
@@ -130,22 +122,26 @@ OS_CFLAGS="-mno-cygwin"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
+audio_possible_drivers="sdl"
;;
MINGW32*)
mingw32="yes"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
+audio_possible_drivers="dsound sdl fmod"
;;
GNU/kFreeBSD)
-oss="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss sdl esd"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
;;
FreeBSD)
bsd="yes"
-oss="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss sdl esd"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
kvm="yes"
@@ -153,18 +149,21 @@ fi
;;
NetBSD)
bsd="yes"
-oss="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss sdl esd"
;;
OpenBSD)
bsd="yes"
-oss="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss sdl esd"
;;
Darwin)
bsd="yes"
darwin="yes"
darwin_user="yes"
cocoa="yes"
-coreaudio="yes"
+audio_drv_list="coreaudio"
+audio_possible_drivers="coreaudio sdl fmod"
OS_CFLAGS="-mdynamic-no-pic"
OS_LDFLAGS="-framework CoreFoundation -framework IOKit"
;;
@@ -197,15 +196,18 @@ SunOS)
fi
fi
if test -f /usr/include/sys/soundcard.h ; then
- oss=yes
+ audio_drv_list="oss"
fi
+ audio_possible_drivers="oss sdl"
;;
*)
-oss="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss alsa sdl esd pa"
linux="yes"
linux_user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
+ audio_possible_drivers="$audio_possible_drivers fmod"
kvm="yes"
fi
if [ "$cpu" = "ia64" ] ; then
@@ -280,34 +282,20 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
- --enable-coreaudio) coreaudio="yes"
- ;;
- --enable-alsa) alsa="yes"
- ;;
- --enable-esd) esd="yes"
- ;;
- --enable-dsound) dsound="yes"
- ;;
- --enable-fmod) fmod="yes"
- ;;
--fmod-lib=*) fmod_lib="$optarg"
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
+ --audio-card-list=*) audio_card_list="$optarg"
+ ;;
+ --audio-drv-list=*) audio_drv_list="$optarg"
+ ;;
--disable-vnc-tls) vnc_tls="no"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no"
;;
--disable-slirp) slirp="no"
;;
- --enable-adlib) adlib="yes"
- ;;
- --enable-ac97) ac97="yes"
- ;;
- --enable-gus) gus="yes"
- ;;
- --enable-cs4231a) cs4231a="yes"
- ;;
--disable-kqemu) kqemu="no"
;;
--disable-kvm) kvm="no"
@@ -318,7 +306,10 @@ for opt do
;;
--kernel-path=*) kernel_path="$optarg"
;;
- --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
+ --enable-cocoa)
+ cocoa="yes" ;
+ sdl="no" ;
+ audio_drv_list="coreaudio `echo $audio_drv_list | sed s,coreaudio,,g`"
;;
--disable-gfx-check) check_gfx="no"
;;
@@ -448,15 +439,10 @@ echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-cocoa enable COCOA (Mac OS X only)"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
-echo " --enable-adlib enable Adlib emulation"
-echo " --enable-ac97 enable AC97 emulation"
-echo " --enable-gus enable Gravis Ultrasound emulation"
-echo " --enable-cs4231a enable CS4231A emulation"
-echo " --enable-coreaudio enable Coreaudio audio driver"
-echo " --enable-alsa enable ALSA audio driver"
-echo " --enable-esd enable EsoundD audio driver"
-echo " --enable-fmod enable FMOD audio driver"
-echo " --enable-dsound enable DirectSound audio driver"
+echo " --audio-drv-list=LIST set audio drivers list:"
+echo " Available drivers: $audio_possible_drivers"
+echo " --audio-card-list=LIST set list of additional emulated audio cards"
+echo " Available cards: ac97 adlib cs4231a gus"
echo " --enable-mixemu enable mixer emulation"
echo " --disable-brlapi disable BrlAPI"
echo " --disable-vnc-tls disable TLS encryption for VNC server"
@@ -765,7 +751,7 @@ else
# Make sure to disable cocoa if sdl was set
if test "$sdl" = "yes" ; then
cocoa="no"
- coreaudio="no"
+ audio_drv_list="`echo $audio_drv_list | sed s,coreaudio,,g`"
fi
fi # -z $sdl
@@ -780,23 +766,59 @@ if test "$vnc_tls" = "yes" ; then
fi
##########################################
-# alsa sound support libraries
+# Sound support libraries probe
-if test "$alsa" = "yes" ; then
- cat > $TMPC << EOF
-#include <alsa/asoundlib.h>
-int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
+audio_drv_probe()
+{
+ drv=$1
+ hdr=$2
+ lib=$3
+ exp=$4
+ cfl=$5
+ cat > $TMPC << EOF
+#include <$hdr>
+int main(void) { $exp }
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lasound 2> /dev/null ; then
- :
- else
- echo
- echo "Error: Could not find alsa"
- echo "Make sure to have the alsa libs and headers installed."
- echo
- exit 1
- fi
-fi
+ if $cc $ARCH_CFLAGS $cfl -o $TMPE $TMPC $lib 2> /dev/null ; then
+ :
+ else
+ echo
+ echo "Error: $drv check failed"
+ echo "Make sure to have the $drv libs and headers installed."
+ echo
+ exit 1
+ fi
+}
+
+for drv in $audio_drv_list; do
+ case $drv in
+ alsa)
+ audio_drv_probe $drv alsa/asoundlib.h -lasound \
+ "snd_pcm_t **handle; return snd_pcm_close(*handle);"
+ ;;
+
+ fmod)
+ if test -z $fmod_lib || test -z $fmod_inc; then
+ echo
+ echo "Error: You must specify path to FMOD library and headers"
+ echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
+ echo
+ exit 1
+ fi
+ audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc"
+ ;;
+
+ esd)
+ audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);'
+ ;;
+
+ pa)
+ audio_drv_probe $drv pulse/simple.h -lpulse-simple \
+ "pa_simple *s = NULL; pa_simple_free(s); return 0;"
+ ;;
+
+ esac
+done
##########################################
# BrlAPI probe
@@ -904,29 +926,9 @@ if test "$sdl" != "no" ; then
fi
echo "curses support $curses"
echo "mingw32 support $mingw32"
-echo "Adlib support $adlib"
-echo "AC97 support $ac97"
-echo "GUS support $gus"
-echo "CS4231A support $cs4231a"
-echo "CoreAudio support $coreaudio"
-echo "ALSA support $alsa"
-echo "EsounD support $esd"
-echo "DSound support $dsound"
+echo "Audio drivers $audio_drv_list"
+echo "Extra audio cards $audio_card_list"
echo "Mixer emulation $mixemu"
-if test "$fmod" = "yes"; then
- if test -z $fmod_lib || test -z $fmod_inc; then
- echo
- echo "Error: You must specify path to FMOD library and headers"
- echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
- echo
- exit 1
- fi
- fmod_support=" (lib='$fmod_lib' include='$fmod_inc')"
-else
- fmod_support=""
-fi
-echo "FMOD support $fmod $fmod_support"
-echo "OSS support $oss"
echo "VNC TLS support $vnc_tls"
if test "$vnc_tls" = "yes" ; then
echo " TLS CFLAGS $vnc_tls_cflags"
@@ -1110,52 +1112,26 @@ if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=yes" >> $config_mak
echo "#define CONFIG_SLIRP 1" >> $config_h
fi
-if test "$adlib" = "yes" ; then
- echo "CONFIG_ADLIB=yes" >> $config_mak
- echo "#define CONFIG_ADLIB 1" >> $config_h
-fi
-if test "$ac97" = "yes" ; then
- echo "CONFIG_AC97=yes" >> $config_mak
- echo "#define CONFIG_AC97 1" >> $config_h
-fi
-if test "$gus" = "yes" ; then
- echo "CONFIG_GUS=yes" >> $config_mak
- echo "#define CONFIG_GUS 1" >> $config_h
-fi
-if test "$cs4231a" = "yes" ; then
- echo "CONFIG_CS4231A=yes" >> $config_mak
- echo "#define CONFIG_CS4231A 1" >> $config_h
-fi
-if test "$oss" = "yes" ; then
- echo "CONFIG_OSS=yes" >> $config_mak
- echo "#define CONFIG_OSS 1" >> $config_h
-fi
-if test "$coreaudio" = "yes" ; then
- echo "CONFIG_COREAUDIO=yes" >> $config_mak
- echo "#define CONFIG_COREAUDIO 1" >> $config_h
-fi
-if test "$alsa" = "yes" ; then
- echo "CONFIG_ALSA=yes" >> $config_mak
- echo "#define CONFIG_ALSA 1" >> $config_h
-fi
-if test "$esd" = "yes" ; then
- echo "CONFIG_ESD=yes" >> $config_mak
- echo "#define CONFIG_ESD 1" >> $config_h
-fi
-if test "$dsound" = "yes" ; then
- echo "CONFIG_DSOUND=yes" >> $config_mak
- echo "#define CONFIG_DSOUND 1" >> $config_h
-fi
+for card in $audio_card_list; do
+ def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
+ echo "$def=yes" >> $config_mak
+ echo "#define $def 1" >> $config_h
+done
+echo "#define AUDIO_DRIVERS \\" >> $config_h
+for drv in $audio_drv_list; do
+ echo " &${drv}_audio_driver, \\" >>$config_h
+ def=CONFIG_`echo $drv | tr '[:lower:]' '[:upper:]'`
+ echo "$def=yes" >> $config_mak
+ if test "$drv" = "fmod"; then
+ echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
+ echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
+ fi
+done
+echo "" >>$config_h
if test "$mixemu" = "yes" ; then
echo "CONFIG_MIXEMU=yes" >> $config_mak
echo "#define CONFIG_MIXEMU 1" >> $config_h
fi
-if test "$fmod" = "yes" ; then
- echo "CONFIG_FMOD=yes" >> $config_mak
- echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
- echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
- echo "#define CONFIG_FMOD 1" >> $config_h
-fi
if test "$vnc_tls" = "yes" ; then
echo "CONFIG_VNC_TLS=yes" >> $config_mak
echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak
diff --git a/console.c b/console.c
index 880ac831a..a1bc769c8 100644
--- a/console.c
+++ b/console.c
@@ -28,6 +28,7 @@
//#define DEBUG_CONSOLE
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
+#define DEFAULT_MONITOR_SIZE "800x600"
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
@@ -108,8 +109,7 @@ static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
typedef enum {
GRAPHIC_CONSOLE,
- TEXT_CONSOLE,
- TEXT_CONSOLE_FIXED_SIZE
+ TEXT_CONSOLE
} console_type_t;
/* ??? This is mis-named.
@@ -1041,6 +1041,9 @@ void console_select(unsigned int index)
s = consoles[index];
if (s) {
active_console = s;
+ if (s->g_width && s->g_height
+ && (s->g_width != s->ds->width || s->g_height != s->ds->height))
+ dpy_resize(s->ds, s->g_width, s->g_height);
vga_hw_invalidate();
}
}
@@ -1149,18 +1152,6 @@ static void text_console_invalidate(void *opaque)
{
TextConsole *s = (TextConsole *) opaque;
- if (s->console_type != GRAPHIC_CONSOLE) {
- if (s->g_width != s->ds->width ||
- s->g_height != s->ds->height) {
- if (s->console_type == TEXT_CONSOLE_FIXED_SIZE)
- dpy_resize(s->ds, s->g_width, s->g_height);
- else {
- s->g_width = s->ds->width;
- s->g_height = s->ds->height;
- text_console_resize(s);
- }
- }
- }
console_refresh(s);
}
@@ -1268,11 +1259,14 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p)
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
- s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
+ s = new_console(ds, TEXT_CONSOLE);
if (!s) {
free(chr);
return NULL;
}
+ if (!p)
+ p = DEFAULT_MONITOR_SIZE;
+
chr->opaque = s;
chr->chr_write = console_puts;
chr->chr_send_event = console_send_event;
@@ -1332,3 +1326,14 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p)
return chr;
}
+
+void qemu_console_resize(QEMUConsole *console, int width, int height)
+{
+ if (console->g_width != width || console->g_height != height) {
+ console->g_width = width;
+ console->g_height = height;
+ if (active_console == console) {
+ dpy_resize(console->ds, width, height);
+ }
+ }
+}
diff --git a/console.h b/console.h
index f3caae884..9e5f530c5 100644
--- a/console.h
+++ b/console.h
@@ -135,6 +135,7 @@ int is_graphic_console(void);
CharDriverState *text_console_init(DisplayState *ds, const char *p);
void console_select(unsigned int index);
void console_color_init(DisplayState *ds);
+void qemu_console_resize(QEMUConsole *console, int width, int height);
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
diff --git a/cpu-all.h b/cpu-all.h
index b0c113f7a..0afd6614e 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -667,7 +667,7 @@ static inline void stfq_be_p(void *ptr, float64 v)
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
-#define h2g(x) ((target_ulong)(x - GUEST_BASE))
+#define h2g(x) ((target_ulong)((unsigned long)(x) - GUEST_BASE))
#define saddr(x) g2h(x)
#define laddr(x) g2h(x)
@@ -782,6 +782,8 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
__attribute__ ((__noreturn__));
extern CPUState *first_cpu;
extern CPUState *cpu_single_env;
+extern int64_t qemu_icount;
+extern int use_icount;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
diff --git a/cpu-defs.h b/cpu-defs.h
index 169568cd8..0c16fc9ea 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -130,18 +130,31 @@ typedef struct CPUTLBEntry {
sizeof(target_phys_addr_t))];
} CPUTLBEntry;
+#ifdef WORDS_BIGENDIAN
+typedef struct icount_decr_u16 {
+ uint16_t high;
+ uint16_t low;
+} icount_decr_u16;
+#else
+typedef struct icount_decr_u16 {
+ uint16_t low;
+ uint16_t high;
+} icount_decr_u16;
+#endif
+
#define CPU_TEMP_BUF_NLONGS 128
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
/* soft mmu support */ \
- /* in order to avoid passing too many arguments to the memory \
- write helpers, we store some rarely used information in the CPU \
+ /* in order to avoid passing too many arguments to the MMIO \
+ helpers, we store some rarely used information in the CPU \
context) */ \
- unsigned long mem_write_pc; /* host pc at which the memory was \
- written */ \
- target_ulong mem_write_vaddr; /* target virtual addr at which the \
- memory was written */ \
- int halted; /* TRUE if the CPU is in suspend state */ \
+ unsigned long mem_io_pc; /* host pc at which the memory was \
+ accessed */ \
+ target_ulong mem_io_vaddr; /* target virtual addr at which the \
+ memory was accessed */ \
+ uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
+ uint32_t interrupt_request; \
/* The meaning of the MMU modes is defined in the target code. */ \
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \
@@ -149,6 +162,16 @@ typedef struct CPUTLBEntry {
/* buffer for temporaries in the code generator */ \
long temp_buf[CPU_TEMP_BUF_NLONGS]; \
\
+ int64_t icount_extra; /* Instructions until next timer event. */ \
+ /* Number of cycles left, with interrupt flag in high bit. \
+ This allows a single read-compare-cbranch-write sequence to test \
+ for both decrementer underflow and exceptions. */ \
+ union { \
+ uint32_t u32; \
+ icount_decr_u16 u16; \
+ } icount_decr; \
+ uint32_t can_do_io; /* nonzero if memory mapped IO is safe. */ \
+ \
/* from this point: preserved by CPU reset */ \
/* ice debug support */ \
target_ulong breakpoints[MAX_BREAKPOINTS]; \
@@ -166,6 +189,8 @@ typedef struct CPUTLBEntry {
jmp_buf jmp_env; \
int exception_index; \
\
+ int user_mode_only; \
+ \
void *next_cpu; /* next CPU sharing TB cache */ \
int cpu_index; /* CPU index (informative) */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
diff --git a/cpu-exec.c b/cpu-exec.c
index 7af8bba46..68feb8bfc 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -86,15 +86,40 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
longjmp(env->jmp_env, 1);
}
+/* Execute the code without caching the generated code. An interpreter
+ could be used if available. */
+static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
+{
+ unsigned long next_tb;
+ TranslationBlock *tb;
+
+ /* Should never happen.
+ We only end up here when an existing TB is too long. */
+ if (max_cycles > CF_COUNT_MASK)
+ max_cycles = CF_COUNT_MASK;
+
+ tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
+ max_cycles);
+ env->current_tb = tb;
+ /* execute the generated code */
+ next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
+
+ if ((next_tb & 3) == 2) {
+ /* Restore PC. This may happen if async event occurs before
+ the TB starts executing. */
+ CPU_PC_FROM_TB(env, tb);
+ }
+ tb_phys_invalidate(tb, -1);
+ tb_free(tb);
+}
+
static TranslationBlock *tb_find_slow(target_ulong pc,
target_ulong cs_base,
uint64_t flags)
{
TranslationBlock *tb, **ptb1;
- int code_gen_size;
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
- uint8_t *tc_ptr;
tb_invalidated_flag = 0;
@@ -128,30 +153,8 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
ptb1 = &tb->phys_hash_next;
}
not_found:
- /* if no translated code available, then translate it now */
- tb = tb_alloc(pc);
- if (!tb) {
- /* flush must be done */
- tb_flush(env);
- /* cannot fail at this point */
- tb = tb_alloc(pc);
- /* don't forget to invalidate previous TB info */
- tb_invalidated_flag = 1;
- }
- tc_ptr = code_gen_ptr;
- tb->tc_ptr = tc_ptr;
- tb->cs_base = cs_base;
- tb->flags = flags;
- cpu_gen_code(env, tb, &code_gen_size);
- code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-
- /* check next page if needed */
- virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
- phys_page2 = -1;
- if ((pc & TARGET_PAGE_MASK) != virt_page2) {
- phys_page2 = get_phys_addr_code(env, virt_page2);
- }
- tb_link_phys(tb, phys_pc, phys_page2);
+ /* if no translated code available, then translate it now */
+ tb = tb_gen_code(env, pc, cs_base, flags, 0);
found:
/* we add the TB in the virtual pc hash table */
@@ -201,7 +204,7 @@ static inline TranslationBlock *tb_find_fast(void)
#elif defined(TARGET_MIPS)
flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
cs_base = 0;
- pc = env->PC[env->current_tc];
+ pc = env->active_tc.PC;
#elif defined(TARGET_M68K)
flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
| (env->sr & SR_S) /* Bit 13 */
@@ -229,8 +232,8 @@ static inline TranslationBlock *tb_find_fast(void)
#error unsupported CPU
#endif
tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
- if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
- tb->flags != flags, 0)) {
+ if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
+ tb->flags != flags)) {
tb = tb_find_slow(pc, cs_base, flags);
}
return tb;
@@ -372,7 +375,7 @@ int cpu_exec(CPUState *env1)
next_tb = 0; /* force lookup of first TB */
for(;;) {
interrupt_request = env->interrupt_request;
- if (__builtin_expect(interrupt_request, 0) &&
+ if (unlikely(interrupt_request) &&
likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
@@ -598,6 +601,7 @@ int cpu_exec(CPUState *env1)
of memory exceptions while generating the code, we
must recompute the hash index here */
next_tb = 0;
+ tb_invalidated_flag = 0;
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) {
@@ -619,16 +623,45 @@ int cpu_exec(CPUState *env1)
}
}
spin_unlock(&tb_lock);
- tc_ptr = tb->tc_ptr;
env->current_tb = tb;
+ while (env->current_tb) {
+ tc_ptr = tb->tc_ptr;
/* execute the generated code */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
- env = cpu_single_env;
+ env = cpu_single_env;
#define env cpu_single_env
#endif
- next_tb = tcg_qemu_tb_exec(tc_ptr);
- env->current_tb = NULL;
+ next_tb = tcg_qemu_tb_exec(tc_ptr);
+ env->current_tb = NULL;
+ if ((next_tb & 3) == 2) {
+ /* Instruction counter expired. */
+ int insns_left;
+ tb = (TranslationBlock *)(long)(next_tb & ~3);
+ /* Restore PC. */
+ CPU_PC_FROM_TB(env, tb);
+ insns_left = env->icount_decr.u32;
+ if (env->icount_extra && insns_left >= 0) {
+ /* Refill decrementer and continue execution. */
+ env->icount_extra += insns_left;
+ if (env->icount_extra > 0xffff) {
+ insns_left = 0xffff;
+ } else {
+ insns_left = env->icount_extra;
+ }
+ env->icount_extra -= insns_left;
+ env->icount_decr.u16.low = insns_left;
+ } else {
+ if (insns_left > 0) {
+ /* Execute remaining instructions. */
+ cpu_exec_nocache(insns_left, tb);
+ }
+ env->exception_index = EXCP_INTERRUPT;
+ next_tb = 0;
+ cpu_loop_exit();
+ }
+ }
+ }
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
#if defined(USE_KQEMU)
@@ -1342,7 +1375,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
unsigned long pc;
int is_write;
-#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ =< 3))
+#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
pc = uc->uc_mcontext.gregs[R15];
#else
pc = uc->uc_mcontext.arm_pc;
diff --git a/exec-all.h b/exec-all.h
index 62a939487..943297755 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -27,7 +27,7 @@
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
-struct TranslationBlock;
+typedef struct TranslationBlock TranslationBlock;
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 64
@@ -48,6 +48,7 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
+extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
extern target_ulong gen_opc_jump_pc[2];
extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
@@ -75,6 +76,10 @@ int cpu_restore_state_copy(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
void cpu_resume_from_signal(CPUState *env1, void *puc);
+void cpu_io_recompile(CPUState *env, void *retaddr);
+TranslationBlock *tb_gen_code(CPUState *env,
+ target_ulong pc, target_ulong cs_base, int flags,
+ int cflags);
void cpu_exec_init(CPUState *env);
int page_unprotect(target_ulong address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
@@ -117,16 +122,15 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
#define USE_DIRECT_JUMP
#endif
-typedef struct TranslationBlock {
+struct TranslationBlock {
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
target_ulong cs_base; /* CS base for this block */
uint64_t flags; /* flags defining in which context the code was generated */
uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */
uint16_t cflags; /* compile flags */
-#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */
-#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */
-#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
+#define CF_COUNT_MASK 0x7fff
+#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */
uint8_t *tc_ptr; /* pointer to the translated code */
/* next matching tb for physical address. */
@@ -150,7 +154,8 @@ typedef struct TranslationBlock {
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
-} TranslationBlock;
+ uint32_t icount;
+};
static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
{
@@ -173,9 +178,11 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
}
TranslationBlock *tb_alloc(target_ulong pc);
+void tb_free(TranslationBlock *tb);
void tb_flush(CPUState *env);
void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2);
+void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr);
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
extern uint8_t *code_gen_ptr;
@@ -350,8 +357,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = cpu_mmu_index(env1);
- if (__builtin_expect(env1->tlb_table[mmu_idx][page_index].addr_code !=
- (addr & TARGET_PAGE_MASK), 0)) {
+ if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
+ (addr & TARGET_PAGE_MASK))) {
ldub_code(addr);
}
pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
@@ -364,6 +371,20 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
}
return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
}
+
+/* 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 USE_KQEMU
diff --git a/exec.c b/exec.c
index 867be048a..c15ce94fb 100644
--- a/exec.c
+++ b/exec.c
@@ -42,6 +42,7 @@
#endif
#include "qemu-kvm.h"
+#include "hw/hw.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
#endif
@@ -114,6 +115,13 @@ CPUState *first_cpu;
/* current CPU in the current thread. It is only valid inside
cpu_exec() */
CPUState *cpu_single_env;
+/* 0 = Do not count executed instructions.
+ 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 */
@@ -443,6 +451,33 @@ void cpu_exec_init_all(unsigned long tb_size)
#endif
}
+#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
+
+#define CPU_COMMON_SAVE_VERSION 1
+
+static void cpu_common_save(QEMUFile *f, void *opaque)
+{
+ CPUState *env = opaque;
+
+ qemu_put_be32s(f, &env->halted);
+ qemu_put_be32s(f, &env->interrupt_request);
+}
+
+static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
+{
+ CPUState *env = opaque;
+
+ if (version_id != CPU_COMMON_SAVE_VERSION)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &env->halted);
+ qemu_get_be32s(f, &env->interrupt_request);
+ tlb_flush(env, 1);
+
+ return 0;
+}
+#endif
+
void cpu_exec_init(CPUState *env)
{
CPUState **penv;
@@ -463,6 +498,12 @@ void cpu_exec_init(CPUState *env)
env->thread_id = getpid();
#endif
*penv = env;
+#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
+ register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
+ cpu_common_save, cpu_common_load, env);
+ register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
+ cpu_save, cpu_load, env);
+#endif
}
static inline void invalidate_page_bitmap(PageDesc *p)
@@ -646,7 +687,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n)
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
}
-static inline void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
+void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
{
CPUState *env;
PageDesc *p;
@@ -759,11 +800,9 @@ static void build_page_bitmap(PageDesc *p)
}
}
-#ifdef TARGET_HAS_PRECISE_SMC
-
-static void tb_gen_code(CPUState *env,
- target_ulong pc, target_ulong cs_base, int flags,
- int cflags)
+TranslationBlock *tb_gen_code(CPUState *env,
+ target_ulong pc, target_ulong cs_base,
+ int flags, int cflags)
{
TranslationBlock *tb;
uint8_t *tc_ptr;
@@ -777,6 +816,8 @@ static void tb_gen_code(CPUState *env,
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc(pc);
+ /* Don't forget to invalidate previous TB info. */
+ tb_invalidated_flag = 1;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
@@ -793,8 +834,8 @@ static void tb_gen_code(CPUState *env,
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
+ return tb;
}
-#endif
/* invalidate all TBs which intersect with the target physical page
starting in range [start;end[. NOTE: start and end must refer to
@@ -849,13 +890,13 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
if (current_tb_not_found) {
current_tb_not_found = 0;
current_tb = NULL;
- if (env->mem_write_pc) {
+ if (env->mem_io_pc) {
/* now we have a real cpu fault */
- current_tb = tb_find_pc(env->mem_write_pc);
+ current_tb = tb_find_pc(env->mem_io_pc);
}
}
if (current_tb == tb &&
- !(current_tb->cflags & CF_SINGLE_INSN)) {
+ (current_tb->cflags & CF_COUNT_MASK) != 1) {
/* If we are modifying the current TB, we must stop
its execution. We could be more precise by checking
that the modification is after the current PC, but it
@@ -864,7 +905,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
current_tb_modified = 1;
cpu_restore_state(current_tb, env,
- env->mem_write_pc, NULL);
+ env->mem_io_pc, NULL);
#if defined(TARGET_I386)
current_flags = env->hflags;
current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
@@ -896,7 +937,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
if (!p->first_tb) {
invalidate_page_bitmap(p);
if (is_cpu_write_access) {
- tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
+ tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
}
}
#endif
@@ -906,8 +947,7 @@ void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t
modifying the memory. It will ensure that it cannot modify
itself */
env->current_tb = NULL;
- tb_gen_code(env, current_pc, current_cs_base, current_flags,
- CF_SINGLE_INSN);
+ tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
cpu_resume_from_signal(env, NULL);
}
#endif
@@ -922,7 +962,7 @@ static inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int le
if (1) {
if (loglevel) {
fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
- cpu_single_env->mem_write_vaddr, len,
+ cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip,
cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
}
@@ -974,7 +1014,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr,
tb = (TranslationBlock *)((long)tb & ~3);
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb == tb &&
- !(current_tb->cflags & CF_SINGLE_INSN)) {
+ (current_tb->cflags & CF_COUNT_MASK) != 1) {
/* If we are modifying the current TB, we must stop
its execution. We could be more precise by checking
that the modification is after the current PC, but it
@@ -1003,8 +1043,7 @@ static void tb_invalidate_phys_page(target_phys_addr_t addr,
modifying the memory. It will ensure that it cannot modify
itself */
env->current_tb = NULL;
- tb_gen_code(env, current_pc, current_cs_base, current_flags,
- CF_SINGLE_INSN);
+ tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
cpu_resume_from_signal(env, puc);
}
#endif
@@ -1081,6 +1120,17 @@ TranslationBlock *tb_alloc(target_ulong pc)
return tb;
}
+void tb_free(TranslationBlock *tb)
+{
+ /* In practice this is mostly used for single use temporary TB
+ Ignore the hard cases and just back up if this TB happens to
+ be the last one generated. */
+ if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
+ code_gen_ptr = tb->tc_ptr;
+ nb_tbs--;
+ }
+}
+
/* add a new TB and link it to the physical page tables. phys_page2 is
(-1) to indicate that only one page contains the TB. */
void tb_link_phys(TranslationBlock *tb,
@@ -1390,9 +1440,11 @@ void cpu_interrupt(CPUState *env, int mask)
TranslationBlock *tb;
static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
#endif
+ int old_mask;
+ old_mask = env->interrupt_request;
/* FIXME: This is probably not threadsafe. A different thread could
- be in the mittle of a read-modify-write operation. */
+ be in the middle of a read-modify-write operation. */
env->interrupt_request |= mask;
if (kvm_enabled() && !qemu_kvm_irqchip_in_kernel())
kvm_update_interrupt_request(env);
@@ -1402,13 +1454,25 @@ void cpu_interrupt(CPUState *env, int mask)
emulation this often isn't actually as bad as it sounds. Often
signals are used primarily to interrupt blocking syscalls. */
#else
- /* if the cpu is currently executing code, we must unlink it and
- all the potentially executing TB */
- tb = env->current_tb;
- if (tb && !testandset(&interrupt_lock)) {
- env->current_tb = NULL;
- tb_reset_jump_recursive(tb);
- resetlock(&interrupt_lock);
+ if (use_icount) {
+ env->icount_decr.u16.high = 0xffff;
+#ifndef CONFIG_USER_ONLY
+ /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
+ an async event happened and we need to process it. */
+ if (!can_do_io(env)
+ && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
+ cpu_abort(env, "Raised interrupt while not in I/O function");
+ }
+#endif
+ } else {
+ tb = env->current_tb;
+ /* if the cpu is currently executing code, we must unlink it and
+ all the potentially executing TB */
+ if (tb && !testandset(&interrupt_lock)) {
+ env->current_tb = NULL;
+ tb_reset_jump_recursive(tb);
+ resetlock(&interrupt_lock);
+ }
}
#endif
}
@@ -2265,7 +2329,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
}
static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
@@ -2290,7 +2354,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
}
static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
@@ -2315,7 +2379,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
}
static CPUReadMemoryFunc *error_mem_read[3] = {
@@ -2337,7 +2401,7 @@ static void check_watchpoint(int offset, int flags)
target_ulong vaddr;
int i;
- vaddr = (env->mem_write_vaddr & TARGET_PAGE_MASK) + offset;
+ vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
for (i = 0; i < env->nb_watchpoints; i++) {
if (vaddr == env->watchpoint[i].vaddr
&& (env->watchpoint[i].type & flags)) {
@@ -3057,6 +3121,65 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
return 0;
}
+/* in deterministic execution mode, instructions doing device I/Os
+ must be at the end of the TB */
+void cpu_io_recompile(CPUState *env, void *retaddr)
+{
+ TranslationBlock *tb;
+ uint32_t n, cflags;
+ target_ulong pc, cs_base;
+ uint64_t flags;
+
+ tb = tb_find_pc((unsigned long)retaddr);
+ if (!tb) {
+ cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
+ retaddr);
+ }
+ n = env->icount_decr.u16.low + tb->icount;
+ cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
+ /* Calculate how many instructions had been executed before the fault
+ occurred. */
+ n = n - env->icount_decr.u16.low;
+ /* Generate a new TB ending on the I/O insn. */
+ n++;
+ /* On MIPS and SH, delay slot instructions can only be restarted if
+ they were already the first instruction in the TB. If this is not
+ the first instruction in a TB then re-execute the preceding
+ branch. */
+#if defined(TARGET_MIPS)
+ if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
+ env->active_tc.PC -= 4;
+ env->icount_decr.u16.low++;
+ env->hflags &= ~MIPS_HFLAG_BMASK;
+ }
+#elif defined(TARGET_SH4)
+ if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
+ && n > 1) {
+ env->pc -= 2;
+ env->icount_decr.u16.low++;
+ env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
+ }
+#endif
+ /* This should never happen. */
+ if (n > CF_COUNT_MASK)
+ cpu_abort(env, "TB too big during recompile");
+
+ cflags = n | CF_LAST_IO;
+ pc = tb->pc;
+ cs_base = tb->cs_base;
+ flags = tb->flags;
+ tb_phys_invalidate(tb, -1);
+ /* FIXME: In theory this could raise an exception. In practice
+ we have already translated the block once so it's probably ok. */
+ tb_gen_code(env, pc, cs_base, flags, cflags);
+ /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
+ the first in the TB) then we end up generating a whole new TB and
+ repeating the fault, which is horribly inefficient.
+ Better would be to execute just this insn uncached, or generate a
+ second new TB. */
+ cpu_resume_from_signal(env, NULL);
+}
+
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
diff --git a/gdbstub.c b/gdbstub.c
index 86428d1d0..d8288444e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -705,17 +705,17 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
ptr = mem_buf;
for (i = 0; i < 32; i++)
{
- *(target_ulong *)ptr = tswapl(env->gpr[env->current_tc][i]);
+ *(target_ulong *)ptr = tswapl(env->active_tc.gpr[i]);
ptr += sizeof(target_ulong);
}
*(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status);
ptr += sizeof(target_ulong);
- *(target_ulong *)ptr = tswapl(env->LO[env->current_tc][0]);
+ *(target_ulong *)ptr = tswapl(env->active_tc.LO[0]);
ptr += sizeof(target_ulong);
- *(target_ulong *)ptr = tswapl(env->HI[env->current_tc][0]);
+ *(target_ulong *)ptr = tswapl(env->active_tc.HI[0]);
ptr += sizeof(target_ulong);
*(target_ulong *)ptr = tswapl(env->CP0_BadVAddr);
@@ -724,7 +724,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
*(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause);
ptr += sizeof(target_ulong);
- *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]);
+ *(target_ulong *)ptr = tswapl(env->active_tc.PC);
ptr += sizeof(target_ulong);
if (env->CP0_Config1 & (1 << CP0C1_FP))
@@ -782,17 +782,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
ptr = mem_buf;
for (i = 0; i < 32; i++)
{
- env->gpr[env->current_tc][i] = tswapl(*(target_ulong *)ptr);
+ env->active_tc.gpr[i] = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
}
env->CP0_Status = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
- env->LO[env->current_tc][0] = tswapl(*(target_ulong *)ptr);
+ env->active_tc.LO[0] = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
- env->HI[env->current_tc][0] = tswapl(*(target_ulong *)ptr);
+ env->active_tc.HI[0] = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr);
@@ -801,7 +801,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
env->CP0_Cause = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
- env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr);
+ env->active_tc.PC = tswapl(*(target_ulong *)ptr);
ptr += sizeof(target_ulong);
if (env->CP0_Config1 & (1 << CP0C1_FP))
@@ -1006,7 +1006,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
#elif defined (TARGET_SH4)
env->pc = addr;
#elif defined (TARGET_MIPS)
- env->PC[env->current_tc] = addr;
+ env->active_tc.PC = addr;
#elif defined (TARGET_CRIS)
env->pc = addr;
#endif
@@ -1045,7 +1045,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
#elif defined (TARGET_SH4)
env->pc = addr;
#elif defined (TARGET_MIPS)
- env->PC[env->current_tc] = addr;
+ env->active_tc.PC = addr;
#elif defined (TARGET_CRIS)
env->pc = addr;
#endif
diff --git a/gen-icount.h b/gen-icount.h
new file mode 100644
index 000000000..61545f157
--- /dev/null
+++ b/gen-icount.h
@@ -0,0 +1,56 @@
+/* Helpers for instruction counting code generation. */
+
+static TCGArg *icount_arg;
+static int icount_label;
+
+static inline void gen_icount_start(void)
+{
+ TCGv count;
+
+ if (!use_icount)
+ return;
+
+ icount_label = gen_new_label();
+ /* FIXME: This generates lousy code. We can't use tcg_new_temp because
+ count needs to live over the conditional branch. To workaround this
+ we allow the target to supply a convenient register temporary. */
+#ifndef ICOUNT_TEMP
+ count = tcg_temp_local_new(TCG_TYPE_I32);
+#else
+ count = ICOUNT_TEMP;
+#endif
+ tcg_gen_ld_i32(count, cpu_env, offsetof(CPUState, icount_decr.u32));
+ /* This is a horrid hack to allow fixing up the value later. */
+ icount_arg = gen_opparam_ptr + 1;
+ tcg_gen_subi_i32(count, count, 0xdeadbeef);
+
+ tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
+ tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low));
+#ifndef ICOUNT_TEMP
+ tcg_temp_free(count);
+#endif
+}
+
+static void gen_icount_end(TranslationBlock *tb, int num_insns)
+{
+ if (use_icount) {
+ *icount_arg = num_insns;
+ gen_set_label(icount_label);
+ tcg_gen_exit_tb((long)tb + 2);
+ }
+}
+
+static void inline gen_io_start(void)
+{
+ TCGv tmp = tcg_const_i32(1);
+ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
+ tcg_temp_free(tmp);
+}
+
+static inline void gen_io_end(void)
+{
+ TCGv tmp = tcg_const_i32(0);
+ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
+ tcg_temp_free(tmp);
+}
+
diff --git a/hw/ads7846.c b/hw/ads7846.c
index 578bb5493..b39c00f51 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -140,8 +140,6 @@ static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int ads7846_iid = 0;
-
struct ads7846_state_s *ads7846_init(qemu_irq penirq)
{
struct ads7846_state_s *s;
@@ -162,8 +160,7 @@ struct ads7846_state_s *ads7846_init(qemu_irq penirq)
ads7846_int_update(s);
- register_savevm("ads7846", ads7846_iid ++, 0,
- ads7846_save, ads7846_load, s);
+ register_savevm("ads7846", -1, 0, ads7846_save, ads7846_load, s);
return s;
}
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 7f67c5276..54e99f4d6 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -650,6 +650,79 @@ static void gic_reset(gic_state *s)
#endif
}
+static void gic_save(QEMUFile *f, void *opaque)
+{
+ gic_state *s = (gic_state *)opaque;
+ int i;
+ int j;
+
+ qemu_put_be32(f, s->enabled);
+ for (i = 0; i < NCPU; i++) {
+ qemu_put_be32(f, s->cpu_enabled[i]);
+#ifndef NVIC
+ qemu_put_be32(f, s->irq_target[i]);
+#endif
+ for (j = 0; j < 32; j++)
+ qemu_put_be32(f, s->priority1[j][i]);
+ for (j = 0; j < GIC_NIRQ; j++)
+ qemu_put_be32(f, s->last_active[j][i]);
+ qemu_put_be32(f, s->priority_mask[i]);
+ qemu_put_be32(f, s->running_irq[i]);
+ qemu_put_be32(f, s->running_priority[i]);
+ qemu_put_be32(f, s->current_pending[i]);
+ }
+ for (i = 0; i < GIC_NIRQ - 32; i++) {
+ qemu_put_be32(f, s->priority2[i]);
+ }
+ for (i = 0; i < GIC_NIRQ; i++) {
+ qemu_put_byte(f, s->irq_state[i].enabled);
+ qemu_put_byte(f, s->irq_state[i].pending);
+ qemu_put_byte(f, s->irq_state[i].active);
+ qemu_put_byte(f, s->irq_state[i].level);
+ qemu_put_byte(f, s->irq_state[i].model);
+ qemu_put_byte(f, s->irq_state[i].trigger);
+ }
+}
+
+static int gic_load(QEMUFile *f, void *opaque, int version_id)
+{
+ gic_state *s = (gic_state *)opaque;
+ int i;
+ int j;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->enabled = qemu_get_be32(f);
+ for (i = 0; i < NCPU; i++) {
+ s->cpu_enabled[i] = qemu_get_be32(f);
+#ifndef NVIC
+ s->irq_target[i] = qemu_get_be32(f);
+#endif
+ for (j = 0; j < 32; j++)
+ s->priority1[j][i] = qemu_get_be32(f);
+ for (j = 0; j < GIC_NIRQ; j++)
+ s->last_active[j][i] = qemu_get_be32(f);
+ s->priority_mask[i] = qemu_get_be32(f);
+ s->running_irq[i] = qemu_get_be32(f);
+ s->running_priority[i] = qemu_get_be32(f);
+ s->current_pending[i] = qemu_get_be32(f);
+ }
+ for (i = 0; i < GIC_NIRQ - 32; i++) {
+ s->priority2[i] = qemu_get_be32(f);
+ }
+ for (i = 0; i < GIC_NIRQ; i++) {
+ s->irq_state[i].enabled = qemu_get_byte(f);
+ s->irq_state[i].pending = qemu_get_byte(f);
+ s->irq_state[i].active = qemu_get_byte(f);
+ s->irq_state[i].level = qemu_get_byte(f);
+ s->irq_state[i].model = qemu_get_byte(f);
+ s->irq_state[i].trigger = qemu_get_byte(f);
+ }
+
+ return 0;
+}
+
static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq)
{
gic_state *s;
@@ -669,5 +742,6 @@ static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq)
iomemtype);
s->base = base;
gic_reset(s);
+ register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
return s;
}
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 540d3dea1..5150fe9a5 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -143,6 +143,29 @@ static void arm_timer_tick(void *opaque)
arm_timer_update(s);
}
+static void arm_timer_save(QEMUFile *f, void *opaque)
+{
+ arm_timer_state *s = (arm_timer_state *)opaque;
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->limit);
+ qemu_put_be32(f, s->int_level);
+ qemu_put_ptimer(f, s->timer);
+}
+
+static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+ arm_timer_state *s = (arm_timer_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->control = qemu_get_be32(f);
+ s->limit = qemu_get_be32(f);
+ s->int_level = qemu_get_be32(f);
+ qemu_get_ptimer(f, s->timer);
+ return 0;
+}
+
static void *arm_timer_init(uint32_t freq, qemu_irq irq)
{
arm_timer_state *s;
@@ -155,7 +178,7 @@ static void *arm_timer_init(uint32_t freq, qemu_irq irq)
bh = qemu_bh_new(arm_timer_tick, s);
s->timer = ptimer_init(bh);
- /* ??? Save/restore. */
+ register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
return s;
}
@@ -218,6 +241,25 @@ static CPUWriteMemoryFunc *sp804_writefn[] = {
sp804_write
};
+static void sp804_save(QEMUFile *f, void *opaque)
+{
+ sp804_state *s = (sp804_state *)opaque;
+ qemu_put_be32(f, s->level[0]);
+ qemu_put_be32(f, s->level[1]);
+}
+
+static int sp804_load(QEMUFile *f, void *opaque, int version_id)
+{
+ sp804_state *s = (sp804_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->level[0] = qemu_get_be32(f);
+ s->level[1] = qemu_get_be32(f);
+ return 0;
+}
+
void sp804_init(uint32_t base, qemu_irq irq)
{
int iomemtype;
@@ -235,7 +277,7 @@ void sp804_init(uint32_t base, qemu_irq irq)
iomemtype = cpu_register_io_memory(0, sp804_readfn,
sp804_writefn, s);
cpu_register_physical_memory(base, 0x00001000, iomemtype);
- /* ??? Save/restore. */
+ register_savevm("sp804", -1, 1, sp804_save, sp804_load, s);
}
@@ -303,6 +345,7 @@ void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
icp_pit_writefn, s);
cpu_register_physical_memory(base, 0x00001000, iomemtype);
- /* ??? Save/restore. */
+ /* This device has no state to save/restore. The component timers will
+ save themselves. */
}
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 37596d0cc..26e4c2f2f 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -368,6 +368,31 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
}
}
+static void nvic_save(QEMUFile *f, void *opaque)
+{
+ nvic_state *s = (nvic_state *)opaque;
+
+ qemu_put_be32(f, s->systick.control);
+ qemu_put_be32(f, s->systick.reload);
+ qemu_put_be64(f, s->systick.tick);
+ qemu_put_timer(f, s->systick.timer);
+}
+
+static int nvic_load(QEMUFile *f, void *opaque, int version_id)
+{
+ nvic_state *s = (nvic_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->systick.control = qemu_get_be32(f);
+ s->systick.reload = qemu_get_be32(f);
+ s->systick.tick = qemu_get_be64(f);
+ qemu_get_timer(f, s->systick.timer);
+
+ return 0;
+}
+
qemu_irq *armv7m_nvic_init(CPUState *env)
{
nvic_state *s;
@@ -381,5 +406,6 @@ qemu_irq *armv7m_nvic_init(CPUState *env)
if (env->v7m.nvic)
cpu_abort(env, "CPU can only have one NVIC\n");
env->v7m.nvic = s;
+ register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
return s->gic->in;
}
diff --git a/hw/blizzard.c b/hw/blizzard.c
index 9ad7e6a15..37330e7f2 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -73,6 +73,7 @@ struct blizzard_s {
uint8_t iformat;
uint8_t source;
DisplayState *state;
+ QEMUConsole *console;
blizzard_fn_t *line_fn_tab[2];
void *fb;
@@ -896,7 +897,7 @@ static void blizzard_update_display(void *opaque)
if (s->x != s->state->width || s->y != s->state->height) {
s->invalidate = 1;
- dpy_resize(s->state, s->x, s->y);
+ qemu_console_resize(s->console, s->x, s->y);
}
if (s->invalidate) {
@@ -993,9 +994,9 @@ void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds)
blizzard_reset(s);
- graphic_console_init(s->state, blizzard_update_display,
- blizzard_invalidate_display, blizzard_screen_dump,
- NULL, s);
+ s->console = graphic_console_init(s->state, blizzard_update_display,
+ blizzard_invalidate_display,
+ blizzard_screen_dump, NULL, s);
return s;
}
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 1e36446fd..c7e8f2cba 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3442,8 +3442,8 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
ds, vga_ram_base, vga_ram_offset, vga_ram_size);
cirrus_init_common(s, device_id, 1);
- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
- s->text_update, s);
+ s->console = graphic_console_init(s->ds, s->update, s->invalidate,
+ s->screen_dump, s->text_update, s);
s->pci_dev = (PCIDevice *)d;
diff --git a/hw/dma.c b/hw/dma.c
index f192c63d1..00c6332b4 100644
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -450,7 +450,7 @@ static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
static void dma_init2(struct dma_cont *d, int base, int dshift,
int page_base, int pageh_base)
{
- const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
+ static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
int i;
d->dshift = dshift;
diff --git a/hw/esp.c b/hw/esp.c
index 1843fb895..0a8b3e4d8 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -496,6 +496,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
//s->ti_size = 0;
s->rregs[ESP_RINTR] = INTR_FC;
s->rregs[ESP_RSEQ] = 0;
+ s->rregs[ESP_RFLAGS] = 0;
break;
case CMD_RESET:
DPRINTF("Chip reset (%2.2x)\n", val);
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index 0efcd831f..276f1fd09 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -67,7 +67,6 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size,
cpu_model = "crisv32";
}
env = cpu_init(cpu_model);
- register_savevm("cpu", 0, 1, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index 776cfb9cf..a2750386f 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -214,6 +214,7 @@ static inline int fs_channel(target_phys_addr_t base, target_phys_addr_t addr)
return (addr - base) >> 13;
}
+#ifdef USE_THIS_DEAD_CODE
static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
{
target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP);
@@ -227,23 +228,24 @@ static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
static void dump_c(int ch, struct dma_descr_context *c)
{
printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", (uint32_t) c->next);
- printf("saved_data=%x\n", (uint32_t) c->saved_data);
- printf("saved_data_buf=%x\n", (uint32_t) c->saved_data_buf);
+ printf("next=%p\n", c->next);
+ printf("saved_data=%p\n", c->saved_data);
+ printf("saved_data_buf=%p\n", c->saved_data_buf);
printf("eol=%x\n", (uint32_t) c->eol);
}
static void dump_d(int ch, struct dma_descr_data *d)
{
printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", (uint32_t) d->next);
- printf("buf=%x\n", (uint32_t) d->buf);
- printf("after=%x\n", (uint32_t) d->after);
+ printf("next=%p\n", d->next);
+ printf("buf=%p\n", d->buf);
+ printf("after=%p\n", d->after);
printf("intr=%x\n", (uint32_t) d->intr);
printf("out_eop=%x\n", (uint32_t) d->out_eop);
printf("in_eop=%x\n", (uint32_t) d->in_eop);
printf("eol=%x\n", (uint32_t) d->eol);
}
+#endif
static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
{
@@ -256,10 +258,10 @@ static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
D(dump_c(c, &ctrl->channels[c].current_c));
/* I guess this should update the current pos. */
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)ctrl->channels[c].current_c.saved_data;
+ ctrl->channels[c].regs[RW_SAVED_DATA] =
+ (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)ctrl->channels[c].current_c.saved_data_buf;
+ (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
}
static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
@@ -339,20 +341,20 @@ static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
D(printf("continue %d ok %p\n", c,
ctrl->channels[c].current_d.next));
ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t) ctrl->channels[c].current_d.next;
+ (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
channel_load_d(ctrl, c);
channel_start(ctrl, c);
}
ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t) ctrl->channels[c].current_d.buf;
+ (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
}
static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
{
unsigned int cmd = v & ((1 << 10) - 1);
- D(printf("%s ch=%d cmd=%x pc=%x\n",
- __func__, c, cmd, ctrl->env->pc));
+ D(printf("%s ch=%d cmd=%x\n",
+ __func__, c, cmd));
if (cmd & regk_dma_load_d) {
channel_load_d(ctrl, c);
if (cmd & regk_dma_burst)
@@ -402,7 +404,7 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c)
(uint32_t)ctrl->channels[c].current_d.after,
saved_data_buf));
- len = (uint32_t) ctrl->channels[c].current_d.after;
+ len = (uint32_t)(unsigned long) ctrl->channels[c].current_d.after;
len -= saved_data_buf;
if (len > sizeof buf)
@@ -420,7 +422,8 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c)
saved_data_buf += len;
- if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after) {
+ if (saved_data_buf ==
+ (uint32_t)(unsigned long)ctrl->channels[c].current_d.after) {
/* Done. Step to next. */
if (ctrl->channels[c].current_d.out_eop) {
/* TODO: signal eop to the client. */
@@ -444,10 +447,10 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c)
channel_stop(ctrl, c);
} else {
ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t) ctrl->channels[c].current_d.next;
+ (uint32_t)(unsigned long) ctrl->channels[c].current_d.next;
/* Load new descriptor. */
channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)
+ saved_data_buf = (uint32_t)(unsigned long)
ctrl->channels[c].current_d.buf;
}
@@ -468,7 +471,7 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
return 0;
saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t) ctrl->channels[c].current_d.after;
+ len = (uint32_t)(unsigned long) ctrl->channels[c].current_d.after;
len -= saved_data_buf;
if (len > buflen)
@@ -477,7 +480,8 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
cpu_physical_memory_write (saved_data_buf, buf, len);
saved_data_buf += len;
- if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after
+ if (saved_data_buf ==
+ (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
|| eop) {
uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
@@ -485,7 +489,7 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
ctrl->channels[c].current_d.after
- ctrl->channels[c].current_d.buf));
ctrl->channels[c].current_d.after =
- (void *) saved_data_buf;
+ (void *)(unsigned long) saved_data_buf;
/* Done. Step to next. */
if (ctrl->channels[c].current_d.intr) {
@@ -514,10 +518,10 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
channel_stop(ctrl, c);
} else {
ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t) ctrl->channels[c].current_d.next;
+ (uint32_t)(unsigned long) ctrl->channels[c].current_d.next;
/* Load new descriptor. */
channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)
+ saved_data_buf = (uint32_t)(unsigned long)
ctrl->channels[c].current_d.buf;
}
}
@@ -537,8 +541,8 @@ static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr)
{
struct fs_dma_ctrl *ctrl = opaque;
CPUState *env = ctrl->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
return 0;
}
@@ -562,8 +566,8 @@ dma_readl (void *opaque, target_phys_addr_t addr)
default:
r = ctrl->channels[c].regs[addr];
- D(printf ("%s c=%d addr=%x pc=%x\n",
- __func__, c, addr, ctrl->env->pc));
+ D(printf ("%s c=%d addr=%x\n",
+ __func__, c, addr));
break;
}
return r;
@@ -574,8 +578,8 @@ dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
{
struct fs_dma_ctrl *ctrl = opaque;
CPUState *env = ctrl->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
}
static void
@@ -619,14 +623,12 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
case RW_STREAM_CMD:
ctrl->channels[c].regs[addr] = value;
- D(printf("stream_cmd ch=%d pc=%x\n",
- c, ctrl->env->pc));
+ D(printf("stream_cmd ch=%d\n", c));
channel_stream_cmd(ctrl, c, value);
break;
default:
- D(printf ("%s c=%d %x %x pc=%x\n",
- __func__, c, addr, value, ctrl->env->pc));
+ D(printf ("%s c=%d %x %x\n", __func__, c, addr));
break;
}
}
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 3d7ca0f62..9ef610fd1 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -154,11 +154,13 @@ mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
bus->devs[addr & 0x1f] = phy;
}
+#ifdef USE_THIS_DEAD_CODE
static void
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
{
bus->devs[addr & 0x1f] = NULL;
}
+#endif
static void mdio_read_req(struct qemu_mdio *bus)
{
@@ -328,15 +330,14 @@ static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
{
struct fs_eth *eth = opaque;
CPUState *env = eth->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
return 0;
}
static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
{
struct fs_eth *eth = opaque;
- D(CPUState *env = eth->env);
uint32_t r = 0;
/* Make addr relative to this instances base. */
@@ -348,7 +349,7 @@ static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
break;
default:
r = eth->regs[addr];
- D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
+ D(printf ("%s %x\n", __func__, addr));
break;
}
return r;
@@ -359,8 +360,8 @@ eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
{
struct fs_eth *eth = opaque;
CPUState *env = eth->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
}
static void eth_update_ma(struct fs_eth *eth, int ma)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index bb971f8d2..11a0f2210 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -89,7 +89,7 @@ static void ser_update_irq(struct etrax_serial_t *s)
static uint32_t ser_readb (void *opaque, target_phys_addr_t addr)
{
D(CPUState *env = opaque);
- D(printf ("%s %x pc=%x\n", __func__, addr, env->pc));
+ D(printf ("%s %x\n", __func__, addr));
return 0;
}
@@ -132,7 +132,7 @@ static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
break;
default:
- D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
+ D(printf ("%s %x\n", __func__, addr));
break;
}
return r;
@@ -143,7 +143,7 @@ ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
D(struct etrax_serial_t *s = opaque);
D(CPUState *env = s->env);
- D(printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc));
+ D(printf ("%s %x %x\n", __func__, addr, value));
}
static void
ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -181,8 +181,7 @@ ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
s->rw_intr_mask = value;
break;
default:
- D(printf ("%s %x %x pc=%x\n",
- __func__, addr, value, env->pc));
+ D(printf ("%s %x %x\n", __func__, addr, value));
break;
}
ser_update_irq(s);
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index e996c57f6..8d4505192 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -80,15 +80,14 @@ static uint32_t timer_rinvalid (void *opaque, target_phys_addr_t addr)
{
struct fs_timer_t *t = opaque;
CPUState *env = t->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
return 0;
}
static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
{
struct fs_timer_t *t = opaque;
- D(CPUState *env = t->env);
uint32_t r = 0;
/* Make addr relative to this instances base. */
@@ -109,7 +108,7 @@ static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
r = t->r_intr & t->rw_intr_mask;
break;
default:
- D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
+ D(printf ("%s %x\n", __func__, addr));
break;
}
return r;
@@ -120,8 +119,8 @@ timer_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
{
struct fs_timer_t *t = opaque;
CPUState *env = t->env;
- cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
- addr, env->pc);
+ cpu_abort(env, "Unsupported short access. reg=" TARGET_FMT_plx "\n",
+ addr);
}
#define TIMER_SLOWDOWN 1
@@ -273,7 +272,6 @@ static void
timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
struct fs_timer_t *t = opaque;
- CPUState *env = t->env;
/* Make addr relative to this instances base. */
addr -= t->base;
@@ -309,8 +307,8 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
t->rw_ack_intr = 0;
break;
default:
- printf ("%s %x %x pc=%x\n",
- __func__, addr, value, env->pc);
+ printf ("%s " TARGET_FMT_plx " %x\n",
+ __func__, addr, value);
break;
}
}
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 0dd4ee766..3dfc8e1cd 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -33,6 +33,7 @@ typedef struct G364State {
uint8_t palette[256][3];
/* display refresh support */
DisplayState *ds;
+ QEMUConsole *console;
int graphic_mode;
uint32_t scr_width, scr_height; /* in pixels */
uint32_t last_scr_width, last_scr_height; /* in pixels */
@@ -74,13 +75,6 @@ static void g364fb_draw_graphic(G364State *s, int full_update)
{
if (s->scr_width == 0 || s->scr_height == 0)
return;
- if (s->scr_width != s->last_scr_width
- || s->scr_height != s->last_scr_height) {
- s->last_scr_width = s->scr_width;
- s->last_scr_height = s->scr_height;
- dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
- full_update = 1;
- }
switch (s->ds->depth) {
case 8:
@@ -272,7 +266,10 @@ static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t v
#endif
break;
}
+ if (s->scr_width && s->scr_height)
+ qemu_console_resize(s->console, s->scr_width, s->scr_height);
}
+ s->graphic_mode = -1; /* force full update */
}
static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -382,9 +379,9 @@ int g364fb_mm_init(DisplayState *ds,
s->ds = ds;
s->vram_base = vram_base;
- graphic_console_init(ds, g364fb_update_display,
- g364fb_invalidate_display, g364fb_screen_dump,
- NULL, s);
+ s->console = graphic_console_init(ds, g364fb_update_display,
+ g364fb_invalidate_display,
+ g364fb_screen_dump, NULL, s);
io_vram = cpu_register_io_memory(0, g364fb_mem_read, g364fb_mem_write, s);
cpu_register_physical_memory(s->vram_base, vram_size, io_vram);
diff --git a/hw/gus.c b/hw/gus.c
index 9ff00d791..0ab55a63b 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -222,32 +222,30 @@ int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
static void GUS_save (QEMUFile *f, void *opaque)
{
- int32_t val;
GUSState *s = opaque;
- val = s->pos; qemu_put_be32s (f, &val);
- val = s->left; qemu_put_be32s (f, &val);
- val = s->shift; qemu_put_be32s (f, &val);
- val = s->irqs; qemu_put_be32s (f, &val);
- val = s->samples; qemu_put_be32s (f, &val);
- qemu_put_be64s (f, &s->last_ticks);
+ qemu_put_be32 (f, s->pos);
+ qemu_put_be32 (f, s->left);
+ qemu_put_be32 (f, s->shift);
+ qemu_put_be32 (f, s->irqs);
+ qemu_put_be32 (f, s->samples);
+ qemu_put_be64 (f, s->last_ticks);
qemu_put_buffer (f, s->himem, sizeof (s->himem));
}
static int GUS_load (QEMUFile *f, void *opaque, int version_id)
{
- int32_t val;
GUSState *s = opaque;
if (version_id != 2)
return -EINVAL;
- qemu_get_be32s (f, &val); s->pos = val;
- qemu_get_be32s (f, &val); s->left = val;
- qemu_get_be32s (f, &val); s->shift = val;
- qemu_get_be32s (f, &val); s->irqs = val;
- qemu_get_be32s (f, &val); s->samples = val;
- qemu_get_be64s (f, &s->last_ticks);
+ s->pos = qemu_get_be32 (f);
+ s->left = qemu_get_be32 (f);
+ s->shift = qemu_get_be32 (f);
+ s->irqs = qemu_get_be32 (f);
+ s->samples = qemu_get_be32 (f);
+ s->last_ticks = qemu_get_be64 (f);
qemu_get_buffer (f, s->himem, sizeof (s->himem));
return 0;
}
diff --git a/hw/i2c.c b/hw/i2c.c
index e590801af..5d283fb4c 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -14,14 +14,38 @@ struct i2c_bus
{
i2c_slave *current_dev;
i2c_slave *dev;
+ int saved_address;
};
+static void i2c_bus_save(QEMUFile *f, void *opaque)
+{
+ i2c_bus *bus = (i2c_bus *)opaque;
+
+ qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : -1);
+}
+
+static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id)
+{
+ i2c_bus *bus = (i2c_bus *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ /* The bus is loaded before attached devices, so load and save the
+ current device id. Devices will check themselves as loaded. */
+ bus->saved_address = qemu_get_be32(f);
+ bus->current_dev = NULL;
+
+ return 0;
+}
+
/* Create a new I2C bus. */
i2c_bus *i2c_init_bus(void)
{
i2c_bus *bus;
bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus));
+ register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus);
return bus;
}
@@ -37,6 +61,7 @@ i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size)
dev->address = address;
dev->next = bus->dev;
bus->dev = dev;
+ dev->bus = bus;
return dev;
}
@@ -115,28 +140,6 @@ void i2c_nack(i2c_bus *bus)
dev->event(dev, I2C_NACK);
}
-void i2c_bus_save(QEMUFile *f, i2c_bus *bus)
-{
- qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00);
-}
-
-void i2c_bus_load(QEMUFile *f, i2c_bus *bus)
-{
- i2c_slave *dev;
- uint8_t address = qemu_get_byte(f);
-
- if (address) {
- for (dev = bus->dev; dev; dev = dev->next)
- if (dev->address == address) {
- bus->current_dev = dev;
- return;
- }
-
- fprintf(stderr, "%s: I2C slave with address %02x disappeared\n",
- __FUNCTION__, address);
- }
-}
-
void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
{
qemu_put_byte(f, dev->address);
@@ -145,4 +148,6 @@ void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
{
dev->address = qemu_get_byte(f);
+ if (dev->bus->saved_address == dev->address)
+ dev->bus->current_dev = dev;
}
diff --git a/hw/i2c.h b/hw/i2c.h
index f297237b7..d3e4352b1 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -30,6 +30,7 @@ struct i2c_slave
/* Remaining fields for internal use by the I2C code. */
int address;
void *next;
+ i2c_bus *bus;
};
i2c_bus *i2c_init_bus(void);
@@ -41,8 +42,6 @@ void i2c_end_transfer(i2c_bus *bus);
void i2c_nack(i2c_bus *bus);
int i2c_send(i2c_bus *bus, uint8_t data);
int i2c_recv(i2c_bus *bus);
-void i2c_bus_save(QEMUFile *f, i2c_bus *bus);
-void i2c_bus_load(QEMUFile *f, i2c_bus *bus);
void i2c_slave_save(QEMUFile *f, i2c_slave *dev);
void i2c_slave_load(QEMUFile *f, i2c_slave *dev);
diff --git a/hw/ide.c b/hw/ide.c
index 816d04ba9..6c61d993c 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -352,6 +352,7 @@
#define ASC_ILLEGAL_OPCODE 0x20
#define ASC_LOGICAL_BLOCK_OOR 0x21
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
+#define ASC_INCOMPATIBLE_FORMAT 0x30
#define ASC_MEDIUM_NOT_PRESENT 0x3a
#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
@@ -435,6 +436,22 @@ typedef struct IDEState {
int media_changed;
} IDEState;
+/* XXX: DVDs that could fit on a CD will be reported as a CD */
+static inline int media_present(IDEState *s)
+{
+ return (s->nb_sectors > 0);
+}
+
+static inline int media_is_dvd(IDEState *s)
+{
+ return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS);
+}
+
+static inline int media_is_cd(IDEState *s)
+{
+ return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
+}
+
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
#define BM_STATUS_INT 0x04
@@ -1365,6 +1382,93 @@ static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
return 4;
}
+static int ide_dvd_read_structure(IDEState *s, int format,
+ const uint8_t *packet, uint8_t *buf)
+{
+ switch (format) {
+ case 0x0: /* Physical format information */
+ {
+ int layer = packet[6];
+ uint64_t total_sectors;
+
+ if (layer != 0)
+ return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+ bdrv_get_geometry(s->bs, &total_sectors);
+ total_sectors >>= 2;
+ if (total_sectors == 0)
+ return -ASC_MEDIUM_NOT_PRESENT;
+
+ buf[4] = 1; /* DVD-ROM, part version 1 */
+ buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+ buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
+ buf[7] = 0; /* default densities */
+
+ /* FIXME: 0x30000 per spec? */
+ cpu_to_ube32(buf + 8, 0); /* start sector */
+ cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */
+ cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
+
+ /* Size of buffer, not including 2 byte size field */
+ cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+ /* 2k data + 4 byte header */
+ return (2048 + 4);
+ }
+
+ case 0x01: /* DVD copyright information */
+ buf[4] = 0; /* no copyright data */
+ buf[5] = 0; /* no region restrictions */
+
+ /* Size of buffer, not including 2 byte size field */
+ cpu_to_be16wu((uint16_t *)buf, 4 + 2);
+
+ /* 4 byte header + 4 byte data */
+ return (4 + 4);
+
+ case 0x03: /* BCA information - invalid field for no BCA info */
+ return -ASC_INV_FIELD_IN_CMD_PACKET;
+
+ case 0x04: /* DVD disc manufacturing information */
+ /* Size of buffer, not including 2 byte size field */
+ cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+
+ /* 2k data + 4 byte header */
+ return (2048 + 4);
+
+ case 0xff:
+ /*
+ * This lists all the command capabilities above. Add new ones
+ * in order and update the length and buffer return values.
+ */
+
+ buf[4] = 0x00; /* Physical format */
+ buf[5] = 0x40; /* Not writable, is readable */
+ cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
+
+ buf[8] = 0x01; /* Copyright info */
+ buf[9] = 0x40; /* Not writable, is readable */
+ cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
+
+ buf[12] = 0x03; /* BCA info */
+ buf[13] = 0x40; /* Not writable, is readable */
+ cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
+
+ buf[16] = 0x04; /* Manufacturing info */
+ buf[17] = 0x40; /* Not writable, is readable */
+ cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
+
+ /* Size of buffer, not including 2 byte size field */
+ cpu_to_be16wu((uint16_t *)buf, 16 + 2);
+
+ /* data written + 4 byte header */
+ return (16 + 4);
+
+ default: /* TODO: formats beyond DVD-ROM requires */
+ return -ASC_INV_FIELD_IN_CMD_PACKET;
+ }
+}
+
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
@@ -1652,42 +1756,48 @@ static void ide_atapi_cmd(IDEState *s)
case GPCMD_READ_DVD_STRUCTURE:
{
int media = packet[1];
- int layer = packet[6];
- int format = packet[2];
- uint64_t total_sectors;
-
- if (media != 0 || layer != 0)
- {
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- }
-
- switch (format) {
- case 0:
- bdrv_get_geometry(s->bs, &total_sectors);
- total_sectors >>= 2;
- if (total_sectors == 0) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
+ int format = packet[7];
+ int ret;
- memset(buf, 0, 2052);
+ max_len = ube16_to_cpu(packet + 8);
- buf[4] = 1; // DVD-ROM, part version 1
- buf[5] = 0xf; // 120mm disc, maximum rate unspecified
- buf[6] = 0; // one layer, embossed data
- buf[7] = 0;
+ if (format < 0xff) {
+ if (media_is_cd(s)) {
+ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_INCOMPATIBLE_FORMAT);
+ break;
+ } else if (!media_present(s)) {
+ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ break;
+ }
+ }
- cpu_to_ube32(buf + 8, 0);
- cpu_to_ube32(buf + 12, total_sectors - 1);
- cpu_to_ube32(buf + 16, total_sectors - 1);
+ memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ?
+ IDE_DMA_BUF_SECTORS * 512 + 4 : max_len);
- cpu_to_be16wu((uint16_t *)buf, 2048 + 4);
+ switch (format) {
+ case 0x00 ... 0x7f:
+ case 0xff:
+ if (media == 0) {
+ ret = ide_dvd_read_structure(s, format, packet, buf);
- ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4);
- break;
+ if (ret < 0)
+ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
+ else
+ ide_atapi_cmd_reply(s, ret, max_len);
+ break;
+ }
+ /* TODO: BD support, fall through for now */
+
+ /* Generic disk structures */
+ case 0x80: /* TODO: AACS volume identifier */
+ case 0x81: /* TODO: AACS media serial number */
+ case 0x82: /* TODO: AACS media identifier */
+ case 0x83: /* TODO: AACS media key block */
+ case 0x90: /* TODO: List of recognized format layers */
+ case 0xc0: /* TODO: Write protection status */
default:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
@@ -1742,16 +1852,11 @@ static void ide_atapi_cmd(IDEState *s)
/*
* the number of sectors from the media tells us which profile
* to use as current. 0 means there is no media
- *
- * XXX: fails to detect correctly DVDs with less data burned
- * than what a CD can hold
*/
- if (s -> nb_sectors) {
- if (s -> nb_sectors > CD_MAX_SECTORS)
- cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
- else
- cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
- }
+ if (media_is_dvd(s))
+ cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
+ else if (media_is_cd(s))
+ cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
buf[10] = 0x02 | 0x01; /* persistent and current */
len = 12; /* headers: 8 + 4 */
@@ -3502,8 +3607,6 @@ static int md_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int md_iid = 0;
-
static const uint8_t dscm1xxxx_cis[0x14a] = {
[0x000] = CISTPL_DEVICE, /* 5V Device Information */
[0x002] = 0x03, /* Tuple length = 4 bytes */
@@ -3730,7 +3833,7 @@ struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
md->ide->mdata_size = METADATA_SIZE;
md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
- register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md);
+ register_savevm("microdrive", -1, 0, md_save, md_load, md);
return &md->card;
}
diff --git a/hw/iommu.c b/hw/iommu.c
index 0879df95f..fe6911e5e 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -301,9 +301,9 @@ void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
iommu_bad_addr(opaque, page, is_write);
return;
}
- cpu_physical_memory_write(phys_addr, buf, len);
+ cpu_physical_memory_write(phys_addr, buf, l);
} else {
- cpu_physical_memory_read(phys_addr, buf, len);
+ cpu_physical_memory_read(phys_addr, buf, l);
}
len -= l;
buf += l;
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index d547138b9..8460bfcd5 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -37,6 +37,7 @@ typedef struct LedState {
target_phys_addr_t base;
uint8_t segments;
DisplayState *ds;
+ QEMUConsole *console;
screen_state_t state;
} LedState;
@@ -291,7 +292,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
char buf[2];
dpy_cursor(s->ds, -1, -1);
- dpy_resize(s->ds, 2, 1);
+ qemu_console_resize(s->console, 2, 1);
/* TODO: draw the segments */
snprintf(buf, 2, "%02hhx\n", s->segments);
@@ -317,7 +318,9 @@ void jazz_led_init(DisplayState *ds, target_phys_addr_t base)
io = cpu_register_io_memory(0, led_read, led_write, s);
cpu_register_physical_memory(s->base, 1, io);
- graphic_console_init(ds, jazz_led_update_display,
- jazz_led_invalidate_display, jazz_led_screen_dump,
- jazz_led_text_update, s);
+ s->console = graphic_console_init(ds, jazz_led_update_display,
+ jazz_led_invalidate_display,
+ jazz_led_screen_dump,
+ jazz_led_text_update, s);
+ qemu_console_resize(s->console, 60, 80);
}
diff --git a/hw/lm832x.c b/hw/lm832x.c
index efb80f7e7..1e4564e3b 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -490,8 +490,6 @@ static int lm_kbd_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int lm_kbd_iid = 0;
-
struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq)
{
struct lm_kbd_s *s;
@@ -510,8 +508,7 @@ struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq)
lm_kbd_reset(s);
qemu_register_reset((void *) lm_kbd_reset, s);
- register_savevm("LM8323", lm_kbd_iid ++, 0,
- lm_kbd_save, lm_kbd_load, s);
+ register_savevm("LM8323", -1, 0, lm_kbd_save, lm_kbd_load, s);
return &s->i2c;
}
diff --git a/hw/max111x.c b/hw/max111x.c
index cc3ded1df..15392a21f 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -121,8 +121,6 @@ static int max111x_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int max111x_iid = 0;
-
static struct max111x_s *max111x_init(qemu_irq cb)
{
struct max111x_s *s;
@@ -143,8 +141,7 @@ static struct max111x_s *max111x_init(qemu_irq cb)
s->input[7] = 0x80;
s->com = 0;
- register_savevm("max111x", max111x_iid ++, 0,
- max111x_save, max111x_load, s);
+ register_savevm("max111x", -1, 0, max111x_save, max111x_load, s);
return s;
}
diff --git a/hw/max7310.c b/hw/max7310.c
index 397950a08..2816611a8 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -177,8 +177,6 @@ static int max7310_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int max7310_iid = 0;
-
static void max7310_gpio_set(void *opaque, int line, int level)
{
struct max7310_s *s = (struct max7310_s *) opaque;
@@ -205,8 +203,7 @@ struct i2c_slave *max7310_init(i2c_bus *bus)
max7310_reset(&s->i2c);
- register_savevm("max7310", max7310_iid ++, 0,
- max7310_save, max7310_load, s);
+ register_savevm("max7310", -1, 0, max7310_save, max7310_load, s);
return &s->i2c;
}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index bfd8b53bc..52cf47b84 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -146,7 +146,6 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 367d07dcc..1d6532624 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -804,7 +804,6 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index e29d8af46..d04c660b4 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -65,7 +65,7 @@ static void load_kernel (CPUState *env)
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
- env->PC[env->current_tc] = entry;
+ env->active_tc.PC = entry;
} else {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
@@ -129,7 +129,6 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* Allocate RAM. */
@@ -152,7 +151,7 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
cpu_register_physical_memory(0x1fc00000LL,
bios_size, bios_offset | IO_MEM_ROM);
/* We have a boot vector start address. */
- env->PC[env->current_tc] = (target_long)(int32_t)0xbfc00000;
+ env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
}
if (kernel_filename) {
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 66ae13561..a9d42eadc 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -87,7 +87,7 @@ static void load_kernel (CPUState *env)
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
- env->PC[env->current_tc] = entry;
+ env->active_tc.PC = entry;
} else {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
@@ -175,7 +175,6 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 5b172ea42..5549e2483 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -91,7 +91,12 @@ static void mips_timer_cb (void *opaque)
if (env->CP0_Cause & (1 << CP0Ca_DC))
return;
+ /* ??? This callback should occur when the counter is exactly equal to
+ the comparator value. Offset the count by one to avoid immediately
+ retriggering the callback before any virtual time has passed. */
+ env->CP0_Count++;
cpu_mips_timer_update(env);
+ env->CP0_Count--;
if (env->insn_flags & ISA_MIPS32R2)
env->CP0_Cause |= 1 << CP0Ca_TI;
qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index b0fcee25b..e4d8c89be 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -758,8 +758,8 @@ typedef struct musicpal_lcd_state {
int page;
int page_off;
DisplayState *ds;
+ QEMUConsole *console;
uint8_t video_ram[128*64/8];
- int invalidate;
} musicpal_lcd_state;
static uint32_t lcd_brightness;
@@ -818,11 +818,6 @@ static void lcd_refresh(void *opaque)
musicpal_lcd_state *s = opaque;
int x, y, col;
- if (s->invalidate && (s->ds->width != 128*3 || s->ds->height != 64*3)) {
- dpy_resize(s->ds, 128*3, 64*3);
- s->invalidate = 0;
- }
-
switch (s->ds->depth) {
case 0:
return;
@@ -851,9 +846,6 @@ static void lcd_refresh(void *opaque)
static void lcd_invalidate(void *opaque)
{
- musicpal_lcd_state *s = opaque;
-
- s->invalidate = 1;
}
static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
@@ -932,12 +924,13 @@ static void musicpal_lcd_init(DisplayState *ds, uint32_t base)
return;
s->base = base;
s->ds = ds;
- s->invalidate = 1;
iomemtype = cpu_register_io_memory(0, musicpal_lcd_readfn,
musicpal_lcd_writefn, s);
cpu_register_physical_memory(base, MP_LCD_SIZE, iomemtype);
- graphic_console_init(ds, lcd_refresh, lcd_invalidate, NULL, NULL, s);
+ s->console = graphic_console_init(ds, lcd_refresh, lcd_invalidate,
+ NULL, NULL, s);
+ qemu_console_resize(s->console, 128*3, 64*3);
}
/* PIC register offsets */
diff --git a/hw/nand.c b/hw/nand.c
index aa0c200f2..294a83f85 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -319,8 +319,6 @@ static int nand_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int nand_iid = 0;
-
/*
* Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
* outputs are R/B and eight I/O pins.
@@ -495,7 +493,7 @@ struct nand_flash_s *nand_init(int manf_id, int chip_id)
s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
0xff, s->pages * pagesize);
- register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s);
+ register_savevm("nand", -1, 0, nand_save, nand_load, s);
return s;
}
diff --git a/hw/nseries.c b/hw/nseries.c
index 5620897b1..725554d44 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1307,7 +1307,9 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
n800_setup_nolo_tags(phys_ram_base + sdram_size);
}
-
+ /* FIXME: We shouldn't really be doing this here. The LCD controller
+ will set the size once configured, so this just sets an initial
+ size until the guest activates the display. */
dpy_resize(ds, 800, 480);
}
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index 42174f7e0..99e8b4fa4 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -26,6 +26,7 @@ struct omap_lcd_panel_s {
target_phys_addr_t base;
qemu_irq irq;
DisplayState *state;
+ QEMUConsole *console;
ram_addr_t imif_base;
ram_addr_t emiff_base;
@@ -175,8 +176,8 @@ static void omap_update_display(void *opaque)
width = omap_lcd->width;
if (width != omap_lcd->state->width ||
omap_lcd->height != omap_lcd->state->height) {
- dpy_resize(omap_lcd->state,
- omap_lcd->width, omap_lcd->height);
+ qemu_console_resize(omap_lcd->console,
+ omap_lcd->width, omap_lcd->height);
omap_lcd->invalidate = 1;
}
@@ -494,8 +495,9 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
omap_lcdc_writefn, s);
cpu_register_physical_memory(s->base, 0x100, iomemtype);
- graphic_console_init(ds, omap_update_display,
- omap_invalidate_display, omap_screen_dump, NULL, s);
+ s->console = graphic_console_init(ds, omap_update_display,
+ omap_invalidate_display,
+ omap_screen_dump, NULL, s);
return s;
}
diff --git a/hw/palm.c b/hw/palm.c
index a573ed7d1..9af0b1362 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -275,6 +275,9 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size,
arm_load_kernel(cpu->env, &palmte_binfo);
}
+ /* FIXME: We shouldn't really be doing this here. The LCD controller
+ will set the size once configured, so this just sets an initial
+ size until the guest activates the display. */
dpy_resize(ds, 320, 320);
}
diff --git a/hw/pc.c b/hw/pc.c
index 6334c769b..d578e6870 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -760,7 +760,6 @@ CPUState *pc_new_cpu(int cpu, const char *cpu_model, int pci_enabled)
/* XXX: enable it in all cases */
env->cpuid_features |= CPUID_APIC;
}
- register_savevm("cpu", cpu, 5, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
if (pci_enabled) {
apic_init(env);
diff --git a/hw/pl011.c b/hw/pl011.c
index 667664499..bbef0a4c6 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -238,6 +238,57 @@ static CPUWriteMemoryFunc *pl011_writefn[] = {
pl011_write
};
+static void pl011_save(QEMUFile *f, void *opaque)
+{
+ pl011_state *s = (pl011_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->readbuff);
+ qemu_put_be32(f, s->flags);
+ qemu_put_be32(f, s->lcr);
+ qemu_put_be32(f, s->cr);
+ qemu_put_be32(f, s->dmacr);
+ qemu_put_be32(f, s->int_enabled);
+ qemu_put_be32(f, s->int_level);
+ for (i = 0; i < 16; i++)
+ qemu_put_be32(f, s->read_fifo[i]);
+ qemu_put_be32(f, s->ilpr);
+ qemu_put_be32(f, s->ibrd);
+ qemu_put_be32(f, s->fbrd);
+ qemu_put_be32(f, s->ifl);
+ qemu_put_be32(f, s->read_pos);
+ qemu_put_be32(f, s->read_count);
+ qemu_put_be32(f, s->read_trigger);
+}
+
+static int pl011_load(QEMUFile *f, void *opaque, int version_id)
+{
+ pl011_state *s = (pl011_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->readbuff = qemu_get_be32(f);
+ s->flags = qemu_get_be32(f);
+ s->lcr = qemu_get_be32(f);
+ s->cr = qemu_get_be32(f);
+ s->dmacr = qemu_get_be32(f);
+ s->int_enabled = qemu_get_be32(f);
+ s->int_level = qemu_get_be32(f);
+ for (i = 0; i < 16; i++)
+ s->read_fifo[i] = qemu_get_be32(f);
+ s->ilpr = qemu_get_be32(f);
+ s->ibrd = qemu_get_be32(f);
+ s->fbrd = qemu_get_be32(f);
+ s->ifl = qemu_get_be32(f);
+ s->read_pos = qemu_get_be32(f);
+ s->read_count = qemu_get_be32(f);
+ s->read_trigger = qemu_get_be32(f);
+
+ return 0;
+}
+
void pl011_init(uint32_t base, qemu_irq irq,
CharDriverState *chr, enum pl011_type type)
{
@@ -260,6 +311,6 @@ void pl011_init(uint32_t base, qemu_irq irq,
qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
pl011_event, s);
}
- /* ??? Save/restore. */
+ register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s);
}
diff --git a/hw/pl022.c b/hw/pl022.c
index 54a581b88..a9d20c517 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -244,6 +244,55 @@ static CPUWriteMemoryFunc *pl022_writefn[] = {
pl022_write
};
+static void pl022_save(QEMUFile *f, void *opaque)
+{
+ pl022_state *s = (pl022_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->cr0);
+ qemu_put_be32(f, s->cr1);
+ qemu_put_be32(f, s->bitmask);
+ qemu_put_be32(f, s->sr);
+ qemu_put_be32(f, s->cpsr);
+ qemu_put_be32(f, s->is);
+ qemu_put_be32(f, s->im);
+ qemu_put_be32(f, s->tx_fifo_head);
+ qemu_put_be32(f, s->rx_fifo_head);
+ qemu_put_be32(f, s->tx_fifo_len);
+ qemu_put_be32(f, s->rx_fifo_len);
+ for (i = 0; i < 8; i++) {
+ qemu_put_be16(f, s->tx_fifo[i]);
+ qemu_put_be16(f, s->rx_fifo[i]);
+ }
+}
+
+static int pl022_load(QEMUFile *f, void *opaque, int version_id)
+{
+ pl022_state *s = (pl022_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->cr0 = qemu_get_be32(f);
+ s->cr1 = qemu_get_be32(f);
+ s->bitmask = qemu_get_be32(f);
+ s->sr = qemu_get_be32(f);
+ s->cpsr = qemu_get_be32(f);
+ s->is = qemu_get_be32(f);
+ s->im = qemu_get_be32(f);
+ s->tx_fifo_head = qemu_get_be32(f);
+ s->rx_fifo_head = qemu_get_be32(f);
+ s->tx_fifo_len = qemu_get_be32(f);
+ s->rx_fifo_len = qemu_get_be32(f);
+ for (i = 0; i < 8; i++) {
+ s->tx_fifo[i] = qemu_get_be16(f);
+ s->rx_fifo[i] = qemu_get_be16(f);
+ }
+
+ return 0;
+}
+
void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int),
void * opaque)
{
@@ -259,7 +308,7 @@ void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int),
s->xfer_cb = xfer_cb;
s->opaque = opaque;
pl022_reset(s);
- /* ??? Save/restore. */
+ register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s);
}
diff --git a/hw/pl061.c b/hw/pl061.c
index 3ac0a4c10..6db5e393b 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -240,6 +240,62 @@ static CPUWriteMemoryFunc *pl061_writefn[] = {
pl061_write
};
+static void pl061_save(QEMUFile *f, void *opaque)
+{
+ pl061_state *s = (pl061_state *)opaque;
+
+ qemu_put_be32(f, s->locked);
+ qemu_put_be32(f, s->data);
+ qemu_put_be32(f, s->old_data);
+ qemu_put_be32(f, s->dir);
+ qemu_put_be32(f, s->isense);
+ qemu_put_be32(f, s->ibe);
+ qemu_put_be32(f, s->iev);
+ qemu_put_be32(f, s->im);
+ qemu_put_be32(f, s->istate);
+ qemu_put_be32(f, s->afsel);
+ qemu_put_be32(f, s->dr2r);
+ qemu_put_be32(f, s->dr4r);
+ qemu_put_be32(f, s->dr8r);
+ qemu_put_be32(f, s->odr);
+ qemu_put_be32(f, s->pur);
+ qemu_put_be32(f, s->pdr);
+ qemu_put_be32(f, s->slr);
+ qemu_put_be32(f, s->den);
+ qemu_put_be32(f, s->cr);
+ qemu_put_be32(f, s->float_high);
+}
+
+static int pl061_load(QEMUFile *f, void *opaque, int version_id)
+{
+ pl061_state *s = (pl061_state *)opaque;
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->locked = qemu_get_be32(f);
+ s->data = qemu_get_be32(f);
+ s->old_data = qemu_get_be32(f);
+ s->dir = qemu_get_be32(f);
+ s->isense = qemu_get_be32(f);
+ s->ibe = qemu_get_be32(f);
+ s->iev = qemu_get_be32(f);
+ s->im = qemu_get_be32(f);
+ s->istate = qemu_get_be32(f);
+ s->afsel = qemu_get_be32(f);
+ s->dr2r = qemu_get_be32(f);
+ s->dr4r = qemu_get_be32(f);
+ s->dr8r = qemu_get_be32(f);
+ s->odr = qemu_get_be32(f);
+ s->pur = qemu_get_be32(f);
+ s->pdr = qemu_get_be32(f);
+ s->slr = qemu_get_be32(f);
+ s->den = qemu_get_be32(f);
+ s->cr = qemu_get_be32(f);
+ s->float_high = qemu_get_be32(f);
+
+ return 0;
+}
+
/* Returns an array of inputs. */
qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out)
{
@@ -256,7 +312,7 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out)
if (out)
*out = s->out;
- /* ??? Save/restore. */
+ register_savevm("pl061_gpio", -1, 1, pl061_save, pl061_load, s);
return qemu_allocate_irqs(pl061_set_irq, s, 8);
}
diff --git a/hw/pl110.c b/hw/pl110.c
index 7f450851a..2437185f6 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -30,6 +30,8 @@ enum pl110_bppmode
typedef struct {
uint32_t base;
DisplayState *ds;
+ QEMUConsole *console;
+
/* The Versatile/PB uses a slightly modified PL110 controller. */
int versatile;
uint32_t timing[4];
@@ -270,7 +272,7 @@ static void pl110_resize(pl110_state *s, int width, int height)
{
if (width != s->cols || height != s->rows) {
if (pl110_enabled(s)) {
- dpy_resize(s->ds, width, height);
+ qemu_console_resize(s->console, width, height);
}
}
s->cols = width;
@@ -387,7 +389,7 @@ static void pl110_write(void *opaque, target_phys_addr_t offset,
s->cr = val;
s->bpp = (val >> 1) & 7;
if (pl110_enabled(s)) {
- dpy_resize(s->ds, s->cols, s->rows);
+ qemu_console_resize(s->console, s->cols, s->rows);
}
break;
case 10: /* LCDICR */
@@ -425,8 +427,9 @@ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq,
s->ds = ds;
s->versatile = versatile;
s->irq = irq;
- graphic_console_init(ds, pl110_update_display, pl110_invalidate_display,
- NULL, NULL, s);
+ s->console = graphic_console_init(ds, pl110_update_display,
+ pl110_invalidate_display,
+ NULL, NULL, s);
/* ??? Save/restore. */
return s;
}
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index fca3b86e0..80baf308b 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -61,7 +61,6 @@ CPUState *ppc4xx_init (const unsigned char *cpu_model,
ppc_dcr_init(env, NULL, NULL);
/* Register qemu callbacks */
qemu_register_reset(&cpu_ppc_reset, env);
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
return env;
}
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index c7ee5294a..59acbce22 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -103,7 +103,6 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
env->osi_call = vga_osi_call;
#endif
qemu_register_reset(&cpu_ppc_reset, env);
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
envs[i] = env;
}
if (env->nip < 0xFFF80000) {
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index be5ee6710..85d3b2ce8 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -143,7 +143,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
env->osi_call = vga_osi_call;
qemu_register_reset(&cpu_ppc_reset, env);
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
envs[i] = env;
}
if (env->nip < 0xFFF80000) {
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 7d754926d..c6e3a8b80 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -580,7 +580,6 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
}
qemu_register_reset(&cpu_ppc_reset, env);
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
envs[i] = env;
}
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6e06baada..fd663d9da 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1466,7 +1466,6 @@ static void pxa2xx_i2c_save(QEMUFile *f, void *opaque)
qemu_put_8s(f, &s->ibmr);
qemu_put_8s(f, &s->data);
- i2c_bus_save(f, s->bus);
i2c_slave_save(f, &s->slave);
}
@@ -1474,12 +1473,14 @@ static int pxa2xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
{
struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+ if (version_id != 1)
+ return -EINVAL;
+
qemu_get_be16s(f, &s->control);
qemu_get_be16s(f, &s->status);
qemu_get_8s(f, &s->ibmr);
qemu_get_8s(f, &s->data);
- i2c_bus_load(f, s->bus);
i2c_slave_load(f, &s->slave);
return 0;
}
@@ -1488,6 +1489,7 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
qemu_irq irq, uint32_t page_size)
{
int iomemtype;
+ /* FIXME: Should the slave device really be on a separate bus? */
struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *)
i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s));
@@ -1502,7 +1504,7 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
pxa2xx_i2c_writefn, s);
cpu_register_physical_memory(s->base & ~page_size, page_size, iomemtype);
- register_savevm("pxa2xx_i2c", base, 0,
+ register_savevm("pxa2xx_i2c", base, 1,
pxa2xx_i2c_save, pxa2xx_i2c_load, s);
return s;
@@ -2046,9 +2048,6 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load,
- s->env);
-
s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
/* SDRAM & Internal Memory Storage */
@@ -2173,9 +2172,6 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load,
- s->env);
-
s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
/* SDRAM & Internal Memory Storage */
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 7203a3fb6..5e834fe76 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -23,6 +23,7 @@ struct pxa2xx_lcdc_s {
int invalidated;
DisplayState *ds;
+ QEMUConsole *console;
drawfn *line_fn[2];
int dest_width;
int xres, yres;
@@ -794,9 +795,9 @@ static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
if (width != s->xres || height != s->yres) {
if (s->orientation)
- dpy_resize(s->ds, height, width);
+ qemu_console_resize(s->console, height, width);
else
- dpy_resize(s->ds, width, height);
+ qemu_console_resize(s->console, width, height);
s->invalidated = 1;
s->xres = width;
s->yres = height;
@@ -1001,8 +1002,9 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq,
pxa2xx_lcdc_writefn, s);
cpu_register_physical_memory(base, 0x00100000, iomemtype);
- graphic_console_init(ds, pxa2xx_update_display,
- pxa2xx_invalidate_display, pxa2xx_screen_dump, NULL, s);
+ s->console = graphic_console_init(ds, pxa2xx_update_display,
+ pxa2xx_invalidate_display,
+ pxa2xx_screen_dump, NULL, s);
switch (s->ds->depth) {
case 0:
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c7c91c99e..7e5204866 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -532,7 +532,76 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
outbuf[2] = 0x80; /* Readonly. */
}
p += 4;
- if ((page == 8 || page == 0x3f)) {
+ if (page == 4) {
+ int cylinders, heads, secs;
+
+ /* Rigid disk device geometry page. */
+ p[0] = 4;
+ p[1] = 0x16;
+ /* if a geometry hint is available, use it */
+ bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs);
+ p[2] = (cylinders >> 16) & 0xff;
+ p[3] = (cylinders >> 8) & 0xff;
+ p[4] = cylinders & 0xff;
+ p[5] = heads & 0xff;
+ /* Write precomp start cylinder, disabled */
+ p[6] = (cylinders >> 16) & 0xff;
+ p[7] = (cylinders >> 8) & 0xff;
+ p[8] = cylinders & 0xff;
+ /* Reduced current start cylinder, disabled */
+ p[9] = (cylinders >> 16) & 0xff;
+ p[10] = (cylinders >> 8) & 0xff;
+ p[11] = cylinders & 0xff;
+ /* Device step rate [ns], 200ns */
+ p[12] = 0;
+ p[13] = 200;
+ /* Landing zone cylinder */
+ p[14] = 0xff;
+ p[15] = 0xff;
+ p[16] = 0xff;
+ /* Medium rotation rate [rpm], 5400 rpm */
+ p[20] = (5400 >> 8) & 0xff;
+ p[21] = 5400 & 0xff;
+ p += 0x16;
+ } else if (page == 5) {
+ int cylinders, heads, secs;
+
+ /* Flexible disk device geometry page. */
+ p[0] = 5;
+ p[1] = 0x1e;
+ /* Transfer rate [kbit/s], 5Mbit/s */
+ p[2] = 5000 >> 8;
+ p[3] = 5000 & 0xff;
+ /* if a geometry hint is available, use it */
+ bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs);
+ p[4] = heads & 0xff;
+ p[5] = secs & 0xff;
+ p[6] = s->cluster_size * 2;
+ p[8] = (cylinders >> 8) & 0xff;
+ p[9] = cylinders & 0xff;
+ /* Write precomp start cylinder, disabled */
+ p[10] = (cylinders >> 8) & 0xff;
+ p[11] = cylinders & 0xff;
+ /* Reduced current start cylinder, disabled */
+ p[12] = (cylinders >> 8) & 0xff;
+ p[13] = cylinders & 0xff;
+ /* Device step rate [100us], 100us */
+ p[14] = 0;
+ p[15] = 1;
+ /* Device step pulse width [us], 1us */
+ p[16] = 1;
+ /* Device head settle delay [100us], 100us */
+ p[17] = 0;
+ p[18] = 1;
+ /* Motor on delay [0.1s], 0.1s */
+ p[19] = 1;
+ /* Motor off delay [0.1s], 0.1s */
+ p[20] = 1;
+ /* Medium rotation rate [rpm], 5400 rpm */
+ p[28] = (5400 >> 8) & 0xff;
+ p[29] = 5400 & 0xff;
+ p += 0x1e;
+ } else if ((page == 8 || page == 0x3f)) {
/* Caching page. */
memset(p,0,20);
p[0] = 8;
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
index 1ef3c119e..9f5843af6 100644
--- a/hw/slavio_serial.c
+++ b/hw/slavio_serial.c
@@ -260,8 +260,7 @@ static uint32_t get_queue(void *opaque)
static int slavio_serial_update_irq_chn(ChannelState *s)
{
- if ((s->wregs[W_INTR] & INTR_INTALL) && // interrupts enabled
- (((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+ if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
// tx ints enabled, pending
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
@@ -529,10 +528,10 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr,
default:
break;
case MINTR_RST_B:
- slavio_serial_reset_chn(&serial->chn[1]);
+ slavio_serial_reset_chn(&serial->chn[0]);
return;
case MINTR_RST_A:
- slavio_serial_reset_chn(&serial->chn[0]);
+ slavio_serial_reset_chn(&serial->chn[1]);
return;
case MINTR_RST_ALL:
slavio_serial_reset(serial);
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index daa92924a..b0b099f0d 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -45,6 +45,7 @@ enum ssd0303_cmd {
typedef struct {
i2c_slave i2c;
DisplayState *ds;
+ QEMUConsole *console;
int row;
int col;
int start_line;
@@ -202,55 +203,57 @@ static void ssd0303_update_display(void *opaque)
int dest_width;
uint8_t mask;
- if (s->redraw) {
- switch (s->ds->depth) {
- case 0:
- return;
- case 15:
- dest_width = 2;
- break;
- case 16:
- dest_width = 2;
- break;
- case 24:
- dest_width = 3;
- break;
- case 32:
- dest_width = 4;
- break;
- default:
- BADF("Bad color depth\n");
- return;
- }
- dest_width *= MAGNIFY;
- memset(colortab, 0xff, dest_width);
- memset(colortab + dest_width, 0, dest_width);
- if (s->flash) {
- colors[0] = colortab;
- colors[1] = colortab;
- } else if (s->inverse) {
- colors[0] = colortab;
- colors[1] = colortab + dest_width;
- } else {
- colors[0] = colortab + dest_width;
- colors[1] = colortab;
+ if (!s->redraw)
+ return;
+
+ switch (s->ds->depth) {
+ case 0:
+ return;
+ case 15:
+ dest_width = 2;
+ break;
+ case 16:
+ dest_width = 2;
+ break;
+ case 24:
+ dest_width = 3;
+ break;
+ case 32:
+ dest_width = 4;
+ break;
+ default:
+ BADF("Bad color depth\n");
+ return;
+ }
+ dest_width *= MAGNIFY;
+ memset(colortab, 0xff, dest_width);
+ memset(colortab + dest_width, 0, dest_width);
+ if (s->flash) {
+ colors[0] = colortab;
+ colors[1] = colortab;
+ } else if (s->inverse) {
+ colors[0] = colortab;
+ colors[1] = colortab + dest_width;
+ } else {
+ colors[0] = colortab + dest_width;
+ colors[1] = colortab;
+ }
+ dest = s->ds->data;
+ for (y = 0; y < 16; y++) {
+ line = (y + s->start_line) & 63;
+ src = s->framebuffer + 132 * (line >> 3) + 36;
+ mask = 1 << (line & 7);
+ for (x = 0; x < 96; x++) {
+ memcpy(dest, colors[(*src & mask) != 0], dest_width);
+ dest += dest_width;
+ src++;
}
- dest = s->ds->data;
- for (y = 0; y < 16; y++) {
- line = (y + s->start_line) & 63;
- src = s->framebuffer + 132 * (line >> 3) + 36;
- mask = 1 << (line & 7);
- for (x = 0; x < 96; x++) {
- memcpy(dest, colors[(*src & mask) != 0], dest_width);
- dest += dest_width;
- src++;
- }
- for (x = 1; x < MAGNIFY; x++) {
- memcpy(dest, dest - dest_width * 96, dest_width * 96);
- dest += dest_width * 96;
- }
+ for (x = 1; x < MAGNIFY; x++) {
+ memcpy(dest, dest - dest_width * 96, dest_width * 96);
+ dest += dest_width * 96;
}
}
+ s->redraw = 0;
dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
}
@@ -260,6 +263,49 @@ static void ssd0303_invalidate_display(void * opaque)
s->redraw = 1;
}
+static void ssd0303_save(QEMUFile *f, void *opaque)
+{
+ ssd0303_state *s = (ssd0303_state *)opaque;
+
+ qemu_put_be32(f, s->row);
+ qemu_put_be32(f, s->col);
+ qemu_put_be32(f, s->start_line);
+ qemu_put_be32(f, s->mirror);
+ qemu_put_be32(f, s->flash);
+ qemu_put_be32(f, s->enabled);
+ qemu_put_be32(f, s->inverse);
+ qemu_put_be32(f, s->redraw);
+ qemu_put_be32(f, s->mode);
+ qemu_put_be32(f, s->cmd_state);
+ qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+ i2c_slave_save(f, &s->i2c);
+}
+
+static int ssd0303_load(QEMUFile *f, void *opaque, int version_id)
+{
+ ssd0303_state *s = (ssd0303_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->row = qemu_get_be32(f);
+ s->col = qemu_get_be32(f);
+ s->start_line = qemu_get_be32(f);
+ s->mirror = qemu_get_be32(f);
+ s->flash = qemu_get_be32(f);
+ s->enabled = qemu_get_be32(f);
+ s->inverse = qemu_get_be32(f);
+ s->redraw = qemu_get_be32(f);
+ s->mode = qemu_get_be32(f);
+ s->cmd_state = qemu_get_be32(f);
+ qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+ i2c_slave_load(f, &s->i2c);
+
+ return 0;
+}
+
void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address)
{
ssd0303_state *s;
@@ -269,7 +315,9 @@ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address)
s->i2c.event = ssd0303_event;
s->i2c.recv = ssd0303_recv;
s->i2c.send = ssd0303_send;
- graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display,
- NULL, NULL, s);
- dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
+ s->console = graphic_console_init(ds, ssd0303_update_display,
+ ssd0303_invalidate_display,
+ NULL, NULL, s);
+ qemu_console_resize(s->console, 96 * MAGNIFY, 16 * MAGNIFY);
+ register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s);
}
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index e2e619f07..e496fe784 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -44,6 +44,7 @@ enum ssd0323_mode
typedef struct {
DisplayState *ds;
+ QEMUConsole *console;
int cmd_len;
int cmd;
@@ -183,78 +184,80 @@ static void ssd0323_update_display(void *opaque)
char *p;
int dest_width;
- if (s->redraw) {
+ if (!s->redraw)
+ return;
+
+ switch (s->ds->depth) {
+ case 0:
+ return;
+ case 15:
+ dest_width = 2;
+ break;
+ case 16:
+ dest_width = 2;
+ break;
+ case 24:
+ dest_width = 3;
+ break;
+ case 32:
+ dest_width = 4;
+ break;
+ default:
+ BADF("Bad color depth\n");
+ return;
+ }
+ p = colortab;
+ for (i = 0; i < 16; i++) {
+ int n;
+ colors[i] = p;
switch (s->ds->depth) {
- case 0:
- return;
case 15:
- dest_width = 2;
+ n = i * 2 + (i >> 3);
+ p[0] = n | (n << 5);
+ p[1] = (n << 2) | (n >> 3);
break;
case 16:
- dest_width = 2;
+ n = i * 2 + (i >> 3);
+ p[0] = n | (n << 6) | ((n << 1) & 0x20);
+ p[1] = (n << 3) | (n >> 2);
break;
case 24:
- dest_width = 3;
- break;
case 32:
- dest_width = 4;
+ n = (i << 4) | i;
+ p[0] = p[1] = p[2] = n;
break;
default:
BADF("Bad color depth\n");
return;
}
- p = colortab;
- for (i = 0; i < 16; i++) {
- int n;
- colors[i] = p;
- switch (s->ds->depth) {
- case 15:
- n = i * 2 + (i >> 3);
- p[0] = n | (n << 5);
- p[1] = (n << 2) | (n >> 3);
- break;
- case 16:
- n = i * 2 + (i >> 3);
- p[0] = n | (n << 6) | ((n << 1) & 0x20);
- p[1] = (n << 3) | (n >> 2);
- break;
- case 24:
- case 32:
- n = (i << 4) | i;
- p[0] = p[1] = p[2] = n;
- break;
- default:
- BADF("Bad color depth\n");
- return;
- }
- p += dest_width;
- }
- /* TODO: Implement row/column remapping. */
- dest = s->ds->data;
- for (y = 0; y < 64; y++) {
- line = y;
- src = s->framebuffer + 64 * line;
- for (x = 0; x < 64; x++) {
- int val;
- val = *src >> 4;
- for (i = 0; i < MAGNIFY; i++) {
- memcpy(dest, colors[val], dest_width);
- dest += dest_width;
- }
- val = *src & 0xf;
- for (i = 0; i < MAGNIFY; i++) {
- memcpy(dest, colors[val], dest_width);
- dest += dest_width;
- }
- src++;
+ p += dest_width;
+ }
+ /* TODO: Implement row/column remapping. */
+ dest = s->ds->data;
+ for (y = 0; y < 64; y++) {
+ line = y;
+ src = s->framebuffer + 64 * line;
+ for (x = 0; x < 64; x++) {
+ int val;
+ val = *src >> 4;
+ for (i = 0; i < MAGNIFY; i++) {
+ memcpy(dest, colors[val], dest_width);
+ dest += dest_width;
}
- for (i = 1; i < MAGNIFY; i++) {
- memcpy(dest, dest - dest_width * MAGNIFY * 128,
- dest_width * 128 * MAGNIFY);
- dest += dest_width * 128 * MAGNIFY;
+ val = *src & 0xf;
+ for (i = 0; i < MAGNIFY; i++) {
+ memcpy(dest, colors[val], dest_width);
+ dest += dest_width;
}
+ src++;
+ }
+ for (i = 1; i < MAGNIFY; i++) {
+ memcpy(dest, dest - dest_width * MAGNIFY * 128,
+ dest_width * 128 * MAGNIFY);
+ dest += dest_width * 128 * MAGNIFY;
}
}
+ s->redraw = 0;
dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
}
@@ -272,21 +275,71 @@ static void ssd0323_cd(void *opaque, int n, int level)
s->mode = level ? SSD0323_DATA : SSD0323_CMD;
}
+static void ssd0323_save(QEMUFile *f, void *opaque)
+{
+ ssd0323_state *s = (ssd0323_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->cmd_len);
+ qemu_put_be32(f, s->cmd);
+ for (i = 0; i < 8; i++)
+ qemu_put_be32(f, s->cmd_data[i]);
+ qemu_put_be32(f, s->row);
+ qemu_put_be32(f, s->row_start);
+ qemu_put_be32(f, s->row_end);
+ qemu_put_be32(f, s->col);
+ qemu_put_be32(f, s->col_start);
+ qemu_put_be32(f, s->col_end);
+ qemu_put_be32(f, s->redraw);
+ qemu_put_be32(f, s->remap);
+ qemu_put_be32(f, s->mode);
+ qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+}
+
+static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
+{
+ ssd0323_state *s = (ssd0323_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->cmd_len = qemu_get_be32(f);
+ s->cmd = qemu_get_be32(f);
+ for (i = 0; i < 8; i++)
+ s->cmd_data[i] = qemu_get_be32(f);
+ s->row = qemu_get_be32(f);
+ s->row_start = qemu_get_be32(f);
+ s->row_end = qemu_get_be32(f);
+ s->col = qemu_get_be32(f);
+ s->col_start = qemu_get_be32(f);
+ s->col_end = qemu_get_be32(f);
+ s->redraw = qemu_get_be32(f);
+ s->remap = qemu_get_be32(f);
+ s->mode = qemu_get_be32(f);
+ qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+ return 0;
+}
+
void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p)
{
ssd0323_state *s;
qemu_irq *cmd;
s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state));
- s->ds = ds;
- graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display,
- NULL, NULL, s);
- dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
s->col_end = 63;
s->row_end = 79;
+ s->ds = ds;
+ s->console = graphic_console_init(ds, ssd0323_update_display,
+ ssd0323_invalidate_display,
+ NULL, NULL, s);
+ qemu_console_resize(s->console, 128 * MAGNIFY, 64 * MAGNIFY);
cmd = qemu_allocate_irqs(ssd0323_cd, s, 1);
*cmd_p = *cmd;
+ register_savevm("ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s);
+
return s;
}
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 8b45fc4d1..1c57f1f2d 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -190,6 +190,43 @@ int ssi_sd_xfer(void *opaque, int val)
return 0xff;
}
+static void ssi_sd_save(QEMUFile *f, void *opaque)
+{
+ ssi_sd_state *s = (ssi_sd_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->mode);
+ qemu_put_be32(f, s->cmd);
+ for (i = 0; i < 4; i++)
+ qemu_put_be32(f, s->cmdarg[i]);
+ for (i = 0; i < 5; i++)
+ qemu_put_be32(f, s->response[i]);
+ qemu_put_be32(f, s->arglen);
+ qemu_put_be32(f, s->response_pos);
+ qemu_put_be32(f, s->stopping);
+}
+
+static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
+{
+ ssi_sd_state *s = (ssi_sd_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->mode = qemu_get_be32(f);
+ s->cmd = qemu_get_be32(f);
+ for (i = 0; i < 4; i++)
+ s->cmdarg[i] = qemu_get_be32(f);
+ for (i = 0; i < 5; i++)
+ s->response[i] = qemu_get_be32(f);
+ s->arglen = qemu_get_be32(f);
+ s->response_pos = qemu_get_be32(f);
+ s->stopping = qemu_get_be32(f);
+
+ return 0;
+}
+
void *ssi_sd_init(BlockDriverState *bs)
{
ssi_sd_state *s;
@@ -197,6 +234,7 @@ void *ssi_sd_init(BlockDriverState *bs)
s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state));
s->mode = SSI_SD_CMD;
s->sd = sd_init(bs, 1);
+ register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return s;
}
diff --git a/hw/stellaris.c b/hw/stellaris.c
index a32f86fe9..999cb5059 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -286,6 +286,65 @@ static CPUWriteMemoryFunc *gptm_writefn[] = {
gptm_write
};
+static void gptm_save(QEMUFile *f, void *opaque)
+{
+ gptm_state *s = (gptm_state *)opaque;
+
+ qemu_put_be32(f, s->config);
+ qemu_put_be32(f, s->mode[0]);
+ qemu_put_be32(f, s->mode[1]);
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->state);
+ qemu_put_be32(f, s->mask);
+ qemu_put_be32(f, s->mode[0]);
+ qemu_put_be32(f, s->mode[0]);
+ qemu_put_be32(f, s->load[0]);
+ qemu_put_be32(f, s->load[1]);
+ qemu_put_be32(f, s->match[0]);
+ qemu_put_be32(f, s->match[1]);
+ qemu_put_be32(f, s->prescale[0]);
+ qemu_put_be32(f, s->prescale[1]);
+ qemu_put_be32(f, s->match_prescale[0]);
+ qemu_put_be32(f, s->match_prescale[1]);
+ qemu_put_be32(f, s->rtc);
+ qemu_put_be64(f, s->tick[0]);
+ qemu_put_be64(f, s->tick[1]);
+ qemu_put_timer(f, s->timer[0]);
+ qemu_put_timer(f, s->timer[1]);
+}
+
+static int gptm_load(QEMUFile *f, void *opaque, int version_id)
+{
+ gptm_state *s = (gptm_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->config = qemu_get_be32(f);
+ s->mode[0] = qemu_get_be32(f);
+ s->mode[1] = qemu_get_be32(f);
+ s->control = qemu_get_be32(f);
+ s->state = qemu_get_be32(f);
+ s->mask = qemu_get_be32(f);
+ s->mode[0] = qemu_get_be32(f);
+ s->mode[0] = qemu_get_be32(f);
+ s->load[0] = qemu_get_be32(f);
+ s->load[1] = qemu_get_be32(f);
+ s->match[0] = qemu_get_be32(f);
+ s->match[1] = qemu_get_be32(f);
+ s->prescale[0] = qemu_get_be32(f);
+ s->prescale[1] = qemu_get_be32(f);
+ s->match_prescale[0] = qemu_get_be32(f);
+ s->match_prescale[1] = qemu_get_be32(f);
+ s->rtc = qemu_get_be32(f);
+ s->tick[0] = qemu_get_be64(f);
+ s->tick[1] = qemu_get_be64(f);
+ qemu_get_timer(f, s->timer[0]);
+ qemu_get_timer(f, s->timer[1]);
+
+ return 0;
+}
+
static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger)
{
int iomemtype;
@@ -302,7 +361,7 @@ static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger)
cpu_register_physical_memory(base, 0x00001000, iomemtype);
s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]);
s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]);
- /* ??? Save/restore. */
+ register_savevm("stellaris_gptm", -1, 1, gptm_save, gptm_load, s);
}
@@ -452,6 +511,11 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
}
}
+static void ssys_calculate_system_clock(ssys_state *s)
+{
+ system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+}
+
static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
{
ssys_state *s = (ssys_state *)opaque;
@@ -484,7 +548,7 @@ static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
s->int_status |= (1 << 6);
}
s->rcc = value;
- system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+ ssys_calculate_system_clock(s);
break;
case 0x100: /* RCGC0 */
s->rcgc[0] = value;
@@ -548,6 +612,58 @@ static void ssys_reset(void *opaque)
s->dcgc[0] = 1;
}
+static void ssys_save(QEMUFile *f, void *opaque)
+{
+ ssys_state *s = (ssys_state *)opaque;
+
+ qemu_put_be32(f, s->pborctl);
+ qemu_put_be32(f, s->ldopctl);
+ qemu_put_be32(f, s->int_mask);
+ qemu_put_be32(f, s->int_status);
+ qemu_put_be32(f, s->resc);
+ qemu_put_be32(f, s->rcc);
+ qemu_put_be32(f, s->rcgc[0]);
+ qemu_put_be32(f, s->rcgc[1]);
+ qemu_put_be32(f, s->rcgc[2]);
+ qemu_put_be32(f, s->scgc[0]);
+ qemu_put_be32(f, s->scgc[1]);
+ qemu_put_be32(f, s->scgc[2]);
+ qemu_put_be32(f, s->dcgc[0]);
+ qemu_put_be32(f, s->dcgc[1]);
+ qemu_put_be32(f, s->dcgc[2]);
+ qemu_put_be32(f, s->clkvclr);
+ qemu_put_be32(f, s->ldoarst);
+}
+
+static int ssys_load(QEMUFile *f, void *opaque, int version_id)
+{
+ ssys_state *s = (ssys_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->pborctl = qemu_get_be32(f);
+ s->ldopctl = qemu_get_be32(f);
+ s->int_mask = qemu_get_be32(f);
+ s->int_status = qemu_get_be32(f);
+ s->resc = qemu_get_be32(f);
+ s->rcc = qemu_get_be32(f);
+ s->rcgc[0] = qemu_get_be32(f);
+ s->rcgc[1] = qemu_get_be32(f);
+ s->rcgc[2] = qemu_get_be32(f);
+ s->scgc[0] = qemu_get_be32(f);
+ s->scgc[1] = qemu_get_be32(f);
+ s->scgc[2] = qemu_get_be32(f);
+ s->dcgc[0] = qemu_get_be32(f);
+ s->dcgc[1] = qemu_get_be32(f);
+ s->dcgc[2] = qemu_get_be32(f);
+ s->clkvclr = qemu_get_be32(f);
+ s->ldoarst = qemu_get_be32(f);
+ ssys_calculate_system_clock(s);
+
+ return 0;
+}
+
static void stellaris_sys_init(uint32_t base, qemu_irq irq,
stellaris_board_info * board,
uint8_t *macaddr)
@@ -567,7 +683,7 @@ static void stellaris_sys_init(uint32_t base, qemu_irq irq,
ssys_writefn, s);
cpu_register_physical_memory(base, 0x00001000, iomemtype);
ssys_reset(s);
- /* ??? Save/restore. */
+ register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
}
@@ -737,6 +853,37 @@ static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = {
stellaris_i2c_write
};
+static void stellaris_i2c_save(QEMUFile *f, void *opaque)
+{
+ stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+ qemu_put_be32(f, s->msa);
+ qemu_put_be32(f, s->mcs);
+ qemu_put_be32(f, s->mdr);
+ qemu_put_be32(f, s->mtpr);
+ qemu_put_be32(f, s->mimr);
+ qemu_put_be32(f, s->mris);
+ qemu_put_be32(f, s->mcr);
+}
+
+static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+ stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->msa = qemu_get_be32(f);
+ s->mcs = qemu_get_be32(f);
+ s->mdr = qemu_get_be32(f);
+ s->mtpr = qemu_get_be32(f);
+ s->mimr = qemu_get_be32(f);
+ s->mris = qemu_get_be32(f);
+ s->mcr = qemu_get_be32(f);
+
+ return 0;
+}
+
static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus)
{
stellaris_i2c_state *s;
@@ -752,6 +899,8 @@ static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus)
cpu_register_physical_memory(base, 0x00001000, iomemtype);
/* ??? For now we only implement the master interface. */
stellaris_i2c_reset(s);
+ register_savevm("stellaris_i2c", -1, 1,
+ stellaris_i2c_save, stellaris_i2c_load, s);
}
/* Analogue to Digital Converter. This is only partially implemented,
@@ -785,6 +934,7 @@ typedef struct
} fifo[4];
uint32_t ssmux[4];
uint32_t ssctl[4];
+ uint32_t noise;
qemu_irq irq;
} stellaris_adc_state;
@@ -833,17 +983,16 @@ static void stellaris_adc_update(stellaris_adc_state *s)
static void stellaris_adc_trigger(void *opaque, int irq, int level)
{
stellaris_adc_state *s = (stellaris_adc_state *)opaque;
- /* Some applications use the ADC as a random number source, so introduce
- some variation into the signal. */
- static uint32_t noise = 0;
if ((s->actss & 1) == 0) {
return;
}
- noise = noise * 314159 + 1;
+ /* Some applications use the ADC as a random number source, so introduce
+ some variation into the signal. */
+ s->noise = s->noise * 314159 + 1;
/* ??? actual inputs not implemented. Return an arbitrary value. */
- stellaris_adc_fifo_write(s, 0, 0x200 + ((noise >> 16) & 7));
+ stellaris_adc_fifo_write(s, 0, 0x200 + ((s->noise >> 16) & 7));
s->ris |= 1;
stellaris_adc_update(s);
}
@@ -983,6 +1132,61 @@ static CPUWriteMemoryFunc *stellaris_adc_writefn[] = {
stellaris_adc_write
};
+static void stellaris_adc_save(QEMUFile *f, void *opaque)
+{
+ stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+ int i;
+ int j;
+
+ qemu_put_be32(f, s->actss);
+ qemu_put_be32(f, s->ris);
+ qemu_put_be32(f, s->im);
+ qemu_put_be32(f, s->emux);
+ qemu_put_be32(f, s->ostat);
+ qemu_put_be32(f, s->ustat);
+ qemu_put_be32(f, s->sspri);
+ qemu_put_be32(f, s->sac);
+ for (i = 0; i < 4; i++) {
+ qemu_put_be32(f, s->fifo[i].state);
+ for (j = 0; j < 16; j++) {
+ qemu_put_be32(f, s->fifo[i].data[j]);
+ }
+ qemu_put_be32(f, s->ssmux[i]);
+ qemu_put_be32(f, s->ssctl[i]);
+ }
+ qemu_put_be32(f, s->noise);
+}
+
+static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
+{
+ stellaris_adc_state *s = (stellaris_adc_state *)opaque;
+ int i;
+ int j;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->actss = qemu_get_be32(f);
+ s->ris = qemu_get_be32(f);
+ s->im = qemu_get_be32(f);
+ s->emux = qemu_get_be32(f);
+ s->ostat = qemu_get_be32(f);
+ s->ustat = qemu_get_be32(f);
+ s->sspri = qemu_get_be32(f);
+ s->sac = qemu_get_be32(f);
+ for (i = 0; i < 4; i++) {
+ s->fifo[i].state = qemu_get_be32(f);
+ for (j = 0; j < 16; j++) {
+ s->fifo[i].data[j] = qemu_get_be32(f);
+ }
+ s->ssmux[i] = qemu_get_be32(f);
+ s->ssctl[i] = qemu_get_be32(f);
+ }
+ s->noise = qemu_get_be32(f);
+
+ return 0;
+}
+
static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq)
{
stellaris_adc_state *s;
@@ -998,6 +1202,8 @@ static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq)
cpu_register_physical_memory(base, 0x00001000, iomemtype);
stellaris_adc_reset(s);
qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1);
+ register_savevm("stellaris_adc", -1, 1,
+ stellaris_adc_save, stellaris_adc_load, s);
return qi[0];
}
@@ -1029,6 +1235,25 @@ static int stellaris_ssi_bus_xfer(void *opaque, int val)
return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val);
}
+static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque)
+{
+ stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
+
+ qemu_put_be32(f, s->current_dev);
+}
+
+static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id)
+{
+ stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->current_dev = qemu_get_be32(f);
+
+ return 0;
+}
+
static void *stellaris_ssi_bus_init(qemu_irq *irqp,
ssi_xfer_cb cb0, void *opaque0,
ssi_xfer_cb cb1, void *opaque1)
@@ -1043,6 +1268,8 @@ static void *stellaris_ssi_bus_init(qemu_irq *irqp,
s->opaque[1] = opaque1;
qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1);
*irqp = *qi;
+ register_savevm("stellaris_ssi_bus", -1, 1,
+ stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
return s;
}
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 31711b9d6..8057f80f3 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -326,6 +326,67 @@ static void stellaris_enet_reset(stellaris_enet_state *s)
s->tx_frame_len = -1;
}
+static void stellaris_enet_save(QEMUFile *f, void *opaque)
+{
+ stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->ris);
+ qemu_put_be32(f, s->im);
+ qemu_put_be32(f, s->rctl);
+ qemu_put_be32(f, s->tctl);
+ qemu_put_be32(f, s->thr);
+ qemu_put_be32(f, s->mctl);
+ qemu_put_be32(f, s->mdv);
+ qemu_put_be32(f, s->mtxd);
+ qemu_put_be32(f, s->mrxd);
+ qemu_put_be32(f, s->np);
+ qemu_put_be32(f, s->tx_frame_len);
+ qemu_put_be32(f, s->tx_fifo_len);
+ qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+ for (i = 0; i < 31; i++) {
+ qemu_put_be32(f, s->rx[i].len);
+ qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+ }
+ qemu_put_be32(f, s->next_packet);
+ qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
+ qemu_put_be32(f, s->rx_fifo_len);
+}
+
+static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
+{
+ stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->ris = qemu_get_be32(f);
+ s->im = qemu_get_be32(f);
+ s->rctl = qemu_get_be32(f);
+ s->tctl = qemu_get_be32(f);
+ s->thr = qemu_get_be32(f);
+ s->mctl = qemu_get_be32(f);
+ s->mdv = qemu_get_be32(f);
+ s->mtxd = qemu_get_be32(f);
+ s->mrxd = qemu_get_be32(f);
+ s->np = qemu_get_be32(f);
+ s->tx_frame_len = qemu_get_be32(f);
+ s->tx_fifo_len = qemu_get_be32(f);
+ qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+ for (i = 0; i < 31; i++) {
+ s->rx[i].len = qemu_get_be32(f);
+ qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+ }
+ s->next_packet = qemu_get_be32(f);
+ s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
+ s->rx_fifo_len = qemu_get_be32(f);
+
+ return 0;
+}
+
void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq)
{
stellaris_enet_state *s;
@@ -344,4 +405,6 @@ void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq)
stellaris_enet_can_receive, s);
stellaris_enet_reset(s);
+ register_savevm("stellaris_enet", -1, 1,
+ stellaris_enet_save, stellaris_enet_load, s);
}
diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c
index 461868b2e..aef4ce0c6 100644
--- a/hw/stellaris_input.c
+++ b/hw/stellaris_input.c
@@ -47,6 +47,31 @@ static void stellaris_gamepad_put_key(void * opaque, int keycode)
s->extension = 0;
}
+static void stellaris_gamepad_save(QEMUFile *f, void *opaque)
+{
+ gamepad_state *s = (gamepad_state *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->extension);
+ for (i = 0; i < s->num_buttons; i++)
+ qemu_put_byte(f, s->buttons[i].pressed);
+}
+
+static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id)
+{
+ gamepad_state *s = (gamepad_state *)opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ s->extension = qemu_get_be32(f);
+ for (i = 0; i < s->num_buttons; i++)
+ s->buttons[i].pressed = qemu_get_byte(f);
+
+ return 0;
+}
+
/* Returns an array 5 ouput slots. */
void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
{
@@ -61,6 +86,8 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
}
s->num_buttons = n;
qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
+ register_savevm("stellaris_gamepad", -1, 1,
+ stellaris_gamepad_save, stellaris_gamepad_load, s);
}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index e1ff225e3..899e2d506 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -426,7 +426,6 @@ static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size,
qemu_register_reset(secondary_cpu_reset, env);
env->halted = 1;
}
- register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS);
env->prom_addr = hwdef->slavio_base;
}
@@ -601,7 +600,6 @@ static void sun4c_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size,
cpu_sparc_set_id(env, 0);
qemu_register_reset(main_cpu_reset, env);
- register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
env->prom_addr = hwdef->slavio_base;
@@ -1413,7 +1411,6 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
qemu_register_reset(secondary_cpu_reset, env);
env->halted = 1;
}
- register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS);
env->prom_addr = hwdef->slavio_base;
}
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 985efd9dd..91e64c3cc 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -282,7 +282,6 @@ static void sun4u_init(ram_addr_t RAM_size, int vga_ram_size,
bh = qemu_bh_new(hstick_irq, env);
env->hstick = ptimer_init(bh);
ptimer_set_period(env->hstick, 1ULL);
- register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
main_cpu_reset(env);
diff --git a/hw/tcx.c b/hw/tcx.c
index a63b44188..df02ea74e 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -36,6 +36,7 @@
typedef struct TCXState {
target_phys_addr_t addr;
DisplayState *ds;
+ QEMUConsole *console;
uint8_t *vram;
uint32_t *vram24, *cplane;
ram_addr_t vram_offset, vram24_offset, cplane_offset;
@@ -186,8 +187,6 @@ static void tcx_update_display(void *opaque)
if (ts->ds->depth == 0)
return;
- if (ts->ds->width != ts->width || ts->ds->height != ts->height)
- dpy_resize(ts->ds, ts->width, ts->height);
page = ts->vram_offset;
y_start = -1;
page_min = 0xffffffff;
@@ -266,8 +265,6 @@ static void tcx24_update_display(void *opaque)
if (ts->ds->depth != 32)
return;
- if (ts->ds->width != ts->width || ts->ds->height != ts->height)
- dpy_resize(ts->ds, ts->width, ts->height);
page = ts->vram_offset;
page24 = ts->vram24_offset;
cpage = ts->cplane_offset;
@@ -541,14 +538,15 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
s->cplane = (uint32_t *)vram_base;
s->cplane_offset = vram_offset;
cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset);
- graphic_console_init(s->ds, tcx24_update_display,
- tcx24_invalidate_display,
- tcx24_screen_dump, NULL, s);
+ s->console = graphic_console_init(s->ds, tcx24_update_display,
+ tcx24_invalidate_display,
+ tcx24_screen_dump, NULL, s);
} else {
cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8,
dummy_memory);
- graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
- tcx_screen_dump, NULL, s);
+ s->console = graphic_console_init(s->ds, tcx_update_display,
+ tcx_invalidate_display,
+ tcx_screen_dump, NULL, s);
}
// NetBSD writes here even with 8-bit display
cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24,
@@ -557,7 +555,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
register_savevm("tcx", addr, 4, tcx_save, tcx_load, s);
qemu_register_reset(tcx_reset, s);
tcx_reset(s);
- dpy_resize(s->ds, width, height);
+ qemu_console_resize(s->console, width, height);
}
static void tcx_screen_dump(void *opaque, const char *filename)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index da26e4671..a4a0103d7 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -228,8 +228,6 @@ void tmp105_reset(i2c_slave *i2c)
tmp105_interrupt_update(s);
}
-static int tmp105_iid = 0;
-
struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm)
{
struct tmp105_s *s = (struct tmp105_s *)
@@ -242,8 +240,7 @@ struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm)
tmp105_reset(&s->i2c);
- register_savevm("TMP105", tmp105_iid ++, 0,
- tmp105_save, tmp105_load, s);
+ register_savevm("TMP105", -1, 0, tmp105_save, tmp105_load, s);
return &s->i2c;
}
diff --git a/hw/tsc2005.c b/hw/tsc2005.c
index 7708a36d5..f7a35b2d9 100644
--- a/hw/tsc2005.c
+++ b/hw/tsc2005.c
@@ -520,8 +520,6 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int tsc2005_iid = 0;
-
void *tsc2005_init(qemu_irq pintdav)
{
struct tsc2005_state_s *s;
@@ -551,8 +549,7 @@ void *tsc2005_init(qemu_irq pintdav)
"QEMU TSC2005-driven Touchscreen");
qemu_register_reset((void *) tsc2005_reset, s);
- register_savevm("tsc2005", tsc2005_iid ++, 0,
- tsc2005_save, tsc2005_load, s);
+ register_savevm("tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
return s;
}
diff --git a/hw/tsc210x.c b/hw/tsc210x.c
index f15aebaf1..97c21ef02 100644
--- a/hw/tsc210x.c
+++ b/hw/tsc210x.c
@@ -1107,8 +1107,6 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int tsc2102_iid = 0;
-
struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio)
{
struct tsc210x_state_s *s;
@@ -1154,7 +1152,7 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio)
AUD_register_card(s->audio, s->name, &s->card);
qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(s->name, tsc2102_iid ++, 0,
+ register_savevm(s->name, -1, 0,
tsc210x_save, tsc210x_load, s);
return &s->chip;
@@ -1208,8 +1206,7 @@ struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq,
AUD_register_card(s->audio, s->name, &s->card);
qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(s->name, tsc2102_iid ++, 0,
- tsc210x_save, tsc210x_load, s);
+ register_savevm(s->name, -1, 0, tsc210x_save, tsc210x_load, s);
return &s->chip;
}
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 8d0ce5da6..8fad96902 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -876,8 +876,6 @@ static int menelaus_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int menelaus_iid = 0;
-
i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq)
{
struct menelaus_s *s = (struct menelaus_s *)
@@ -894,8 +892,7 @@ i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq)
menelaus_reset(&s->i2c);
- register_savevm("menelaus", menelaus_iid ++,
- 0, menelaus_save, menelaus_load, s);
+ register_savevm("menelaus", -1, 0, menelaus_save, menelaus_load, s);
return &s->i2c;
}
diff --git a/hw/vga.c b/hw/vga.c
index 52749e30a..a059e32a3 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1158,7 +1158,7 @@ static void vga_draw_text(VGAState *s, int full_update)
cw != s->last_cw || cheight != s->last_ch) {
s->last_scr_width = width * cw;
s->last_scr_height = height * cheight;
- dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
+ qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height);
s->last_width = width;
s->last_height = height;
s->last_ch = cheight;
@@ -1527,7 +1527,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
if (disp_width != s->last_width ||
height != s->last_height) {
- dpy_resize(s->ds, disp_width, height);
+ qemu_console_resize(s->console, disp_width, height);
s->last_scr_width = disp_width;
s->last_scr_height = height;
s->last_width = disp_width;
@@ -1769,7 +1769,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
cw != s->last_cw || cheight != s->last_ch) {
s->last_scr_width = width * cw;
s->last_scr_height = height * cheight;
- dpy_resize(s->ds, width, height);
+ qemu_console_resize(s->console, width, height);
s->last_width = width;
s->last_height = height;
s->last_ch = cheight;
@@ -1849,7 +1849,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
s->last_width = 60;
s->last_height = height = 3;
dpy_cursor(s->ds, -1, -1);
- dpy_resize(s->ds, s->last_width, height);
+ qemu_console_resize(s->console, s->last_width, height);
for (dst = chardata, i = 0; i < s->last_width * height; i ++)
console_write_ch(dst ++, ' ');
@@ -2350,8 +2350,8 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
vga_init(s);
- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
- s->text_update, s);
+ s->console = graphic_console_init(s->ds, s->update, s->invalidate,
+ s->screen_dump, s->text_update, s);
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
@@ -2375,8 +2375,8 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
vga_mm_init(s, vram_base, ctrl_base, it_shift);
- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
- s->text_update, s);
+ s->console = graphic_console_init(s->ds, s->update, s->invalidate,
+ s->screen_dump, s->text_update, s);
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
@@ -2404,8 +2404,8 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
vga_init(s);
- graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
- s->text_update, s);
+ s->console = graphic_console_init(s->ds, s->update, s->invalidate,
+ s->screen_dump, s->text_update, s);
s->pci_dev = &d->dev;
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 02515ab04..8ede653db 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -121,6 +121,7 @@
VGA_STATE_COMMON_BOCHS_VBE \
/* display refresh support */ \
DisplayState *ds; \
+ QEMUConsole *console; \
uint32_t font_offsets[2]; \
int graphic_mode; \
uint8_t shift_control; \
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 2f9b15ccd..25c7915b4 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -57,6 +57,7 @@ struct vmsvga_state_s {
#ifndef EMBED_STDVGA
DisplayState *ds;
+ QEMUConsole *console;
int vram_size;
ram_addr_t vram_offset;
#endif
@@ -869,7 +870,7 @@ static inline void vmsvga_size(struct vmsvga_state_s *s)
if (s->new_width != s->width || s->new_height != s->height) {
s->width = s->new_width;
s->height = s->new_height;
- dpy_resize(s->ds, s->width, s->height);
+ qemu_console_resize(s->console, s->width, s->height);
s->invalidated = 1;
}
}
@@ -1122,9 +1123,10 @@ static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds,
vmsvga_reset(s);
- graphic_console_init(ds, vmsvga_update_display,
- vmsvga_invalidate_display, vmsvga_screen_dump,
- vmsvga_text_update, s);
+ s->console = graphic_console_init(ds, vmsvga_update_display,
+ vmsvga_invalidate_display,
+ vmsvga_screen_dump,
+ vmsvga_text_update, s);
#ifdef EMBED_STDVGA
vga_common_init((VGAState *) s, ds,
diff --git a/hw/wm8750.c b/hw/wm8750.c
index ee6790bb9..b175167ad 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -646,8 +646,6 @@ static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int wm8750_iid = 0;
-
i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
{
struct wm8750_s *s = (struct wm8750_s *)
@@ -659,7 +657,7 @@ i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
AUD_register_card(audio, CODEC, &s->card);
wm8750_reset(&s->i2c);
- register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
+ register_savevm(CODEC, -1, 0, wm8750_save, wm8750_load, s);
return &s->i2c;
}
diff --git a/keymaps/ja b/keymaps/ja
index 6947cb124..9d90a78c8 100644
--- a/keymaps/ja
+++ b/keymaps/ja
@@ -101,6 +101,7 @@ yen 0x7d
bar 0x7d shift
underscore 0x73 shift
Henkan_Mode 0x79
+Katakana_Real 0x70
Katakana 0x70
Muhenkan 0x7b
Henkan_Mode_Real 0x79
diff --git a/linux-user/main.c b/linux-user/main.c
index a4ffea3fd..060ef823e 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1779,8 +1779,8 @@ void cpu_loop(CPUMIPSState *env)
trapnr = cpu_mips_exec(env);
switch(trapnr) {
case EXCP_SYSCALL:
- syscall_num = env->gpr[env->current_tc][2] - 4000;
- env->PC[env->current_tc] += 4;
+ syscall_num = env->active_tc.gpr[2] - 4000;
+ env->active_tc.PC += 4;
if (syscall_num >= sizeof(mips_syscall_args)) {
ret = -ENOSYS;
} else {
@@ -1789,7 +1789,7 @@ void cpu_loop(CPUMIPSState *env)
abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
nb_args = mips_syscall_args[syscall_num];
- sp_reg = env->gpr[env->current_tc][29];
+ sp_reg = env->active_tc.gpr[29];
switch (nb_args) {
/* these arguments are taken from the stack */
/* FIXME - what to do if get_user() fails? */
@@ -1800,20 +1800,20 @@ void cpu_loop(CPUMIPSState *env)
default:
break;
}
- ret = do_syscall(env, env->gpr[env->current_tc][2],
- env->gpr[env->current_tc][4],
- env->gpr[env->current_tc][5],
- env->gpr[env->current_tc][6],
- env->gpr[env->current_tc][7],
+ ret = do_syscall(env, env->active_tc.gpr[2],
+ env->active_tc.gpr[4],
+ env->active_tc.gpr[5],
+ env->active_tc.gpr[6],
+ env->active_tc.gpr[7],
arg5, arg6/*, arg7, arg8*/);
}
if ((unsigned int)ret >= (unsigned int)(-1133)) {
- env->gpr[env->current_tc][7] = 1; /* error flag */
+ env->active_tc.gpr[7] = 1; /* error flag */
ret = -ret;
} else {
- env->gpr[env->current_tc][7] = 0; /* error flag */
+ env->active_tc.gpr[7] = 0; /* error flag */
}
- env->gpr[env->current_tc][2] = ret;
+ env->active_tc.gpr[2] = ret;
break;
case EXCP_TLBL:
case EXCP_TLBS:
@@ -2566,9 +2566,9 @@ int main(int argc, char **argv)
int i;
for(i = 0; i < 32; i++) {
- env->gpr[env->current_tc][i] = regs->regs[i];
+ env->active_tc.gpr[i] = regs->regs[i];
}
- env->PC[env->current_tc] = regs->cp0_epc;
+ env->active_tc.PC = regs->cp0_epc;
}
#elif defined(TARGET_SH4)
{
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index f3ef38d24..6e1dc8b6e 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -23,7 +23,7 @@ typedef struct target_sigaltstack {
static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
{
- return state->gpr[state->current_tc][29];
+ return state->active_tc.gpr[29];
}
#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h
index f3ef38d24..6e1dc8b6e 100644
--- a/linux-user/mips64/target_signal.h
+++ b/linux-user/mips64/target_signal.h
@@ -23,7 +23,7 @@ typedef struct target_sigaltstack {
static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
{
- return state->gpr[state->current_tc][29];
+ return state->active_tc.gpr[29];
}
#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mipsn32/target_signal.h b/linux-user/mipsn32/target_signal.h
index 5da84112b..ff20d9e33 100644
--- a/linux-user/mipsn32/target_signal.h
+++ b/linux-user/mipsn32/target_signal.h
@@ -23,7 +23,7 @@ typedef struct target_sigaltstack {
static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
{
- return state->gpr[state->current_tc][29];
+ return state->active_tc.gpr[29];
}
#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 623a5e31c..599b8af2c 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2290,10 +2290,10 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
{
int err = 0;
- err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc);
+ err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
-#define save_gp_reg(i) do { \
- err |= __put_user(regs->gpr[regs->current_tc][i], &sc->sc_regs[i]); \
+#define save_gp_reg(i) do { \
+ err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
} while(0)
__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
@@ -2306,8 +2306,8 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
save_gp_reg(31);
#undef save_gp_reg
- err |= __put_user(regs->HI[regs->current_tc][0], &sc->sc_mdhi);
- err |= __put_user(regs->LO[regs->current_tc][0], &sc->sc_mdlo);
+ err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
/* Not used yet, but might be useful if we ever have DSP suppport */
#if 0
@@ -2367,11 +2367,11 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
- err |= __get_user(regs->HI[regs->current_tc][0], &sc->sc_mdhi);
- err |= __get_user(regs->LO[regs->current_tc][0], &sc->sc_mdlo);
+ err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
#define restore_gp_reg(i) do { \
- err |= __get_user(regs->gpr[regs->current_tc][i], &sc->sc_regs[i]); \
+ err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
} while(0)
restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
@@ -2437,7 +2437,7 @@ get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
unsigned long sp;
/* Default to using normal stack */
- sp = regs->gpr[regs->current_tc][29];
+ sp = regs->active_tc.gpr[29];
/*
* FPU emulator may have it's own trampoline active just
@@ -2486,15 +2486,15 @@ static void setup_frame(int sig, struct target_sigaction * ka,
* $25 and PC point to the signal handler, $29 points to the
* struct sigframe.
*/
- regs->gpr[regs->current_tc][ 4] = sig;
- regs->gpr[regs->current_tc][ 5] = 0;
- regs->gpr[regs->current_tc][ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
- regs->gpr[regs->current_tc][29] = frame_addr;
- regs->gpr[regs->current_tc][31] = frame_addr + offsetof(struct sigframe, sf_code);
+ regs->active_tc.gpr[ 4] = sig;
+ regs->active_tc.gpr[ 5] = 0;
+ regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
+ regs->active_tc.gpr[29] = frame_addr;
+ regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
/* The original kernel code sets CP0_EPC to the handler
* since it returns to userland using eret
* we cannot do this here, and we must set PC directly */
- regs->PC[regs->current_tc] = regs->gpr[regs->current_tc][25] = ka->_sa_handler;
+ regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
unlock_user_struct(frame, frame_addr, 1);
return;
@@ -2515,7 +2515,7 @@ long do_sigreturn(CPUState *regs)
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "do_sigreturn\n");
#endif
- frame_addr = regs->gpr[regs->current_tc][29];
+ frame_addr = regs->active_tc.gpr[29];
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
goto badframe;
@@ -2542,7 +2542,7 @@ long do_sigreturn(CPUState *regs)
/* Unreached */
#endif
- regs->PC[regs->current_tc] = regs->CP0_EPC;
+ regs->active_tc.PC = regs->CP0_EPC;
/* I am not sure this is right, but it seems to work
* maybe a problem with nested signals ? */
regs->CP0_EPC = 0;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cd90946ae..839ac7f75 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3686,7 +3686,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
#if defined(TARGET_MIPS)
CPUMIPSState *env = (CPUMIPSState*)cpu_env;
- env->gpr[env->current_tc][3] = host_pipe[1];
+ env->active_tc.gpr[3] = host_pipe[1];
ret = host_pipe[0];
#elif defined(TARGET_SH4)
((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
diff --git a/monitor.c b/monitor.c
index e0d076c79..46d59981e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -323,7 +323,7 @@ static void do_info_cpus(void)
#elif defined(TARGET_SPARC)
term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
#elif defined(TARGET_MIPS)
- term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]);
+ term_printf(" PC=0x" TARGET_FMT_lx, env->active_tc.PC);
#endif
if (env->halted)
term_printf(" (halted)");
diff --git a/nbd.c b/nbd.c
index c7d63d348..e9308ee04 100644
--- a/nbd.c
+++ b/nbd.c
@@ -1,4 +1,4 @@
-/*\
+/*
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-\*/
+ */
#include "nbd.h"
@@ -25,22 +25,27 @@
#include <ctype.h>
#include <inttypes.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
+#if defined(QEMU_NBD)
extern int verbose;
+#else
+static int verbose = 0;
+#endif
+
+#define TRACE(msg, ...) do { \
+ if (verbose) LOG(msg, ## __VA_ARGS__); \
+} while(0)
#define LOG(msg, ...) do { \
fprintf(stderr, "%s:%s():L%d: " msg "\n", \
__FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
} while(0)
-#define TRACE(msg, ...) do { \
- if (verbose) LOG(msg, ## __VA_ARGS__); \
-} while(0)
-
/* This is all part of the "official" NBD API */
#define NBD_REQUEST_MAGIC 0x25609513
@@ -58,10 +63,10 @@ extern int verbose;
/* That's all folks */
-#define read_sync(fd, buffer, size) wr_sync(fd, buffer, size, true)
-#define write_sync(fd, buffer, size) wr_sync(fd, buffer, size, false)
+#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
+#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
-static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
{
size_t offset = 0;
@@ -75,7 +80,7 @@ static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
}
/* recoverable error */
- if (len == -1 && errno == EAGAIN) {
+ if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
continue;
}
@@ -95,7 +100,7 @@ static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
return offset;
}
-static int tcp_socket_outgoing(const char *address, uint16_t port)
+int tcp_socket_outgoing(const char *address, uint16_t port)
{
int s;
struct in_addr in;
@@ -183,6 +188,65 @@ error:
return -1;
}
+int unix_socket_incoming(const char *path)
+{
+ int s;
+ struct sockaddr_un addr;
+ int serrno;
+
+ s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ goto error;
+ }
+
+ if (listen(s, 128) == -1) {
+ goto error;
+ }
+
+ return s;
+error:
+ serrno = errno;
+ close(s);
+ errno = serrno;
+ return -1;
+}
+
+int unix_socket_outgoing(const char *path)
+{
+ int s;
+ struct sockaddr_un addr;
+ int serrno;
+
+ s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
+
+ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ goto error;
+ }
+
+ return s;
+error:
+ serrno = errno;
+ close(s);
+ errno = serrno;
+ return -1;
+}
+
+
/* Basic flow
Server Client
@@ -225,12 +289,10 @@ int nbd_negotiate(BlockDriverState *bs, int csock, off_t size)
return 0;
}
-int nbd_receive_negotiate(int fd, int csock)
+int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
{
char buf[8 + 8 + 8 + 128];
uint64_t magic;
- off_t size;
- size_t blocksize;
TRACE("Receiving negotation.");
@@ -241,8 +303,8 @@ int nbd_receive_negotiate(int fd, int csock)
}
magic = be64_to_cpup((uint64_t*)(buf + 8));
- size = be64_to_cpup((uint64_t*)(buf + 16));
- blocksize = 1024;
+ *size = be64_to_cpup((uint64_t*)(buf + 16));
+ *blocksize = 1024;
TRACE("Magic is %c%c%c%c%c%c%c%c",
isprint(buf[0]) ? buf[0] : '.',
@@ -254,7 +316,7 @@ int nbd_receive_negotiate(int fd, int csock)
isprint(buf[6]) ? buf[6] : '.',
isprint(buf[7]) ? buf[7] : '.');
TRACE("Magic is 0x%" PRIx64, magic);
- TRACE("Size is %" PRIu64, size);
+ TRACE("Size is %" PRIu64, *size);
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
@@ -269,7 +331,11 @@ int nbd_receive_negotiate(int fd, int csock)
errno = EINVAL;
return -1;
}
+ return 0;
+}
+int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+{
TRACE("Setting block size to %lu", (unsigned long)blocksize);
if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
@@ -342,20 +408,31 @@ int nbd_client(int fd, int csock)
return ret;
}
-int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly)
+int nbd_send_request(int csock, struct nbd_request *request)
{
-#ifndef _REENTRANT
- static uint8_t data[1024 * 1024]; // keep this off of the stack
-#else
- uint8_t data[1024 * 1024];
-#endif
uint8_t buf[4 + 4 + 8 + 8 + 4];
- uint32_t magic;
- uint32_t type;
- uint64_t from;
- uint32_t len;
- TRACE("Reading request.");
+ cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
+ cpu_to_be32w((uint32_t*)(buf + 4), request->type);
+ cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
+ cpu_to_be64w((uint64_t*)(buf + 16), request->from);
+ cpu_to_be32w((uint32_t*)(buf + 24), request->len);
+
+ TRACE("Sending request to client");
+
+ if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("writing to socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+
+static int nbd_receive_request(int csock, struct nbd_request *request)
+{
+ uint8_t buf[4 + 4 + 8 + 8 + 4];
+ uint32_t magic;
if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
LOG("read failed");
@@ -364,97 +441,159 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, o
}
/* Request
- [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
- [ 4 .. 7] type (0 == READ, 1 == WRITE)
- [ 8 .. 15] handle
- [16 .. 23] from
- [24 .. 27] len
+ [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
+ [ 4 .. 7] type (0 == READ, 1 == WRITE)
+ [ 8 .. 15] handle
+ [16 .. 23] from
+ [24 .. 27] len
*/
magic = be32_to_cpup((uint32_t*)buf);
- type = be32_to_cpup((uint32_t*)(buf + 4));
- from = be64_to_cpup((uint64_t*)(buf + 16));
- len = be32_to_cpup((uint32_t*)(buf + 24));
+ request->type = be32_to_cpup((uint32_t*)(buf + 4));
+ request->handle = be64_to_cpup((uint64_t*)(buf + 8));
+ request->from = be64_to_cpup((uint64_t*)(buf + 16));
+ request->len = be32_to_cpup((uint32_t*)(buf + 24));
TRACE("Got request: "
"{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
- magic, type, from, len);
-
+ magic, request->type, request->from, request->len);
if (magic != NBD_REQUEST_MAGIC) {
LOG("invalid magic (got 0x%x)", magic);
errno = EINVAL;
return -1;
}
+ return 0;
+}
+
+int nbd_receive_reply(int csock, struct nbd_reply *reply)
+{
+ uint8_t buf[4 + 4 + 8];
+ uint32_t magic;
+
+ memset(buf, 0xAA, sizeof(buf));
+
+ if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Reply
+ [ 0 .. 3] magic (NBD_REPLY_MAGIC)
+ [ 4 .. 7] error (0 == no error)
+ [ 7 .. 15] handle
+ */
+
+ magic = be32_to_cpup((uint32_t*)buf);
+ reply->error = be32_to_cpup((uint32_t*)(buf + 4));
+ reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
+
+ TRACE("Got reply: "
+ "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
+ magic, reply->error, reply->handle);
+
+ if (magic != NBD_REPLY_MAGIC) {
+ LOG("invalid magic (got 0x%x)", magic);
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+static int nbd_send_reply(int csock, struct nbd_reply *reply)
+{
+ uint8_t buf[4 + 4 + 8];
+
+ /* Reply
+ [ 0 .. 3] magic (NBD_REPLY_MAGIC)
+ [ 4 .. 7] error (0 == no error)
+ [ 7 .. 15] handle
+ */
+ cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
+ cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
+ cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
+
+ TRACE("Sending response to client");
+
+ if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("writing to socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
+ off_t *offset, bool readonly, uint8_t *data, int data_size)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+
+ TRACE("Reading request.");
+
+ if (nbd_receive_request(csock, &request) == -1)
+ return -1;
- if (len > sizeof(data)) {
+ if (request.len > data_size) {
LOG("len (%u) is larger than max len (%u)",
- len, sizeof(data));
+ request.len, data_size);
errno = EINVAL;
return -1;
}
- if ((from + len) < from) {
+ if ((request.from + request.len) < request.from) {
LOG("integer overflow detected! "
"you're probably being attacked");
errno = EINVAL;
return -1;
}
- if ((from + len) > size) {
+ if ((request.from + request.len) > size) {
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
", Offset: %" PRIu64 "\n",
- from, len, size, dev_offset);
+ request.from, request.len, size, dev_offset);
LOG("requested operation past EOF--bad client?");
errno = EINVAL;
return -1;
}
- /* Reply
- [ 0 .. 3] magic (NBD_REPLY_MAGIC)
- [ 4 .. 7] error (0 == no error)
- [ 7 .. 15] handle
- */
- cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
- cpu_to_be32w((uint32_t*)(buf + 4), 0);
-
TRACE("Decoding type");
- switch (type) {
- case 0:
+ reply.handle = request.handle;
+ reply.error = 0;
+
+ switch (request.type) {
+ case NBD_CMD_READ:
TRACE("Request type is READ");
- if (bdrv_read(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
+ if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
+ request.len / 512) == -1) {
LOG("reading from file failed");
errno = EINVAL;
return -1;
}
- *offset += len;
-
- TRACE("Read %u byte(s)", len);
+ *offset += request.len;
- TRACE("Sending OK response");
+ TRACE("Read %u byte(s)", request.len);
- if (write_sync(csock, buf, 16) != 16) {
- LOG("writing to socket failed");
- errno = EINVAL;
+ if (nbd_send_reply(csock, &reply) == -1)
return -1;
- }
TRACE("Sending data to client");
- if (write_sync(csock, data, len) != len) {
+ if (write_sync(csock, data, request.len) != request.len) {
LOG("writing to socket failed");
errno = EINVAL;
return -1;
}
break;
- case 1:
+ case NBD_CMD_WRITE:
TRACE("Request type is WRITE");
- TRACE("Reading %u byte(s)", len);
+ TRACE("Reading %u byte(s)", request.len);
- if (read_sync(csock, data, len) != len) {
+ if (read_sync(csock, data, request.len) != request.len) {
LOG("reading from socket failed");
errno = EINVAL;
return -1;
@@ -462,34 +601,29 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, o
if (readonly) {
TRACE("Server is read-only, return error");
-
- cpu_to_be32w((uint32_t*)(buf + 4), 1);
+ reply.error = 1;
} else {
TRACE("Writing to device");
- if (bdrv_write(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
+ if (bdrv_write(bs, (request.from + dev_offset) / 512,
+ data, request.len / 512) == -1) {
LOG("writing to file failed");
errno = EINVAL;
return -1;
}
- *offset += len;
+ *offset += request.len;
}
- TRACE("Sending response to client");
-
- if (write_sync(csock, buf, 16) != 16) {
- LOG("writing to socket failed");
- errno = EINVAL;
+ if (nbd_send_reply(csock, &reply) == -1)
return -1;
- }
break;
- case 2:
+ case NBD_CMD_DISC:
TRACE("Request type is DISCONNECT");
errno = 0;
return 1;
default:
- LOG("invalid request type (%u) received", type);
+ LOG("invalid request type (%u) received", request.type);
errno = EINVAL;
return -1;
}
diff --git a/nbd.h b/nbd.h
index 5e583540a..55ba1ba01 100644
--- a/nbd.h
+++ b/nbd.h
@@ -1,4 +1,4 @@
-/*\
+/*
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-\*/
+ */
#ifndef NBD_H
#define NBD_H
@@ -26,11 +26,37 @@
#include <qemu-common.h>
#include "block_int.h"
+struct nbd_request {
+ uint32_t type;
+ uint64_t handle;
+ uint64_t from;
+ uint32_t len;
+};
+
+struct nbd_reply {
+ uint32_t error;
+ uint64_t handle;
+};
+
+enum {
+ NBD_CMD_READ = 0,
+ NBD_CMD_WRITE = 1,
+ NBD_CMD_DISC = 2
+};
+
+size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+int tcp_socket_outgoing(const char *address, uint16_t port);
int tcp_socket_incoming(const char *address, uint16_t port);
+int unix_socket_outgoing(const char *path);
+int unix_socket_incoming(const char *path);
int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
-int nbd_receive_negotiate(int fd, int csock);
-int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly);
+int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize);
+int nbd_init(int fd, int csock, off_t size, size_t blocksize);
+int nbd_send_request(int csock, struct nbd_request *request);
+int nbd_receive_reply(int csock, struct nbd_reply *reply);
+int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
+ off_t *offset, bool readonly, uint8_t *data, int data_size);
int nbd_client(int fd, int csock);
int nbd_disconnect(int fd);
diff --git a/osdep.c b/osdep.c
index df8042627..30e03be44 100644
--- a/osdep.c
+++ b/osdep.c
@@ -185,7 +185,11 @@ void *qemu_vmalloc(size_t size)
#ifdef _BSD
return valloc(size);
#else
- return memalign(TARGET_PAGE_SIZE, size);
+#ifndef __ia64__
+ return memalign(4096, size);
+#else
+ return memalign(65536, size);
+#endif
#endif
}
diff --git a/qemu-common.h b/qemu-common.h
index bd328c51d..194d01c29 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -122,6 +122,7 @@ typedef struct AudioState AudioState;
typedef struct BlockDriverState BlockDriverState;
typedef struct DisplayState DisplayState;
typedef struct TextConsole TextConsole;
+typedef TextConsole QEMUConsole;
typedef struct CharDriverState CharDriverState;
typedef struct VLANState VLANState;
typedef struct QEMUFile QEMUFile;
@@ -135,4 +136,8 @@ typedef struct SerialState SerialState;
typedef struct IRQState *qemu_irq;
struct pcmcia_card_s;
+/* CPU save/load. */
+void cpu_save(QEMUFile *f, void *opaque);
+int cpu_load(QEMUFile *f, void *opaque, int version_id);
+
#endif
diff --git a/qemu-doc.texi b/qemu-doc.texi
index ac3c41718..612e5feb3 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -183,8 +183,8 @@ PCI UHCI USB controller and a virtual USB hub.
SMP is supported with up to 255 CPUs.
Note that adlib, ac97, gus and cs4231a are only available when QEMU
-was configured with --enable-adlib, --enable-ac97, --enable-gus or
---enable-cs4231a respectively.
+was configured with --audio-card-list option containing the name(s) of
+required card(s).
QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
VGA BIOS.
@@ -973,6 +973,17 @@ On M68K this implements the "ColdFire GDB" interface used by libgloss.
Note that this allows guest direct access to the host filesystem,
so should only be used with trusted guest OS.
+
+@item -icount [N|auto]
+Enable virtual instruction counter. The virtual cpu will execute one
+instruction every 2^N ns of virtual time. If @code{auto} is specified
+then the virtual cpu speed will be automatically adjusted to keep virtual
+time within a few seconds of real time.
+
+Note that while this option can give deterministic behavior, it does not
+provide cycle accurate emulation. Modern CPUs contain superscalar out of
+order cores with complex cache hierarchies. The number of instructions
+executed often has little or no correlation with actual performance.
@end table
@c man end
@@ -1315,8 +1326,10 @@ snapshots.
* disk_images_snapshot_mode:: Snapshot mode
* vm_snapshots:: VM snapshots
* qemu_img_invocation:: qemu-img Invocation
+* qemu_nbd_invocation:: qemu-nbd Invocation
* host_drives:: Using host drives
* disk_images_fat_images:: Virtual FAT disk images
+* disk_images_nbd:: NBD access
@end menu
@node disk_images_quickstart
@@ -1397,6 +1410,11 @@ state is not saved or restored properly (in particular USB).
@include qemu-img.texi
+@node qemu_nbd_invocation
+@subsection @code{qemu-nbd} Invocation
+
+@include qemu-nbd.texi
+
@node host_drives
@subsection Using host drives
@@ -1494,6 +1512,40 @@ What you should @emph{never} do:
@item write to the FAT directory on the host system while accessing it with the guest system.
@end itemize
+@node disk_images_nbd
+@subsection NBD access
+
+QEMU can access directly to block device exported using the Network Block Device
+protocol.
+
+@example
+qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
+@end example
+
+If the NBD server is located on the same host, you can use an unix socket instead
+of an inet socket:
+
+@example
+qemu linux.img -hdb nbd:unix:/tmp/my_socket
+@end example
+
+In this case, the block device must be exported using qemu-nbd:
+
+@example
+qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
+@end example
+
+The use of qemu-nbd allows to share a disk between several guests:
+@example
+qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
+@end example
+
+and then you can use it with two guests:
+@example
+qemu linux1.img -hdb nbd:unix:/tmp/my_socket
+qemu linux2.img -hdb nbd:unix:/tmp/my_socket
+@end example
+
@node pcsys_network
@section Network emulation
diff --git a/qemu-nbd.c b/qemu-nbd.c
index ff11cdc4b..45464a0c8 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -1,4 +1,4 @@
-/*\
+/*
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -21,44 +21,22 @@
#include "block_int.h"
#include "nbd.h"
-#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <getopt.h>
#include <err.h>
+#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <signal.h>
-int verbose;
-
-#ifdef _WIN32
-
-void *qemu_memalign(size_t alignment, size_t size)
-{
- return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
-}
-
-#else
+#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
-void *qemu_memalign(size_t alignment, size_t size)
-{
-#if defined(_POSIX_C_SOURCE)
- int ret;
- void *ptr;
- ret = posix_memalign(&ptr, alignment, size);
- if (ret != 0)
- return NULL;
- return ptr;
-#elif defined(_BSD)
- return valloc(size);
-#else
- return memalign(alignment, size);
-#endif
-}
+#define NBD_BUFFER_SIZE (1024*1024)
-#endif
+int verbose;
static void usage(const char *name)
{
@@ -69,14 +47,22 @@ static void usage(const char *name)
" -p, --port=PORT port to listen on (default `1024')\n"
" -o, --offset=OFFSET offset into the image\n"
" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n"
+" -k, --socket=PATH path to the unix socket\n"
+" (default '"SOCKET_PATH"')\n"
" -r, --read-only export read-only\n"
" -P, --partition=NUM only expose partition NUM\n"
+" -s, --snapshot use snapshot file\n"
+" -n, --nocache disable host cache\n"
+" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
+" -d, --disconnect disconnect the specified device\n"
+" -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
+" -t, --persistent don't exit on the last connection\n"
" -v, --verbose display extra debugging information\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
"\n"
"Report bugs to <anthony@codemonkey.ws>\n"
- , name);
+ , name, "DEVICE");
}
static void version(const char *name)
@@ -172,41 +158,81 @@ static int find_partition(BlockDriverState *bs, int partition,
return -1;
}
+static void show_parts(const char *device)
+{
+ if (fork() == 0) {
+ int nbd;
+
+ /* linux just needs an open() to trigger
+ * the partition table update
+ * but remember to load the module with max_part != 0 :
+ * modprobe nbd max_part=63
+ */
+ nbd = open(device, O_RDWR);
+ if (nbd != -1)
+ close(nbd);
+ exit(0);
+ }
+}
+
int main(int argc, char **argv)
{
BlockDriverState *bs;
off_t dev_offset = 0;
off_t offset = 0;
bool readonly = false;
+ bool disconnect = false;
const char *bindto = "0.0.0.0";
int port = 1024;
- int sock, csock;
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
off_t fd_size;
- const char *sopt = "hVbo:p:rsP:v";
+ char *device = NULL;
+ char *socket = NULL;
+ char sockpath[128];
+ const char *sopt = "hVbo:p:rsnP:c:dvk:e:t";
struct option lopt[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "bind", 1, 0, 'b' },
{ "port", 1, 0, 'p' },
+ { "socket", 1, 0, 'k' },
{ "offset", 1, 0, 'o' },
{ "read-only", 0, 0, 'r' },
{ "partition", 1, 0, 'P' },
+ { "connect", 1, 0, 'c' },
+ { "disconnect", 0, 0, 'd' },
{ "snapshot", 0, 0, 's' },
+ { "nocache", 0, 0, 'n' },
+ { "shared", 1, 0, 'e' },
+ { "persistent", 0, 0, 't' },
{ "verbose", 0, 0, 'v' },
+ { NULL, 0, 0, 0 }
};
int ch;
int opt_ind = 0;
int li;
char *end;
- bool snapshot = false;
+ int flags = 0;
int partition = -1;
+ int ret;
+ int shared = 1;
+ uint8_t *data;
+ fd_set fds;
+ int *sharing_fds;
+ int fd;
+ int i;
+ int nb_fds = 0;
+ int max_fd;
+ int persistent = 0;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
case 's':
- snapshot = true;
+ flags |= BDRV_O_SNAPSHOT;
+ break;
+ case 'n':
+ flags |= BDRV_O_DIRECT;
break;
case 'b':
bindto = optarg;
@@ -240,6 +266,29 @@ int main(int argc, char **argv)
if (partition < 1 || partition > 8)
errx(EINVAL, "Invalid partition %d", partition);
break;
+ case 'k':
+ socket = optarg;
+ if (socket[0] != '/')
+ errx(EINVAL, "socket path must be absolute\n");
+ break;
+ case 'd':
+ disconnect = true;
+ break;
+ case 'c':
+ device = optarg;
+ break;
+ case 'e':
+ shared = strtol(optarg, &end, 0);
+ if (*end) {
+ errx(EINVAL, "Invalid shared device number '%s'", optarg);
+ }
+ if (shared < 1) {
+ errx(EINVAL, "Shared device number must be greater than 0\n");
+ }
+ break;
+ case 't':
+ persistent = 1;
+ break;
case 'v':
verbose = 1;
break;
@@ -263,13 +312,27 @@ int main(int argc, char **argv)
argv[0]);
}
+ if (disconnect) {
+ fd = open(argv[optind], O_RDWR);
+ if (fd == -1)
+ errx(errno, "Cannot open %s", argv[optind]);
+
+ nbd_disconnect(fd);
+
+ close(fd);
+
+ printf("%s disconnected\n", argv[optind]);
+
+ return 0;
+ }
+
bdrv_init();
bs = bdrv_new("hda");
if (bs == NULL)
return 1;
- if (bdrv_open(bs, argv[optind], snapshot) == -1)
+ if (bdrv_open(bs, argv[optind], flags) == -1)
return 1;
fd_size = bs->total_sectors * 512;
@@ -278,25 +341,138 @@ int main(int argc, char **argv)
find_partition(bs, partition, &dev_offset, &fd_size))
errx(errno, "Could not find partition %d", partition);
- sock = tcp_socket_incoming(bindto, port);
- if (sock == -1)
- return 1;
+ if (device) {
+ pid_t pid;
+ int sock;
- csock = accept(sock,
- (struct sockaddr *)&addr,
- &addr_len);
- if (csock == -1)
- return 1;
+ if (!verbose)
+ daemon(0, 0); /* detach client and server */
- /* new fd_size is calculated by find_partition */
- if (nbd_negotiate(bs, csock, fd_size) == -1)
+ if (socket == NULL) {
+ sprintf(sockpath, SOCKET_PATH, basename(device));
+ socket = sockpath;
+ }
+
+ pid = fork();
+ if (pid < 0)
+ return 1;
+ if (pid != 0) {
+ off_t size;
+ size_t blocksize;
+
+ ret = 0;
+ bdrv_close(bs);
+
+ do {
+ sock = unix_socket_outgoing(socket);
+ if (sock == -1) {
+ if (errno != ENOENT && errno != ECONNREFUSED)
+ goto out;
+ sleep(1); /* wait children */
+ }
+ } while (sock == -1);
+
+ fd = open(device, O_RDWR);
+ if (fd == -1) {
+ ret = 1;
+ goto out;
+ }
+
+ ret = nbd_receive_negotiate(sock, &size, &blocksize);
+ if (ret == -1) {
+ ret = 1;
+ goto out;
+ }
+
+ ret = nbd_init(fd, sock, size, blocksize);
+ if (ret == -1) {
+ ret = 1;
+ goto out;
+ }
+
+ printf("NBD device %s is now connected to file %s\n",
+ device, argv[optind]);
+
+ /* update partition table */
+
+ show_parts(device);
+
+ nbd_client(fd, sock);
+ close(fd);
+ out:
+ kill(pid, SIGTERM);
+ unlink(socket);
+
+ return ret;
+ }
+ /* children */
+ }
+
+ sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
+ if (sharing_fds == NULL)
+ errx(ENOMEM, "Cannot allocate sharing fds");
+
+ if (socket) {
+ sharing_fds[0] = unix_socket_incoming(socket);
+ } else {
+ sharing_fds[0] = tcp_socket_incoming(bindto, port);
+ }
+
+ if (sharing_fds[0] == -1)
return 1;
+ max_fd = sharing_fds[0];
+ nb_fds++;
- while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly) == 0);
+ data = qemu_memalign(512, NBD_BUFFER_SIZE);
+ if (data == NULL)
+ errx(ENOMEM, "Cannot allocate data buffer");
+
+ do {
+
+ FD_ZERO(&fds);
+ for (i = 0; i < nb_fds; i++)
+ FD_SET(sharing_fds[i], &fds);
+
+ ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
+ if (ret == -1)
+ break;
+
+ if (FD_ISSET(sharing_fds[0], &fds))
+ ret--;
+ for (i = 1; i < nb_fds && ret; i++) {
+ if (FD_ISSET(sharing_fds[i], &fds)) {
+ if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
+ &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
+ close(sharing_fds[i]);
+ nb_fds--;
+ sharing_fds[i] = sharing_fds[nb_fds];
+ i--;
+ }
+ ret--;
+ }
+ }
+ /* new connection ? */
+ if (FD_ISSET(sharing_fds[0], &fds)) {
+ if (nb_fds < shared + 1) {
+ sharing_fds[nb_fds] = accept(sharing_fds[0],
+ (struct sockaddr *)&addr,
+ &addr_len);
+ if (sharing_fds[nb_fds] != -1 &&
+ nbd_negotiate(bs, sharing_fds[nb_fds], fd_size) != -1) {
+ if (sharing_fds[nb_fds] > max_fd)
+ max_fd = sharing_fds[nb_fds];
+ nb_fds++;
+ }
+ }
+ }
+ } while (persistent || nb_fds > 1);
+ qemu_free(data);
- close(csock);
- close(sock);
+ close(sharing_fds[0]);
bdrv_close(bs);
+ qemu_free(sharing_fds);
+ if (socket)
+ unlink(socket);
return 0;
}
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 7b6d0cbb5..ff2f20792 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -20,10 +20,24 @@ Export Qemu disk image using NBD protocol.
offset into the image
@item -b, --bind=IFACE
interface to bind to (default `0.0.0.0')
+@item -k, --socket=PATH
+ Use a unix socket with path PATH
@item -r, --read-only
export read-only
@item -P, --partition=NUM
only expose partition NUM
+@item -s, --snapshot
+ use snapshot file
+@item -n, --nocache
+ disable host cache
+@item -c, --connect
+ connect FILE to NBD device DEV
+@item -d, --disconnect
+ disconnect the specified device
+@item -e, --shared=NUM
+ device can be shared by NUM clients (default '1')
+@item -t, --persistent
+ don't exit on the last connection
@item -v, --verbose
display extra debugging information
@item -h, --help
diff --git a/softmmu_header.h b/softmmu_header.h
index 481051e68..512e5a2e4 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -231,8 +231,8 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
addr = ptr;
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = CPU_MMU_INDEX;
- if (__builtin_expect(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
- (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
+ if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
+ (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
} else {
physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
@@ -252,8 +252,8 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
addr = ptr;
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = CPU_MMU_INDEX;
- if (__builtin_expect(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
- (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
+ if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
+ (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
} else {
physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
@@ -277,8 +277,8 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
addr = ptr;
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = CPU_MMU_INDEX;
- if (__builtin_expect(env->tlb_table[mmu_idx][page_index].addr_write !=
- (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
+ if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write !=
+ (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx);
} else {
physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
diff --git a/softmmu_template.h b/softmmu_template.h
index 934df5286..98dd37881 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -51,12 +51,18 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
int mmu_idx,
void *retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
- target_ulong addr)
+ target_ulong addr,
+ void *retaddr)
{
DATA_TYPE res;
int index;
index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+ env->mem_io_pc = (unsigned long)retaddr;
+ if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
+ && !can_do_io(env)) {
+ cpu_io_recompile(env, retaddr);
+ }
#if SHIFT <= 2
res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
@@ -95,8 +101,9 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
+ retaddr = GETPC();
addend = env->iotlb[mmu_idx][index];
- res = glue(io_read, SUFFIX)(addend, addr);
+ res = glue(io_read, SUFFIX)(addend, addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
/* slow unaligned access (it spans two pages or IO) */
do_unaligned_access:
@@ -148,8 +155,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
+ retaddr = GETPC();
addend = env->iotlb[mmu_idx][index];
- res = glue(io_read, SUFFIX)(addend, addr);
+ res = glue(io_read, SUFFIX)(addend, addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access:
/* slow unaligned access (it spans two pages) */
@@ -194,9 +202,13 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
int index;
index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
+ if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
+ && !can_do_io(env)) {
+ cpu_io_recompile(env, retaddr);
+ }
- env->mem_write_vaddr = addr;
- env->mem_write_pc = (unsigned long)retaddr;
+ env->mem_io_vaddr = addr;
+ env->mem_io_pc = (unsigned long)retaddr;
#if SHIFT <= 2
io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
#else
diff --git a/sysemu.h b/sysemu.h
index 97d73e9b5..993d67b13 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -41,12 +41,6 @@ void qemu_system_powerdown(void);
#endif
void qemu_system_reset(void);
-void cpu_save(QEMUFile *f, void *opaque);
-int cpu_load(QEMUFile *f, void *opaque, int version_id);
-
-void qemu_get_launch_info(int *argc, char ***argv,
- int *opt_daemonize, const char **opt_incoming);
-
void do_savevm(const char *name);
void do_loadvm(const char *name);
void do_delvm(const char *name);
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index e9b2b0757..3d39888ae 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -282,11 +282,9 @@ struct CPUAlphaState {
/* Those resources are used only in Qemu core */
CPU_COMMON
- int user_mode_only; /* user mode only simulation */
uint32_t hflags;
int error_code;
- int interrupt_request;
uint32_t features;
uint32_t amask;
@@ -415,4 +413,6 @@ void cpu_loop_exit (void);
void pal_init (CPUState *env);
void call_pal (CPUState *env, int palcode);
+#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
+
#endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index a3991022e..9bf6163e6 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -43,6 +43,19 @@ struct DisasContext {
uint32_t amask;
};
+static TCGv cpu_env;
+
+#include "gen-icount.h"
+
+static void alpha_translate_init()
+{
+ static int done_init = 0;
+ if (done_init)
+ return;
+ cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
+ done_init = 1;
+}
+
static always_inline void gen_op_nop (void)
{
#if defined(GENERATE_NOP)
@@ -1970,6 +1983,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
uint16_t *gen_opc_end;
int j, lj = -1;
int ret;
+ int num_insns;
+ int max_insns;
pc_start = tb->pc;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -1981,6 +1996,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
ctx.mem_idx = ((env->ps >> 3) & 3);
ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
#endif
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+
+ gen_icount_start();
for (ret = 0; ret == 0;) {
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
@@ -1998,8 +2019,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = ctx.pc;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
#if defined ALPHA_DEBUG_DISAS
insn_count++;
if (logfile != NULL) {
@@ -2014,6 +2038,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
fprintf(logfile, "opcode %08x %d\n", insn, insn_count);
}
#endif
+ num_insns++;
ctx.pc += 4;
ret = translate_one(ctxp, insn);
if (ret != 0)
@@ -2022,7 +2047,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
* generation
*/
if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled)) {
+ (env->singlestep_enabled) ||
+ num_insns >= max_insns) {
break;
}
#if defined (DO_SINGLE_STEP)
@@ -2035,8 +2061,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
#if defined (DO_TB_FLUSH)
gen_op_tb_flush();
#endif
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
/* Generate the return instruction */
tcg_gen_exit_tb(0);
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (search_pc) {
j = gen_opc_ptr - gen_opc_buf;
@@ -2045,6 +2074,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = ctx.pc - pc_start;
+ tb->icount = num_insns;
}
#if defined ALPHA_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_CPU) {
@@ -2079,6 +2109,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
if (!env)
return NULL;
cpu_exec_init(env);
+ alpha_translate_init();
tlb_flush(env, 1);
/* XXX: should not be hardcoded */
env->implver = IMPLVER_2106x;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 5005bf6dd..ff765f783 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -156,10 +156,6 @@ typedef struct CPUARMState {
int (*get_irq_vector)(struct CPUARMState *);
void *irq_opaque;
- /* exception/interrupt handling */
- int interrupt_request;
- int user_mode_only;
-
/* VFP coprocessor state. */
struct {
float64 regs[32];
@@ -397,7 +393,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
-#define ARM_CPU_SAVE_VERSION 1
+#define CPU_SAVE_VERSION 1
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
@@ -417,6 +413,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) env->regs[15] = tb->pc
+
#include "cpu-all.h"
#endif
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 8e8543525..32c2c2e28 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -674,7 +674,7 @@ void do_interrupt_v7m(CPUARMState *env)
/* ??? Should only do this if Configuration Control Register
STACKALIGN bit is set. */
if (env->regs[13] & 4) {
- env->regs[13] += 4;
+ env->regs[13] -= 4;
xpsr |= 0x200;
}
/* Switch to the handler mode. */
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 6637e72ed..42ff5844c 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -120,7 +120,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
CPUARMState *env = (CPUARMState *)opaque;
int i;
- if (version_id != ARM_CPU_SAVE_VERSION)
+ if (version_id != CPU_SAVE_VERSION)
return -EINVAL;
for (i = 0; i < 16; i++) {
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 5d9fd8488..5b5581f2c 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -97,7 +97,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (__builtin_expect(ret, 0)) {
+ if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 91328c813..a3aabd26d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -84,6 +84,9 @@ static TCGv cpu_V0, cpu_V1, cpu_M0;
static TCGv cpu_T[2];
static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d;
+#define ICOUNT_TEMP cpu_T[0]
+#include "gen-icount.h"
+
/* initialize TCG globals. */
void arm_translate_init(void)
{
@@ -3390,7 +3393,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
- if (__builtin_expect(s->singlestep_enabled, 0)) {
+ if (unlikely(s->singlestep_enabled)) {
/* An indirect jump so that we still trigger the debug exception. */
if (s->thumb)
dest |= 1;
@@ -3754,6 +3757,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
} else /* size == 0 */ {
if (load) {
+ TCGV_UNUSED(tmp2);
for (n = 0; n < 4; n++) {
tmp = gen_ld8u(cpu_T[1], IS_USER(s));
gen_op_addl_T1_im(stride);
@@ -3809,6 +3813,8 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
break;
case 3:
return 1;
+ default: /* Avoid compiler warnings. */
+ abort();
}
gen_op_addl_T1_im(1 << size);
tmp2 = new_tmp();
@@ -3851,6 +3857,8 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 2:
tmp = gen_ld32(cpu_T[1], IS_USER(s));
break;
+ default: /* Avoid compiler warnings. */
+ abort();
}
if (size != 2) {
tmp2 = neon_load_reg(rd, pass);
@@ -4853,9 +4861,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
NEON_GET_REG(T0, rn, 1);
gen_neon_movl_scratch_T0(2);
}
+ TCGV_UNUSED(tmp3);
for (pass = 0; pass < 2; pass++) {
if (src1_wide) {
neon_load_reg64(cpu_V0, rn + pass);
+ TCGV_UNUSED(tmp);
} else {
if (pass == 1 && rd == rn) {
gen_neon_movl_T0_scratch(2);
@@ -4870,6 +4880,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
if (src2_wide) {
neon_load_reg64(cpu_V1, rm + pass);
+ TCGV_UNUSED(tmp2);
} else {
if (pass == 1 && rd == rm) {
gen_neon_movl_T0_scratch(2);
@@ -5281,6 +5292,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
if (size == 3)
return 1;
+ TCGV_UNUSED(tmp2);
for (pass = 0; pass < 2; pass++) {
neon_load_reg64(cpu_V0, rm + pass);
tmp = new_tmp();
@@ -6639,6 +6651,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
/* compute total size */
loaded_base = 0;
+ TCGV_UNUSED(loaded_var);
n = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i))
@@ -8336,6 +8349,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
tcg_gen_addi_i32(addr, addr, 4);
}
}
+ TCGV_UNUSED(tmp);
if (insn & (1 << 8)) {
if (insn & (1 << 11)) {
/* pop pc */
@@ -8539,6 +8553,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
int j, lj;
target_ulong pc_start;
uint32_t next_page_start;
+ int num_insns;
+ int max_insns;
/* generate intermediate code */
num_temps = 0;
@@ -8575,6 +8591,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
cpu_M0 = tcg_temp_new(TCG_TYPE_I64);
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+
+ gen_icount_start();
/* Reset the conditional execution bits immediately. This avoids
complications trying to do it at the end of the block. */
if (env->condexec_bits)
@@ -8625,8 +8647,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
}
gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
+
if (env->thumb) {
disas_thumb_insn(env, dc);
if (dc->condexec_mask) {
@@ -8658,15 +8684,26 @@ static inline int gen_intermediate_code_internal(CPUState *env,
/* Translation stops when a conditional branch is enoutered.
* Otherwise the subsequent code could get translated several times.
* Also stop translation when a page boundary is reached. This
- * ensures prefech aborts occur at the right place. */
+ * ensures prefetch aborts occur at the right place. */
+ num_insns ++;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&
- dc->pc < next_page_start);
+ dc->pc < next_page_start &&
+ num_insns < max_insns);
+
+ if (tb->cflags & CF_LAST_IO) {
+ if (dc->condjmp) {
+ /* FIXME: This can theoretically happen with self-modifying
+ code. */
+ cpu_abort(env, "IO on conditional branch instruction");
+ }
+ gen_io_end();
+ }
/* At this stage dc->condjmp will only be set when the skipped
instruction was a conditional branch or trap, and the PC has
already been written. */
- if (__builtin_expect(env->singlestep_enabled, 0)) {
+ if (unlikely(env->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (dc->condjmp) {
gen_set_condexec(dc);
@@ -8726,7 +8763,9 @@ static inline int gen_intermediate_code_internal(CPUState *env,
dc->condjmp = 0;
}
}
+
done_generating:
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
@@ -8744,6 +8783,7 @@ done_generating:
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
}
return 0;
}
@@ -8768,6 +8808,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
int flags)
{
int i;
+#if 0
union {
uint32_t i;
float s;
@@ -8779,6 +8820,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
float64 f64;
double d;
} d0;
+#endif
uint32_t psr;
for(i=0;i<16;i++) {
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 447e780b2..39b106172 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -125,7 +125,6 @@ typedef struct CPUCRISState {
/* X flag at the time of cc snapshot. */
int cc_x;
- int interrupt_request;
int interrupt_vector;
int fault_vector;
int trap_vector;
@@ -156,8 +155,6 @@ typedef struct CPUCRISState {
uint32_t lo;
} tlbsets[2][4][16];
- int user_mode_only;
-
CPU_COMMON
} CPUCRISState;
@@ -210,6 +207,8 @@ enum {
#define cpu_gen_code cpu_cris_gen_code
#define cpu_signal_handler cpu_cris_signal_handler
+#define CPU_SAVE_VERSION 1
+
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
#define MMU_MODE1_SUFFIX _user
@@ -238,5 +237,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5
#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6
+#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
+
#include "cpu-all.h"
#endif
diff --git a/target-cris/mmu.c b/target-cris/mmu.c
index 86f625b75..122e652e4 100644
--- a/target-cris/mmu.c
+++ b/target-cris/mmu.c
@@ -30,7 +30,11 @@
#include "mmu.h"
#include "exec-all.h"
+#ifdef DEBUG
+#define D(x) x
+#else
#define D(x)
+#endif
void cris_mmu_init(CPUState *env)
{
@@ -95,6 +99,7 @@ static inline void set_field(uint32_t *dst, unsigned int val,
*dst |= val;
}
+#ifdef DEBUG
static void dump_tlb(CPUState *env, int mmu)
{
int set;
@@ -113,6 +118,7 @@ static void dump_tlb(CPUState *env, int mmu)
}
}
}
+#endif
/* rw 0 = read, 1 = write, 2 = exec. */
static int cris_mmu_translate_page(struct cris_mmu_result_t *res,
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index 0e7d3c37f..fcf80705e 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -61,7 +61,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__,
env->pc, env->debug1, retaddr));
ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (__builtin_expect(ret, 0)) {
+ if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
@@ -121,8 +121,8 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
if (sreg == 6) {
/* Writes to tlb-hi write to mm_cause as a side
effect. */
- env->sregs[SFR_RW_MM_TLB_HI] = T0;
- env->sregs[SFR_R_MM_CAUSE] = T0;
+ env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
+ env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
}
else if (sreg == 5) {
uint32_t set;
diff --git a/target-cris/translate.c b/target-cris/translate.c
index cd0c2e15f..d971d1d2b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -77,6 +77,8 @@ TCGv env_btaken;
TCGv env_btarget;
TCGv env_pc;
+#include "gen-icount.h"
+
/* This is the state at translation time. */
typedef struct DisasContext {
CPUState *env;
@@ -3032,6 +3034,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
struct DisasContext *dc = &ctx;
uint32_t next_page_start;
target_ulong npc;
+ int num_insns;
+ int max_insns;
if (!logfile)
logfile = stderr;
@@ -3071,14 +3075,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile,
- "srch=%d pc=%x %x flg=%llx bt=%x ds=%lld ccs=%x\n"
+ "srch=%d pc=%x %x flg=%llx bt=%x ds=%u ccs=%x\n"
"pid=%x usp=%x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n",
- search_pc, dc->pc, dc->ppc, tb->flags,
- env->btarget, tb->flags & 7,
+ search_pc, dc->pc, dc->ppc,
+ (unsigned long long)tb->flags,
+ env->btarget, (unsigned)tb->flags & 7,
env->pregs[PR_CCS],
env->pregs[PR_PID], env->pregs[PR_USP],
env->regs[0], env->regs[1], env->regs[2], env->regs[3],
@@ -3092,6 +3097,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+
+ gen_icount_start();
do
{
check_breakpoint(env, dc);
@@ -3108,6 +3119,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
else
gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
/* Pretty disas. */
@@ -3116,6 +3128,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
DIS(fprintf(logfile, "%x ", dc->pc));
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
dc->clear_x = 1;
if (unlikely(loglevel & CPU_LOG_TB_OP))
tcg_gen_debug_insn_start(dc->pc);
@@ -3125,8 +3139,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (dc->clear_x)
cris_clear_x_flag(dc);
+ num_insns++;
/* Check for delayed branches here. If we do it before
- actually genereating any host code, the simulator will just
+ actually generating any host code, the simulator will just
loop doing nothing for on this program location. */
if (dc->delayed_branch) {
dc->delayed_branch--;
@@ -3151,12 +3166,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (!(tb->pc & 1) && env->singlestep_enabled)
break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end
- && (dc->pc < next_page_start));
+ && (dc->pc < next_page_start)
+ && num_insns < max_insns);
npc = dc->pc;
if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
npc = dc->jmp_pc;
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
/* Force an update if the per-tb cpu state has changed. */
if (dc->is_jmp == DISAS_NEXT
&& (dc->cpustate_changed || !dc->flagx_known
@@ -3173,7 +3191,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
cris_evaluate_flags (dc);
- if (__builtin_expect(env->singlestep_enabled, 0)) {
+ if (unlikely(env->singlestep_enabled)) {
tcg_gen_movi_tl(env_pc, npc);
t_gen_raise_exception(EXCP_DEBUG);
} else {
@@ -3194,6 +3212,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break;
}
}
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (search_pc) {
j = gen_opc_ptr - gen_opc_buf;
@@ -3202,6 +3221,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
}
#ifdef DEBUG_DISAS
@@ -3209,7 +3229,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
fprintf(logfile, "--------------\n");
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
target_disas(logfile, pc_start, dc->pc - pc_start, 0);
- fprintf(logfile, "\nisize=%d osize=%d\n",
+ fprintf(logfile, "\nisize=%d osize=%zd\n",
dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
}
#endif
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0cfe730b2..7e9590069 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -574,8 +574,6 @@ typedef struct CPUX86State {
target_ulong exception_next_eip;
target_ulong dr[8]; /* debug registers */
uint32_t smbase;
- int interrupt_request;
- int user_mode_only; /* user mode only simulation */
int old_exception; /* exception in flight */
CPU_COMMON
@@ -739,6 +737,8 @@ static inline int cpu_get_time_fast(void)
#define cpu_signal_handler cpu_x86_signal_handler
#define cpu_list x86_cpu_list
+#define CPU_SAVE_VERSION 6
+
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
#define MMU_MODE1_SUFFIX _user
@@ -766,6 +766,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base
+
#include "cpu-all.h"
#include "svm.h"
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 3c710bfba..73ce7dacb 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -838,12 +838,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
/* XXX: This value should match the one returned by CPUID
* and in exec.c */
#if defined(USE_KQEMU)
-#define PHYS_ADDR_MASK 0xfffff000L
+#define PHYS_ADDR_MASK 0xfffff000LL
#else
# if defined(TARGET_X86_64)
-# define PHYS_ADDR_MASK 0xfffffff000L
+# define PHYS_ADDR_MASK 0xfffffff000LL
# else
-# define PHYS_ADDR_MASK 0xffffff000L
+# define PHYS_ADDR_MASK 0xffffff000LL
# endif
#endif
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 0da657f3b..a3da01a1b 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -128,7 +128,6 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &env->smbase);
qemu_put_be64s(f, &env->pat);
qemu_put_be32s(f, &env->hflags2);
- qemu_put_be32s(f, (uint32_t *)&env->halted);
qemu_put_be64s(f, &env->vm_hsave);
qemu_put_be64s(f, &env->vm_vmcb);
@@ -182,7 +181,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
uint16_t fpus, fpuc, fptag, fpregs_format;
int32_t a20_mask;
- if (version_id != 3 && version_id != 4 && version_id != 5)
+ if (version_id != 3 && version_id != 4 && version_id != 5
+ && version_id != 6)
return -EINVAL;
for(i = 0; i < CPU_NB_REGS; i++)
qemu_get_betls(f, &env->regs[i]);
@@ -292,7 +292,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
if (version_id >= 5) {
qemu_get_be64s(f, &env->pat);
qemu_get_be32s(f, &env->hflags2);
- qemu_get_be32s(f, (uint32_t *)&env->halted);
+ if (version_id < 6)
+ qemu_get_be32s(f, &env->halted);
qemu_get_be64s(f, &env->vm_hsave);
qemu_get_be64s(f, &env->vm_vmcb);
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 6f9c25672..7dc317171 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -65,6 +65,8 @@ static TCGv cpu_T[2], cpu_T3;
static TCGv cpu_tmp0, cpu_tmp1_i64, cpu_tmp2_i32, cpu_tmp3_i32, cpu_tmp4, cpu_ptr0, cpu_ptr1;
static TCGv cpu_tmp5, cpu_tmp6;
+#include "gen-icount.h"
+
#ifdef TARGET_X86_64
static int x86_64_hregs;
#endif
@@ -1203,6 +1205,8 @@ static inline void gen_cmps(DisasContext *s, int ot)
static inline void gen_ins(DisasContext *s, int ot)
{
+ if (use_icount)
+ gen_io_start();
gen_string_movl_A0_EDI(s);
/* Note: we must do this dummy write first to be restartable in
case of page fault. */
@@ -1215,10 +1219,14 @@ static inline void gen_ins(DisasContext *s, int ot)
gen_op_st_T0_A0(ot + s->mem_index);
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_EDI);
+ if (use_icount)
+ gen_io_end();
}
static inline void gen_outs(DisasContext *s, int ot)
{
+ if (use_icount)
+ gen_io_start();
gen_string_movl_A0_ESI(s);
gen_op_ld_T0_A0(ot + s->mem_index);
@@ -1230,6 +1238,8 @@ static inline void gen_outs(DisasContext *s, int ot)
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_ESI);
+ if (use_icount)
+ gen_io_end();
}
/* same method as Valgrind : we generate jumps to current or next
@@ -3330,8 +3340,12 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)];
- tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_tmp2_i32);
+ if (ot == OT_LONG) {
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+ tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_tmp2_i32);
+ } else {
+ tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_T[0]);
+ }
break;
case 0x02c: /* cvttps2pi */
case 0x12c: /* cvttpd2pi */
@@ -5465,7 +5479,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x18 ... 0x1b:
{
int op1, l1;
- const static uint8_t fcmov_cc[8] = {
+ static const uint8_t fcmov_cc[8] = {
(JCC_B << 1),
(JCC_Z << 1),
(JCC_BE << 1),
@@ -5570,6 +5584,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
gen_ins(s, ot);
+ if (use_icount) {
+ gen_jmp(s, s->pc - s->cs_base);
+ }
}
break;
case 0x6e: /* outsS */
@@ -5586,6 +5603,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
gen_outs(s, ot);
+ if (use_icount) {
+ gen_jmp(s, s->pc - s->cs_base);
+ }
}
break;
@@ -5602,9 +5622,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_movl_T0_im(val);
gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+ if (use_icount)
+ gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32);
gen_op_mov_reg_T1(ot, R_EAX);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
break;
case 0xe6:
case 0xe7:
@@ -5618,10 +5644,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
svm_is_rep(prefixes));
gen_op_mov_TN_reg(ot, 1, R_EAX);
+ if (use_icount)
+ gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
break;
case 0xec:
case 0xed:
@@ -5633,9 +5665,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_andl_T0_ffff();
gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+ if (use_icount)
+ gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2_i32);
gen_op_mov_reg_T1(ot, R_EAX);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
break;
case 0xee:
case 0xef:
@@ -5649,10 +5687,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
svm_is_rep(prefixes));
gen_op_mov_TN_reg(ot, 1, R_EAX);
+ if (use_icount)
+ gen_io_start();
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2_i32, cpu_tmp3_i32);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
break;
/************************/
@@ -6342,7 +6386,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
+ if (use_icount)
+ gen_io_start();
tcg_gen_helper_0_0(helper_rdtsc);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
break;
case 0x133: /* rdpmc */
if (s->cc_op != CC_OP_DYNAMIC)
@@ -7109,6 +7159,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
uint64_t flags;
target_ulong pc_start;
target_ulong cs_base;
+ int num_insns;
+ int max_insns;
/* generate intermediate code */
pc_start = tb->pc;
@@ -7179,7 +7231,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
dc->is_jmp = DISAS_NEXT;
pc_ptr = pc_start;
lj = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+ gen_icount_start();
for(;;) {
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
@@ -7199,8 +7256,13 @@ static inline int gen_intermediate_code_internal(CPUState *env,
gen_opc_pc[lj] = pc_ptr;
gen_opc_cc_op[lj] = dc->cc_op;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
+
pc_ptr = disas_insn(dc, pc_ptr);
+ num_insns++;
/* stop translation if indicated */
if (dc->is_jmp)
break;
@@ -7210,20 +7272,23 @@ static inline int gen_intermediate_code_internal(CPUState *env,
the flag and abort the translation to give the irqs a
change to be happen */
if (dc->tf || dc->singlestep_enabled ||
- (flags & HF_INHIBIT_IRQ_MASK) ||
- (cflags & CF_SINGLE_INSN)) {
+ (flags & HF_INHIBIT_IRQ_MASK)) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
/* if too long translation, stop generation too */
if (gen_opc_ptr >= gen_opc_end ||
- (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
+ (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
+ num_insns >= max_insns) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
}
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
/* we don't forget to fill the last values */
if (search_pc) {
@@ -7252,8 +7317,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
}
#endif
- if (!search_pc)
+ if (!search_pc) {
tb->size = pc_ptr - pc_start;
+ tb->icount = num_insns;
+ }
return 0;
}
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index cfeafc003..a6687b11a 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -103,10 +103,6 @@ typedef struct CPUM68KState {
/* ??? remove this. */
uint32_t t1;
- /* exception/interrupt handling */
- int interrupt_request;
- int user_mode_only;
-
int pending_vector;
int pending_level;
@@ -235,6 +231,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) env->pc = tb->pc
+
#include "cpu-all.h"
#endif
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index f2e9f0359..aa36a3356 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -61,7 +61,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (__builtin_expect(ret, 0)) {
+ if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 0d603bdf5..9486c31d7 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -63,6 +63,8 @@ static TCGv NULL_QREG;
/* Used to distinguish stores from bad addressing modes. */
static TCGv store_dummy;
+#include "gen-icount.h"
+
void m68k_tcg_init(void)
{
char *p;
@@ -871,7 +873,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
TranslationBlock *tb;
tb = s->tb;
- if (__builtin_expect (s->singlestep_enabled, 0)) {
+ if (unlikely(s->singlestep_enabled)) {
gen_exception(s, dest, EXCP_DEBUG);
} else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
(s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
@@ -2919,6 +2921,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
target_ulong pc_start;
int pc_offset;
int last_cc_op;
+ int num_insns;
+ int max_insns;
/* generate intermediate code */
pc_start = tb->pc;
@@ -2937,6 +2941,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
dc->is_mem = 0;
dc->mactmp = NULL_QREG;
lj = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+
+ gen_icount_start();
do {
pc_offset = dc->pc - pc_start;
gen_throws_exception = NULL;
@@ -2960,21 +2970,28 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
}
gen_opc_pc[lj] = dc->pc;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
last_cc_op = dc->cc_op;
dc->insn_pc = dc->pc;
disas_m68k_insn(env, dc);
+ num_insns++;
/* Terminate the TB on memory ops if watchpoints are present. */
- /* FIXME: This should be replacd by the deterministic execution
+ /* FIXME: This should be replaced by the deterministic execution
* IRQ raising bits. */
if (dc->is_mem && env->nb_watchpoints)
break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&
- (pc_offset) < (TARGET_PAGE_SIZE - 32));
+ (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
+ num_insns < max_insns);
- if (__builtin_expect(env->singlestep_enabled, 0)) {
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
+ if (unlikely(env->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (!dc->is_jmp) {
gen_flush_cc_op(dc);
@@ -2999,6 +3016,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break;
}
}
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
@@ -3016,6 +3034,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
}
//optimize_flags();
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index fdb05ccfd..3ec867a72 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -134,33 +134,51 @@ typedef struct mips_def_t mips_def_t;
#define MIPS_TC_MAX 5
#define MIPS_DSP_ACC 4
+typedef struct TCState TCState;
+struct TCState {
+ target_ulong gpr[32];
+ target_ulong PC;
+ target_ulong HI[MIPS_DSP_ACC];
+ target_ulong LO[MIPS_DSP_ACC];
+ target_ulong ACX[MIPS_DSP_ACC];
+ target_ulong DSPControl;
+ int32_t CP0_TCStatus;
+#define CP0TCSt_TCU3 31
+#define CP0TCSt_TCU2 30
+#define CP0TCSt_TCU1 29
+#define CP0TCSt_TCU0 28
+#define CP0TCSt_TMX 27
+#define CP0TCSt_RNST 23
+#define CP0TCSt_TDS 21
+#define CP0TCSt_DT 20
+#define CP0TCSt_DA 15
+#define CP0TCSt_A 13
+#define CP0TCSt_TKSU 11
+#define CP0TCSt_IXMT 10
+#define CP0TCSt_TASID 0
+ int32_t CP0_TCBind;
+#define CP0TCBd_CurTC 21
+#define CP0TCBd_TBE 17
+#define CP0TCBd_CurVPE 0
+ target_ulong CP0_TCHalt;
+ target_ulong CP0_TCContext;
+ target_ulong CP0_TCSchedule;
+ target_ulong CP0_TCScheFBack;
+ int32_t CP0_Debug_tcstatus;
+};
+
typedef struct CPUMIPSState CPUMIPSState;
struct CPUMIPSState {
- /* General integer registers */
- target_ulong gpr[MIPS_SHADOW_SET_MAX][32];
- /* Special registers */
- target_ulong PC[MIPS_TC_MAX];
- /* temporary hack for FP globals */
-#ifndef USE_HOST_FLOAT_REGS
- fpr_t ft0;
- fpr_t ft1;
- fpr_t ft2;
-#endif
- target_ulong HI[MIPS_TC_MAX][MIPS_DSP_ACC];
- target_ulong LO[MIPS_TC_MAX][MIPS_DSP_ACC];
- target_ulong ACX[MIPS_TC_MAX][MIPS_DSP_ACC];
- target_ulong DSPControl[MIPS_TC_MAX];
+ TCState active_tc;
CPUMIPSMVPContext *mvp;
CPUMIPSTLBContext *tlb;
CPUMIPSFPUContext *fpu;
uint32_t current_tc;
- target_ulong *current_tc_gprs;
- target_ulong *current_tc_hi;
uint32_t SEGBITS;
- target_ulong SEGMask;
uint32_t PABITS;
+ target_ulong SEGMask;
target_ulong PAMask;
int32_t CP0_Index;
@@ -206,28 +224,6 @@ struct CPUMIPSState {
#define CP0VPEOpt_DWX1 1
#define CP0VPEOpt_DWX0 0
target_ulong CP0_EntryLo0;
- int32_t CP0_TCStatus[MIPS_TC_MAX];
-#define CP0TCSt_TCU3 31
-#define CP0TCSt_TCU2 30
-#define CP0TCSt_TCU1 29
-#define CP0TCSt_TCU0 28
-#define CP0TCSt_TMX 27
-#define CP0TCSt_RNST 23
-#define CP0TCSt_TDS 21
-#define CP0TCSt_DT 20
-#define CP0TCSt_DA 15
-#define CP0TCSt_A 13
-#define CP0TCSt_TKSU 11
-#define CP0TCSt_IXMT 10
-#define CP0TCSt_TASID 0
- int32_t CP0_TCBind[MIPS_TC_MAX];
-#define CP0TCBd_CurTC 21
-#define CP0TCBd_TBE 17
-#define CP0TCBd_CurVPE 0
- target_ulong CP0_TCHalt[MIPS_TC_MAX];
- target_ulong CP0_TCContext[MIPS_TC_MAX];
- target_ulong CP0_TCSchedule[MIPS_TC_MAX];
- target_ulong CP0_TCScheFBack[MIPS_TC_MAX];
target_ulong CP0_EntryLo1;
target_ulong CP0_Context;
int32_t CP0_PageMask;
@@ -398,7 +394,6 @@ struct CPUMIPSState {
#define CP0DB_DDBL 2
#define CP0DB_DBp 1
#define CP0DB_DSS 0
- int32_t CP0_Debug_tcstatus[MIPS_TC_MAX];
target_ulong CP0_DEPC;
int32_t CP0_Performance0;
int32_t CP0_TagLo;
@@ -407,10 +402,10 @@ struct CPUMIPSState {
int32_t CP0_DataHi;
target_ulong CP0_ErrorEPC;
int32_t CP0_DESAVE;
+ /* We waste some space so we can handle shadow registers like TCs. */
+ TCState tcs[MIPS_SHADOW_SET_MAX];
/* Qemu */
- int interrupt_request;
int error_code;
- int user_mode_only; /* user mode only simulation */
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x01FF
@@ -486,6 +481,8 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
#define cpu_signal_handler cpu_mips_signal_handler
#define cpu_list mips_cpu_list
+#define CPU_SAVE_VERSION 3
+
/* MMU modes definitions. We carefully match the indices with our
hflags layout. */
#define MMU_MODE0_SUFFIX _kernel
@@ -501,9 +498,9 @@ static inline int cpu_mmu_index (CPUState *env)
static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
{
if (newsp)
- env->gpr[env->current_tc][29] = newsp;
- env->gpr[env->current_tc][7] = 0;
- env->gpr[env->current_tc][2] = 0;
+ env->active_tc.gpr[29] = newsp;
+ env->active_tc.gpr[7] = 0;
+ env->active_tc.gpr[2] = 0;
}
#endif
@@ -569,4 +566,10 @@ CPUMIPSState *cpu_mips_init(const char *cpu_model);
uint32_t cpu_mips_get_clock (void);
int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
+#define CPU_PC_FROM_TB(env, tb) do { \
+ env->active_tc.PC = tb->pc; \
+ env->hflags &= ~MIPS_HFLAG_BMASK; \
+ env->hflags |= tb->flags & MIPS_HFLAG_BMASK; \
+ } while (0)
+
#endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/exec.h b/target-mips/exec.h
index a7014eea1..8600e79c5 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -10,29 +10,6 @@
register struct CPUMIPSState *env asm(AREG0);
-#if defined (USE_HOST_FLOAT_REGS)
-#error "implement me."
-#else
-#define FDT0 (env->ft0.fd)
-#define FDT1 (env->ft1.fd)
-#define FDT2 (env->ft2.fd)
-#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
-#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
-#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
-#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX])
-#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX])
-#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX])
-#define DT0 (env->ft0.d)
-#define DT1 (env->ft1.d)
-#define DT2 (env->ft2.d)
-#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
-#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
-#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
-#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX])
-#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX])
-#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX])
-#endif
-
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-mips/helper.c b/target-mips/helper.c
index b9622959b..11f58c225 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -241,7 +241,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
cpu_dump_state(env, logfile, fprintf, 0);
#endif
fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
- __func__, env->PC[env->current_tc], address, rw, mmu_idx, is_softmmu);
+ __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
}
rw &= 1;
@@ -370,7 +370,7 @@ void do_interrupt (CPUState *env)
name = excp_names[env->exception_index];
fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
- __func__, env->PC[env->current_tc], env->CP0_EPC, name);
+ __func__, env->active_tc.PC, env->CP0_EPC, name);
}
if (env->exception_index == EXCP_EXT_INTERRUPT &&
(env->hflags & MIPS_HFLAG_DM))
@@ -384,7 +384,7 @@ void do_interrupt (CPUState *env)
* (but we assume the pc has always been updated during
* code translation).
*/
- env->CP0_DEPC = env->PC[env->current_tc];
+ env->CP0_DEPC = env->active_tc.PC;
goto enter_debug_mode;
case EXCP_DINT:
env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -404,10 +404,10 @@ void do_interrupt (CPUState *env)
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
come back to the jump. */
- env->CP0_DEPC = env->PC[env->current_tc] - 4;
+ env->CP0_DEPC = env->active_tc.PC - 4;
env->hflags &= ~MIPS_HFLAG_BMASK;
} else {
- env->CP0_DEPC = env->PC[env->current_tc];
+ env->CP0_DEPC = env->active_tc.PC;
}
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
@@ -415,7 +415,7 @@ void do_interrupt (CPUState *env)
/* EJTAG probe trap enable is not implemented... */
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
- env->PC[env->current_tc] = (int32_t)0xBFC00480;
+ env->active_tc.PC = (int32_t)0xBFC00480;
break;
case EXCP_RESET:
cpu_reset(env);
@@ -430,17 +430,17 @@ void do_interrupt (CPUState *env)
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
come back to the jump. */
- env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
+ env->CP0_ErrorEPC = env->active_tc.PC - 4;
env->hflags &= ~MIPS_HFLAG_BMASK;
} else {
- env->CP0_ErrorEPC = env->PC[env->current_tc];
+ env->CP0_ErrorEPC = env->active_tc.PC;
}
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
- env->PC[env->current_tc] = (int32_t)0xBFC00000;
+ env->active_tc.PC = (int32_t)0xBFC00000;
break;
case EXCP_EXT_INTERRUPT:
cause = 0;
@@ -545,10 +545,10 @@ void do_interrupt (CPUState *env)
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
come back to the jump. */
- env->CP0_EPC = env->PC[env->current_tc] - 4;
+ env->CP0_EPC = env->active_tc.PC - 4;
env->CP0_Cause |= (1 << CP0Ca_BD);
} else {
- env->CP0_EPC = env->PC[env->current_tc];
+ env->CP0_EPC = env->active_tc.PC;
env->CP0_Cause &= ~(1 << CP0Ca_BD);
}
env->CP0_Status |= (1 << CP0St_EXL);
@@ -557,11 +557,11 @@ void do_interrupt (CPUState *env)
}
env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) {
- env->PC[env->current_tc] = (int32_t)0xBFC00200;
+ env->active_tc.PC = (int32_t)0xBFC00200;
} else {
- env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff);
+ env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
- env->PC[env->current_tc] += offset;
+ env->active_tc.PC += offset;
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
break;
default:
@@ -575,7 +575,7 @@ void do_interrupt (CPUState *env)
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
" S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
- __func__, env->PC[env->current_tc], env->CP0_EPC, cause,
+ __func__, env->active_tc.PC, env->CP0_EPC, cause,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 9fb5d7402..9d4ca82c5 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -159,67 +159,85 @@ DEF_HELPER(target_ulong, do_yield, (target_ulong t0))
DEF_HELPER(target_ulong, do_cfc1, (uint32_t reg))
DEF_HELPER(void, do_ctc1, (target_ulong t0, uint32_t reg))
-DEF_HELPER(void, do_float_cvtd_s, (void))
-DEF_HELPER(void, do_float_cvtd_w, (void))
-DEF_HELPER(void, do_float_cvtd_l, (void))
-DEF_HELPER(void, do_float_cvtl_d, (void))
-DEF_HELPER(void, do_float_cvtl_s, (void))
-DEF_HELPER(void, do_float_cvtps_pw, (void))
-DEF_HELPER(void, do_float_cvtpw_ps, (void))
-DEF_HELPER(void, do_float_cvts_d, (void))
-DEF_HELPER(void, do_float_cvts_w, (void))
-DEF_HELPER(void, do_float_cvts_l, (void))
-DEF_HELPER(void, do_float_cvts_pl, (void))
-DEF_HELPER(void, do_float_cvts_pu, (void))
-DEF_HELPER(void, do_float_cvtw_s, (void))
-DEF_HELPER(void, do_float_cvtw_d, (void))
+DEF_HELPER(uint64_t, do_float_cvtd_s, (uint32_t fst0))
+DEF_HELPER(uint64_t, do_float_cvtd_w, (uint32_t wt0))
+DEF_HELPER(uint64_t, do_float_cvtd_l, (uint64_t dt0))
+DEF_HELPER(uint64_t, do_float_cvtl_d, (uint64_t fd0))
+DEF_HELPER(uint64_t, do_float_cvtl_s, (uint32_t fst0))
+DEF_HELPER(uint64_t, do_float_cvtps_pw, (uint64_t dt0))
+DEF_HELPER(uint64_t, do_float_cvtpw_ps, (uint64_t fdt0))
+DEF_HELPER(uint32_t, do_float_cvts_d, (uint64_t fd0))
+DEF_HELPER(uint32_t, do_float_cvts_w, (uint32_t wt0))
+DEF_HELPER(uint32_t, do_float_cvts_l, (uint64_t dt0))
+DEF_HELPER(uint32_t, do_float_cvts_pl, (uint32_t wt0))
+DEF_HELPER(uint32_t, do_float_cvts_pu, (uint32_t wth0))
+DEF_HELPER(uint32_t, do_float_cvtw_s, (uint32_t fst0))
+DEF_HELPER(uint32_t, do_float_cvtw_d, (uint64_t fd0))
-DEF_HELPER(void, do_float_addr_ps, (void))
-DEF_HELPER(void, do_float_mulr_ps, (void))
+DEF_HELPER(uint64_t, do_float_addr_ps, (uint64_t fdt0, uint64_t fdt1))
+DEF_HELPER(uint64_t, do_float_mulr_ps, (uint64_t fdt0, uint64_t fdt1))
-#define FOP_PROTO(op) \
-DEF_HELPER(void, do_float_ ## op ## _s, (void)) \
-DEF_HELPER(void, do_float_ ## op ## _d, (void))
+#define FOP_PROTO(op) \
+DEF_HELPER(uint64_t, do_float_ ## op ## l_s, (uint32_t fst0)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## l_d, (uint64_t fdt0)) \
+DEF_HELPER(uint32_t, do_float_ ## op ## w_s, (uint32_t fst0)) \
+DEF_HELPER(uint32_t, do_float_ ## op ## w_d, (uint64_t fdt0))
+FOP_PROTO(round)
+FOP_PROTO(trunc)
+FOP_PROTO(ceil)
+FOP_PROTO(floor)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op) \
+DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0))
FOP_PROTO(sqrt)
-FOP_PROTO(roundl)
-FOP_PROTO(roundw)
-FOP_PROTO(truncl)
-FOP_PROTO(truncw)
-FOP_PROTO(ceill)
-FOP_PROTO(ceilw)
-FOP_PROTO(floorl)
-FOP_PROTO(floorw)
FOP_PROTO(rsqrt)
FOP_PROTO(recip)
#undef FOP_PROTO
-#define FOP_PROTO(op) \
-DEF_HELPER(void, do_float_ ## op ## _s, (void)) \
-DEF_HELPER(void, do_float_ ## op ## _d, (void)) \
-DEF_HELPER(void, do_float_ ## op ## _ps, (void))
+#define FOP_PROTO(op) \
+DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0))
+FOP_PROTO(abs)
+FOP_PROTO(chs)
+FOP_PROTO(recip1)
+FOP_PROTO(rsqrt1)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op) \
+DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0, uint32_t fst2)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0, uint64_t fdt2)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0, uint64_t fdt2))
FOP_PROTO(add)
FOP_PROTO(sub)
FOP_PROTO(mul)
FOP_PROTO(div)
-FOP_PROTO(abs)
-FOP_PROTO(chs)
+FOP_PROTO(recip2)
+FOP_PROTO(rsqrt2)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op) \
+DEF_HELPER(uint32_t, do_float_ ## op ## _s, (uint32_t fst0, uint32_t fst1, \
+ uint32_t fst2)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _d, (uint64_t fdt0, uint64_t fdt1, \
+ uint64_t fdt2)) \
+DEF_HELPER(uint64_t, do_float_ ## op ## _ps, (uint64_t fdt0, uint64_t fdt1, \
+ uint64_t fdt2))
FOP_PROTO(muladd)
FOP_PROTO(mulsub)
FOP_PROTO(nmuladd)
FOP_PROTO(nmulsub)
-FOP_PROTO(recip1)
-FOP_PROTO(recip2)
-FOP_PROTO(rsqrt1)
-FOP_PROTO(rsqrt2)
#undef FOP_PROTO
-#define FOP_PROTO(op) \
-DEF_HELPER(void, do_cmp_d_ ## op, (long cc)) \
-DEF_HELPER(void, do_cmpabs_d_ ## op, (long cc)) \
-DEF_HELPER(void, do_cmp_s_ ## op, (long cc)) \
-DEF_HELPER(void, do_cmpabs_s_ ## op, (long cc)) \
-DEF_HELPER(void, do_cmp_ps_ ## op, (long cc)) \
-DEF_HELPER(void, do_cmpabs_ps_ ## op, (long cc))
+#define FOP_PROTO(op) \
+DEF_HELPER(void, do_cmp_d_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \
+DEF_HELPER(void, do_cmpabs_d_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \
+DEF_HELPER(void, do_cmp_s_ ## op, (uint32_t fst0, uint32_t fst1, int cc)) \
+DEF_HELPER(void, do_cmpabs_s_ ## op, (uint32_t fst0, uint32_t fst1, int cc)) \
+DEF_HELPER(void, do_cmp_ps_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc)) \
+DEF_HELPER(void, do_cmpabs_ps_ ## op, (uint64_t fdt0, uint64_t fdt1, int cc))
FOP_PROTO(f)
FOP_PROTO(un)
FOP_PROTO(eq)
@@ -239,24 +257,24 @@ FOP_PROTO(ngt)
#undef FOP_PROTO
/* Special functions */
-DEF_HELPER(target_ulong, do_di, (target_ulong t0))
-DEF_HELPER(target_ulong, do_ei, (target_ulong t0))
+DEF_HELPER(target_ulong, do_di, (void))
+DEF_HELPER(target_ulong, do_ei, (void))
DEF_HELPER(void, do_eret, (void))
DEF_HELPER(void, do_deret, (void))
-DEF_HELPER(target_ulong, do_rdhwr_cpunum, (target_ulong t0))
-DEF_HELPER(target_ulong, do_rdhwr_synci_step, (target_ulong t0))
-DEF_HELPER(target_ulong, do_rdhwr_cc, (target_ulong t0))
-DEF_HELPER(target_ulong, do_rdhwr_ccres, (target_ulong t0))
+DEF_HELPER(target_ulong, do_rdhwr_cpunum, (void))
+DEF_HELPER(target_ulong, do_rdhwr_synci_step, (void))
+DEF_HELPER(target_ulong, do_rdhwr_cc, (void))
+DEF_HELPER(target_ulong, do_rdhwr_ccres, (void))
DEF_HELPER(void, do_pmon, (int function))
DEF_HELPER(void, do_wait, (void))
/* Bitfield operations. */
-DEF_HELPER(target_ulong, do_ext, (target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size))
+DEF_HELPER(target_ulong, do_ext, (target_ulong t1, uint32_t pos, uint32_t size))
DEF_HELPER(target_ulong, do_ins, (target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size))
-DEF_HELPER(target_ulong, do_wsbh, (target_ulong t0, target_ulong t1))
+DEF_HELPER(target_ulong, do_wsbh, (target_ulong t1))
#ifdef TARGET_MIPS64
-DEF_HELPER(target_ulong, do_dext, (target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size))
+DEF_HELPER(target_ulong, do_dext, (target_ulong t1, uint32_t pos, uint32_t size))
DEF_HELPER(target_ulong, do_dins, (target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size))
-DEF_HELPER(target_ulong, do_dsbh, (target_ulong t0, target_ulong t1))
-DEF_HELPER(target_ulong, do_dshd, (target_ulong t0, target_ulong t1))
+DEF_HELPER(target_ulong, do_dsbh, (target_ulong t1))
+DEF_HELPER(target_ulong, do_dshd, (target_ulong t1))
#endif
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 20fa58791..f73b9e2f5 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -3,11 +3,11 @@
void register_machines(void)
{
- qemu_register_machine(&mips_machine);
- qemu_register_machine(&mips_magnum_machine);
qemu_register_machine(&mips_malta_machine);
+ qemu_register_machine(&mips_magnum_machine);
qemu_register_machine(&mips_pica61_machine);
qemu_register_machine(&mips_mipssim_machine);
+ qemu_register_machine(&mips_machine);
}
void cpu_save(QEMUFile *f, void *opaque)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index eae5b7489..008fb2c0b 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -89,25 +89,25 @@ target_ulong do_dclz (target_ulong t0)
/* 64 bits arithmetic for 32 bits hosts */
static always_inline uint64_t get_HILO (void)
{
- return ((uint64_t)(env->HI[env->current_tc][0]) << 32) | (uint32_t)env->LO[env->current_tc][0];
+ return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
}
static always_inline void set_HILO (uint64_t HILO)
{
- env->LO[env->current_tc][0] = (int32_t)HILO;
- env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+ env->active_tc.LO[0] = (int32_t)HILO;
+ env->active_tc.HI[0] = (int32_t)(HILO >> 32);
}
static always_inline void set_HIT0_LO (target_ulong t0, uint64_t HILO)
{
- env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
- t0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+ env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ t0 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
}
static always_inline void set_HI_LOT0 (target_ulong t0, uint64_t HILO)
{
- t0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
- env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+ t0 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ env->active_tc.HI[0] = (int32_t)(HILO >> 32);
}
#if TARGET_LONG_BITS > HOST_LONG_BITS
@@ -246,12 +246,12 @@ target_ulong do_mulshiu (target_ulong t0, target_ulong t1)
#ifdef TARGET_MIPS64
void do_dmult (target_ulong t0, target_ulong t1)
{
- muls64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
+ muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
}
void do_dmultu (target_ulong t0, target_ulong t1)
{
- mulu64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
+ mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
}
#endif
@@ -672,86 +672,107 @@ target_ulong do_mfc0_random (void)
target_ulong do_mfc0_tcstatus (void)
{
- return env->CP0_TCStatus[env->current_tc];
+ return env->active_tc.CP0_TCStatus;
}
target_ulong do_mftc0_tcstatus(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCStatus[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCStatus;
+ else
+ return env->tcs[other_tc].CP0_TCStatus;
}
target_ulong do_mfc0_tcbind (void)
{
- return env->CP0_TCBind[env->current_tc];
+ return env->active_tc.CP0_TCBind;
}
target_ulong do_mftc0_tcbind(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCBind[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCBind;
+ else
+ return env->tcs[other_tc].CP0_TCBind;
}
target_ulong do_mfc0_tcrestart (void)
{
- return env->PC[env->current_tc];
+ return env->active_tc.PC;
}
target_ulong do_mftc0_tcrestart(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->PC[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.PC;
+ else
+ return env->tcs[other_tc].PC;
}
target_ulong do_mfc0_tchalt (void)
{
- return env->CP0_TCHalt[env->current_tc];
+ return env->active_tc.CP0_TCHalt;
}
target_ulong do_mftc0_tchalt(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCHalt[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCHalt;
+ else
+ return env->tcs[other_tc].CP0_TCHalt;
}
target_ulong do_mfc0_tccontext (void)
{
- return env->CP0_TCContext[env->current_tc];
+ return env->active_tc.CP0_TCContext;
}
target_ulong do_mftc0_tccontext(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCContext[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCContext;
+ else
+ return env->tcs[other_tc].CP0_TCContext;
}
target_ulong do_mfc0_tcschedule (void)
{
- return env->CP0_TCSchedule[env->current_tc];
+ return env->active_tc.CP0_TCSchedule;
}
target_ulong do_mftc0_tcschedule(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCSchedule[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCSchedule;
+ else
+ return env->tcs[other_tc].CP0_TCSchedule;
}
target_ulong do_mfc0_tcschefback (void)
{
- return env->CP0_TCScheFBack[env->current_tc];
+ return env->active_tc.CP0_TCScheFBack;
}
target_ulong do_mftc0_tcschefback(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->CP0_TCScheFBack[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.CP0_TCScheFBack;
+ else
+ return env->tcs[other_tc].CP0_TCScheFBack;
}
target_ulong do_mfc0_count (void)
@@ -762,15 +783,26 @@ target_ulong do_mfc0_count (void)
target_ulong do_mftc0_entryhi(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+ int32_t tcstatus;
+
+ if (other_tc == env->current_tc)
+ tcstatus = env->active_tc.CP0_TCStatus;
+ else
+ tcstatus = env->tcs[other_tc].CP0_TCStatus;
- return (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff);
+ return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
}
target_ulong do_mftc0_status(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- uint32_t tcstatus = env->CP0_TCStatus[other_tc];
target_ulong t0;
+ int32_t tcstatus;
+
+ if (other_tc == env->current_tc)
+ tcstatus = env->active_tc.CP0_TCStatus;
+ else
+ tcstatus = env->tcs[other_tc].CP0_TCStatus;
t0 = env->CP0_Status & ~0xf1000018;
t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
@@ -807,37 +839,42 @@ target_ulong do_mfc0_debug (void)
target_ulong do_mftc0_debug(void)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+ int32_t tcstatus;
+
+ if (other_tc == env->current_tc)
+ tcstatus = env->active_tc.CP0_Debug_tcstatus;
+ else
+ tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
/* XXX: Might be wrong, check with EJTAG spec. */
return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
- (env->CP0_Debug_tcstatus[other_tc] &
- ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+ (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
}
#if defined(TARGET_MIPS64)
target_ulong do_dmfc0_tcrestart (void)
{
- return env->PC[env->current_tc];
+ return env->active_tc.PC;
}
target_ulong do_dmfc0_tchalt (void)
{
- return env->CP0_TCHalt[env->current_tc];
+ return env->active_tc.CP0_TCHalt;
}
target_ulong do_dmfc0_tccontext (void)
{
- return env->CP0_TCContext[env->current_tc];
+ return env->active_tc.CP0_TCContext;
}
target_ulong do_dmfc0_tcschedule (void)
{
- return env->CP0_TCSchedule[env->current_tc];
+ return env->active_tc.CP0_TCSchedule;
}
target_ulong do_dmfc0_tcschefback (void)
{
- return env->CP0_TCScheFBack[env->current_tc];
+ return env->active_tc.CP0_TCScheFBack;
}
target_ulong do_dmfc0_lladdr (void)
@@ -955,11 +992,11 @@ void do_mtc0_tcstatus (target_ulong t0)
uint32_t mask = env->CP0_TCStatus_rw_bitmask;
uint32_t newval;
- newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (t0 & mask);
+ newval = (env->active_tc.CP0_TCStatus & ~mask) | (t0 & mask);
// TODO: Sync with CP0_Status.
- env->CP0_TCStatus[env->current_tc] = newval;
+ env->active_tc.CP0_TCStatus = newval;
}
void do_mttc0_tcstatus (target_ulong t0)
@@ -968,7 +1005,10 @@ void do_mttc0_tcstatus (target_ulong t0)
// TODO: Sync with CP0_Status.
- env->CP0_TCStatus[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCStatus = t0;
+ else
+ env->tcs[other_tc].CP0_TCStatus = t0;
}
void do_mtc0_tcbind (target_ulong t0)
@@ -978,8 +1018,8 @@ void do_mtc0_tcbind (target_ulong t0)
if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
mask |= (1 << CP0TCBd_CurVPE);
- newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (t0 & mask);
- env->CP0_TCBind[env->current_tc] = newval;
+ newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
+ env->active_tc.CP0_TCBind = newval;
}
void do_mttc0_tcbind (target_ulong t0)
@@ -990,14 +1030,19 @@ void do_mttc0_tcbind (target_ulong t0)
if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
mask |= (1 << CP0TCBd_CurVPE);
- newval = (env->CP0_TCBind[other_tc] & ~mask) | (t0 & mask);
- env->CP0_TCBind[other_tc] = newval;
+ if (other_tc == env->current_tc) {
+ newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
+ env->active_tc.CP0_TCBind = newval;
+ } else {
+ newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (t0 & mask);
+ env->tcs[other_tc].CP0_TCBind = newval;
+ }
}
void do_mtc0_tcrestart (target_ulong t0)
{
- env->PC[env->current_tc] = t0;
- env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS);
+ env->active_tc.PC = t0;
+ env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
env->CP0_LLAddr = 0ULL;
/* MIPS16 not implemented. */
}
@@ -1006,15 +1051,22 @@ void do_mttc0_tcrestart (target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->PC[other_tc] = t0;
- env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS);
- env->CP0_LLAddr = 0ULL;
- /* MIPS16 not implemented. */
+ if (other_tc == env->current_tc) {
+ env->active_tc.PC = t0;
+ env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+ env->CP0_LLAddr = 0ULL;
+ /* MIPS16 not implemented. */
+ } else {
+ env->tcs[other_tc].PC = t0;
+ env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+ env->CP0_LLAddr = 0ULL;
+ /* MIPS16 not implemented. */
+ }
}
void do_mtc0_tchalt (target_ulong t0)
{
- env->CP0_TCHalt[env->current_tc] = t0 & 0x1;
+ env->active_tc.CP0_TCHalt = t0 & 0x1;
// TODO: Halt TC / Restart (if allocated+active) TC.
}
@@ -1025,43 +1077,55 @@ void do_mttc0_tchalt (target_ulong t0)
// TODO: Halt TC / Restart (if allocated+active) TC.
- env->CP0_TCHalt[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCHalt = t0;
+ else
+ env->tcs[other_tc].CP0_TCHalt = t0;
}
void do_mtc0_tccontext (target_ulong t0)
{
- env->CP0_TCContext[env->current_tc] = t0;
+ env->active_tc.CP0_TCContext = t0;
}
void do_mttc0_tccontext (target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->CP0_TCContext[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCContext = t0;
+ else
+ env->tcs[other_tc].CP0_TCContext = t0;
}
void do_mtc0_tcschedule (target_ulong t0)
{
- env->CP0_TCSchedule[env->current_tc] = t0;
+ env->active_tc.CP0_TCSchedule = t0;
}
void do_mttc0_tcschedule (target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->CP0_TCSchedule[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCSchedule = t0;
+ else
+ env->tcs[other_tc].CP0_TCSchedule = t0;
}
void do_mtc0_tcschefback (target_ulong t0)
{
- env->CP0_TCScheFBack[env->current_tc] = t0;
+ env->active_tc.CP0_TCScheFBack = t0;
}
void do_mttc0_tcschefback (target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->CP0_TCScheFBack[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCScheFBack = t0;
+ else
+ env->tcs[other_tc].CP0_TCScheFBack = t0;
}
void do_mtc0_entrylo1 (target_ulong t0)
@@ -1142,8 +1206,8 @@ void do_mtc0_entryhi (target_ulong t0)
old = env->CP0_EntryHi;
env->CP0_EntryHi = val;
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
- uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff;
- env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff);
+ uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
+ env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
}
/* If the ASID changes, flush qemu's TLB. */
if ((old & 0xFF) != (val & 0xFF))
@@ -1153,9 +1217,16 @@ void do_mtc0_entryhi (target_ulong t0)
void do_mttc0_entryhi(target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+ int32_t tcstatus;
env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff);
- env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (t0 & 0xff);
+ if (other_tc == env->current_tc) {
+ tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (t0 & 0xff);
+ env->active_tc.CP0_TCStatus = tcstatus;
+ } else {
+ tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (t0 & 0xff);
+ env->tcs[other_tc].CP0_TCStatus = tcstatus;
+ }
}
void do_mtc0_compare (target_ulong t0)
@@ -1180,13 +1251,16 @@ void do_mtc0_status (target_ulong t0)
void do_mttc0_status(target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+ int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
env->CP0_Status = t0 & ~0xf1000018;
tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0));
tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
- env->CP0_TCStatus[other_tc] = tcstatus;
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_TCStatus = tcstatus;
+ else
+ env->tcs[other_tc].CP0_TCStatus = tcstatus;
}
void do_mtc0_intctl (target_ulong t0)
@@ -1279,9 +1353,13 @@ void do_mtc0_debug (target_ulong t0)
void do_mttc0_debug(target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+ uint32_t val = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
/* XXX: Might be wrong, check with EJTAG spec. */
- env->CP0_Debug_tcstatus[other_tc] = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+ if (other_tc == env->current_tc)
+ env->active_tc.CP0_Debug_tcstatus = val;
+ else
+ env->tcs[other_tc].CP0_Debug_tcstatus = val;
env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
(t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
}
@@ -1336,70 +1414,100 @@ target_ulong do_mftgpr(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->gpr[other_tc][sel];
+ if (other_tc == env->current_tc)
+ return env->active_tc.gpr[sel];
+ else
+ return env->tcs[other_tc].gpr[sel];
}
target_ulong do_mftlo(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->LO[other_tc][sel];
+ if (other_tc == env->current_tc)
+ return env->active_tc.LO[sel];
+ else
+ return env->tcs[other_tc].LO[sel];
}
target_ulong do_mfthi(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->HI[other_tc][sel];
+ if (other_tc == env->current_tc)
+ return env->active_tc.HI[sel];
+ else
+ return env->tcs[other_tc].HI[sel];
}
target_ulong do_mftacx(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->ACX[other_tc][sel];
+ if (other_tc == env->current_tc)
+ return env->active_tc.ACX[sel];
+ else
+ return env->tcs[other_tc].ACX[sel];
}
target_ulong do_mftdsp(target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- return env->DSPControl[other_tc];
+ if (other_tc == env->current_tc)
+ return env->active_tc.DSPControl;
+ else
+ return env->tcs[other_tc].DSPControl;
}
void do_mttgpr(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->gpr[other_tc][sel] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.gpr[sel] = t0;
+ else
+ env->tcs[other_tc].gpr[sel] = t0;
}
void do_mttlo(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->LO[other_tc][sel] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.LO[sel] = t0;
+ else
+ env->tcs[other_tc].LO[sel] = t0;
}
void do_mtthi(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->HI[other_tc][sel] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.HI[sel] = t0;
+ else
+ env->tcs[other_tc].HI[sel] = t0;
}
void do_mttacx(target_ulong t0, uint32_t sel)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->ACX[other_tc][sel] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.ACX[sel] = t0;
+ else
+ env->tcs[other_tc].ACX[sel] = t0;
}
void do_mttdsp(target_ulong t0)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
- env->DSPControl[other_tc] = t0;
+ if (other_tc == env->current_tc)
+ env->active_tc.DSPControl = t0;
+ else
+ env->tcs[other_tc].DSPControl = t0;
}
/* MIPS MT functions */
@@ -1452,7 +1560,7 @@ target_ulong do_yield(target_ulong t0)
/* No scheduling policy implemented. */
if (t0 != -2) {
if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
- env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) {
+ env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
do_raise_exception(EXCP_THREAD);
@@ -1638,18 +1746,20 @@ void r4k_do_tlbr (void)
#endif /* !CONFIG_USER_ONLY */
/* Specials */
-target_ulong do_di (target_ulong t0)
+target_ulong do_di (void)
{
- t0 = env->CP0_Status;
+ target_ulong t0 = env->CP0_Status;
+
env->CP0_Status = t0 & ~(1 << CP0St_IE);
cpu_mips_update_irq(env);
return t0;
}
-target_ulong do_ei (target_ulong t0)
+target_ulong do_ei (void)
{
- t0 = env->CP0_Status;
+ target_ulong t0 = env->CP0_Status;
+
env->CP0_Status = t0 | (1 << CP0St_IE);
cpu_mips_update_irq(env);
@@ -1659,7 +1769,7 @@ target_ulong do_ei (target_ulong t0)
void debug_pre_eret (void)
{
fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
- env->PC[env->current_tc], env->CP0_EPC);
+ env->active_tc.PC, env->CP0_EPC);
if (env->CP0_Status & (1 << CP0St_ERL))
fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
if (env->hflags & MIPS_HFLAG_DM)
@@ -1670,7 +1780,7 @@ void debug_pre_eret (void)
void debug_post_eret (void)
{
fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
- env->PC[env->current_tc], env->CP0_EPC);
+ env->active_tc.PC, env->CP0_EPC);
if (env->CP0_Status & (1 << CP0St_ERL))
fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
if (env->hflags & MIPS_HFLAG_DM)
@@ -1688,10 +1798,10 @@ void do_eret (void)
if (loglevel & CPU_LOG_EXEC)
debug_pre_eret();
if (env->CP0_Status & (1 << CP0St_ERL)) {
- env->PC[env->current_tc] = env->CP0_ErrorEPC;
+ env->active_tc.PC = env->CP0_ErrorEPC;
env->CP0_Status &= ~(1 << CP0St_ERL);
} else {
- env->PC[env->current_tc] = env->CP0_EPC;
+ env->active_tc.PC = env->CP0_EPC;
env->CP0_Status &= ~(1 << CP0St_EXL);
}
compute_hflags(env);
@@ -1704,7 +1814,7 @@ void do_deret (void)
{
if (loglevel & CPU_LOG_EXEC)
debug_pre_eret();
- env->PC[env->current_tc] = env->CP0_DEPC;
+ env->active_tc.PC = env->CP0_DEPC;
env->hflags &= MIPS_HFLAG_DM;
compute_hflags(env);
if (loglevel & CPU_LOG_EXEC)
@@ -1712,52 +1822,52 @@ void do_deret (void)
env->CP0_LLAddr = 1;
}
-target_ulong do_rdhwr_cpunum(target_ulong t0)
+target_ulong do_rdhwr_cpunum(void)
{
if ((env->hflags & MIPS_HFLAG_CP0) ||
(env->CP0_HWREna & (1 << 0)))
- t0 = env->CP0_EBase & 0x3ff;
+ return env->CP0_EBase & 0x3ff;
else
do_raise_exception(EXCP_RI);
- return t0;
+ return 0;
}
-target_ulong do_rdhwr_synci_step(target_ulong t0)
+target_ulong do_rdhwr_synci_step(void)
{
if ((env->hflags & MIPS_HFLAG_CP0) ||
(env->CP0_HWREna & (1 << 1)))
- t0 = env->SYNCI_Step;
+ return env->SYNCI_Step;
else
do_raise_exception(EXCP_RI);
- return t0;
+ return 0;
}
-target_ulong do_rdhwr_cc(target_ulong t0)
+target_ulong do_rdhwr_cc(void)
{
if ((env->hflags & MIPS_HFLAG_CP0) ||
(env->CP0_HWREna & (1 << 2)))
- t0 = env->CP0_Count;
+ return env->CP0_Count;
else
do_raise_exception(EXCP_RI);
- return t0;
+ return 0;
}
-target_ulong do_rdhwr_ccres(target_ulong t0)
+target_ulong do_rdhwr_ccres(void)
{
if ((env->hflags & MIPS_HFLAG_CP0) ||
(env->CP0_HWREna & (1 << 3)))
- t0 = env->CCRes;
+ return env->CCRes;
else
do_raise_exception(EXCP_RI);
- return t0;
+ return 0;
}
/* Bitfield operations. */
-target_ulong do_ext(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
+target_ulong do_ext(target_ulong t1, uint32_t pos, uint32_t size)
{
return (int32_t)((t1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0));
}
@@ -1769,13 +1879,13 @@ target_ulong do_ins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t siz
return (int32_t)((t0 & ~mask) | ((t1 << pos) & mask));
}
-target_ulong do_wsbh(target_ulong t0, target_ulong t1)
+target_ulong do_wsbh(target_ulong t1)
{
return (int32_t)(((t1 << 8) & ~0x00FF00FF) | ((t1 >> 8) & 0x00FF00FF));
}
#if defined(TARGET_MIPS64)
-target_ulong do_dext(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
+target_ulong do_dext(target_ulong t1, uint32_t pos, uint32_t size)
{
return (t1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL);
}
@@ -1787,12 +1897,12 @@ target_ulong do_dins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t si
return (t0 & ~mask) | ((t1 << pos) & mask);
}
-target_ulong do_dsbh(target_ulong t0, target_ulong t1)
+target_ulong do_dsbh(target_ulong t1)
{
return ((t1 << 8) & ~0x00FF00FF00FF00FFULL) | ((t1 >> 8) & 0x00FF00FF00FF00FFULL);
}
-target_ulong do_dshd(target_ulong t0, target_ulong t1)
+target_ulong do_dshd(target_ulong t1)
{
t1 = ((t1 << 16) & ~0x0000FFFF0000FFFFULL) | ((t1 >> 16) & 0x0000FFFF0000FFFFULL);
return (t1 << 32) | (t1 >> 32);
@@ -1804,21 +1914,21 @@ void do_pmon (int function)
function /= 2;
switch (function) {
case 2: /* TODO: char inbyte(int waitflag); */
- if (env->gpr[env->current_tc][4] == 0)
- env->gpr[env->current_tc][2] = -1;
+ if (env->active_tc.gpr[4] == 0)
+ env->active_tc.gpr[2] = -1;
/* Fall through */
case 11: /* TODO: char inbyte (void); */
- env->gpr[env->current_tc][2] = -1;
+ env->active_tc.gpr[2] = -1;
break;
case 3:
case 12:
- printf("%c", (char)(env->gpr[env->current_tc][4] & 0xFF));
+ printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
break;
case 17:
break;
case 158:
{
- unsigned char *fmt = (void *)(unsigned long)env->gpr[env->current_tc][4];
+ unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
printf("%s", fmt);
}
break;
@@ -2011,380 +2121,555 @@ static always_inline void update_fcr31(void)
"d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
paired single lower "pl", paired single upper "pu". */
-#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
-
/* unary operations, modifying fp status */
-#define FLOAT_UNOP(name) \
-FLOAT_OP(name, d) \
-{ \
- FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \
-} \
-FLOAT_OP(name, s) \
-{ \
- FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \
-}
-FLOAT_UNOP(sqrt)
-#undef FLOAT_UNOP
+uint64_t do_float_sqrt_d(uint64_t fdt0)
+{
+ return float64_sqrt(fdt0, &env->fpu->fp_status);
+}
+
+uint32_t do_float_sqrt_s(uint32_t fst0)
+{
+ return float32_sqrt(fst0, &env->fpu->fp_status);
+}
-FLOAT_OP(cvtd, s)
+uint64_t do_float_cvtd_s(uint32_t fst0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
+ fdt2 = float32_to_float64(fst0, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(cvtd, w)
+
+uint64_t do_float_cvtd_w(uint32_t wt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
+ fdt2 = int32_to_float64(wt0, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(cvtd, l)
+
+uint64_t do_float_cvtd_l(uint64_t dt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
+ fdt2 = int64_to_float64(dt0, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(cvtl, d)
+
+uint64_t do_float_cvtl_d(uint64_t fdt0)
{
+ uint64_t dt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+ dt2 = float64_to_int64(fdt0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(cvtl, s)
+
+uint64_t do_float_cvtl_s(uint32_t fst0)
{
+ uint64_t dt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+ dt2 = float32_to_int64(fst0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(cvtps, pw)
+uint64_t do_float_cvtps_pw(uint64_t dt0)
{
+ uint32_t fst2;
+ uint32_t fsth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
- FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
+ fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->fpu->fp_status);
+ fsth2 = int32_to_float32(dt0 >> 32, &env->fpu->fp_status);
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
-FLOAT_OP(cvtpw, ps)
+
+uint64_t do_float_cvtpw_ps(uint64_t fdt0)
{
+ uint32_t wt2;
+ uint32_t wth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
- WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
+ wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->fpu->fp_status);
+ wth2 = float32_to_int32(fdt0 >> 32, &env->fpu->fp_status);
update_fcr31();
- if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) {
+ wt2 = FLOAT_SNAN32;
+ wth2 = FLOAT_SNAN32;
+ }
+ return ((uint64_t)wth2 << 32) | wt2;
}
-FLOAT_OP(cvts, d)
+
+uint32_t do_float_cvts_d(uint64_t fdt0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
+ fst2 = float64_to_float32(fdt0, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(cvts, w)
+
+uint32_t do_float_cvts_w(uint32_t wt0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
+ fst2 = int32_to_float32(wt0, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(cvts, l)
+
+uint32_t do_float_cvts_l(uint64_t dt0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
+ fst2 = int64_to_float32(dt0, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(cvts, pl)
+
+uint32_t do_float_cvts_pl(uint32_t wt0)
{
+ uint32_t wt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- WT2 = WT0;
+ wt2 = wt0;
update_fcr31();
+ return wt2;
}
-FLOAT_OP(cvts, pu)
+
+uint32_t do_float_cvts_pu(uint32_t wth0)
{
+ uint32_t wt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- WT2 = WTH0;
+ wt2 = wth0;
update_fcr31();
+ return wt2;
}
-FLOAT_OP(cvtw, s)
+
+uint32_t do_float_cvtw_s(uint32_t fst0)
{
+ uint32_t wt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+ wt2 = float32_to_int32(fst0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(cvtw, d)
+
+uint32_t do_float_cvtw_d(uint64_t fdt0)
{
+ uint32_t wt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+ wt2 = float64_to_int32(fdt0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(roundl, d)
+uint64_t do_float_roundl_d(uint64_t fdt0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
- DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+ dt2 = float64_to_int64(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(roundl, s)
+
+uint64_t do_float_roundl_s(uint32_t fst0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
- DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+ dt2 = float32_to_int64(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(roundw, d)
+
+uint32_t do_float_roundw_d(uint64_t fdt0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
- WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+ wt2 = float64_to_int32(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(roundw, s)
+
+uint32_t do_float_roundw_s(uint32_t fst0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
- WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+ wt2 = float32_to_int32(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(truncl, d)
+uint64_t do_float_truncl_d(uint64_t fdt0)
{
- DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
+ uint64_t dt2;
+
+ dt2 = float64_to_int64_round_to_zero(fdt0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(truncl, s)
+
+uint64_t do_float_truncl_s(uint32_t fst0)
{
- DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
+ uint64_t dt2;
+
+ dt2 = float32_to_int64_round_to_zero(fst0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(truncw, d)
+
+uint32_t do_float_truncw_d(uint64_t fdt0)
{
- WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
+ uint32_t wt2;
+
+ wt2 = float64_to_int32_round_to_zero(fdt0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(truncw, s)
+
+uint32_t do_float_truncw_s(uint32_t fst0)
{
- WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
+ uint32_t wt2;
+
+ wt2 = float32_to_int32_round_to_zero(fst0, &env->fpu->fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(ceill, d)
+uint64_t do_float_ceill_d(uint64_t fdt0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
- DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+ dt2 = float64_to_int64(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(ceill, s)
+
+uint64_t do_float_ceill_s(uint32_t fst0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
- DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+ dt2 = float32_to_int64(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(ceilw, d)
+
+uint32_t do_float_ceilw_d(uint64_t fdt0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
- WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+ wt2 = float64_to_int32(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(ceilw, s)
+
+uint32_t do_float_ceilw_s(uint32_t fst0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
- WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+ wt2 = float32_to_int32(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(floorl, d)
+uint64_t do_float_floorl_d(uint64_t fdt0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
- DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+ dt2 = float64_to_int64(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(floorl, s)
+
+uint64_t do_float_floorl_s(uint32_t fst0)
{
+ uint64_t dt2;
+
set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
- DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+ dt2 = float32_to_int64(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- DT2 = FLOAT_SNAN64;
+ dt2 = FLOAT_SNAN64;
+ return dt2;
}
-FLOAT_OP(floorw, d)
+
+uint32_t do_float_floorw_d(uint64_t fdt0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
- WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+ wt2 = float64_to_int32(fdt0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
-FLOAT_OP(floorw, s)
+
+uint32_t do_float_floorw_s(uint32_t fst0)
{
+ uint32_t wt2;
+
set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
- WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+ wt2 = float32_to_int32(fst0, &env->fpu->fp_status);
RESTORE_ROUNDING_MODE;
update_fcr31();
if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
- WT2 = FLOAT_SNAN32;
+ wt2 = FLOAT_SNAN32;
+ return wt2;
}
/* unary operations, not modifying fp status */
-#define FLOAT_UNOP(name) \
-FLOAT_OP(name, d) \
-{ \
- FDT2 = float64_ ## name(FDT0); \
-} \
-FLOAT_OP(name, s) \
-{ \
- FST2 = float32_ ## name(FST0); \
-} \
-FLOAT_OP(name, ps) \
-{ \
- FST2 = float32_ ## name(FST0); \
- FSTH2 = float32_ ## name(FSTH0); \
+#define FLOAT_UNOP(name) \
+uint64_t do_float_ ## name ## _d(uint64_t fdt0) \
+{ \
+ return float64_ ## name(fdt0); \
+} \
+uint32_t do_float_ ## name ## _s(uint32_t fst0) \
+{ \
+ return float32_ ## name(fst0); \
+} \
+uint64_t do_float_ ## name ## _ps(uint64_t fdt0) \
+{ \
+ uint32_t wt0; \
+ uint32_t wth0; \
+ \
+ wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
+ wth0 = float32_ ## name(fdt0 >> 32); \
+ return ((uint64_t)wth0 << 32) | wt0; \
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP
/* MIPS specific unary operations */
-FLOAT_OP(recip, d)
+uint64_t do_float_recip_d(uint64_t fdt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
+ fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(recip, s)
+
+uint32_t do_float_recip_s(uint32_t fst0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fst0, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(rsqrt, d)
+uint64_t do_float_rsqrt_d(uint64_t fdt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
- FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
+ fdt2 = float64_sqrt(fdt0, &env->fpu->fp_status);
+ fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(rsqrt, s)
+
+uint32_t do_float_rsqrt_s(uint32_t fst0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+ fst2 = float32_sqrt(fst0, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(recip1, d)
+uint64_t do_float_recip1_d(uint64_t fdt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
+ fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(recip1, s)
+
+uint32_t do_float_recip1_s(uint32_t fst0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fst0, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(recip1, ps)
+
+uint64_t do_float_recip1_ps(uint64_t fdt0)
{
+ uint32_t fst2;
+ uint32_t fsth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
- FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->fpu->fp_status);
+ fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->fpu->fp_status);
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
-FLOAT_OP(rsqrt1, d)
+uint64_t do_float_rsqrt1_d(uint64_t fdt0)
{
+ uint64_t fdt2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
- FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
+ fdt2 = float64_sqrt(fdt0, &env->fpu->fp_status);
+ fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->fpu->fp_status);
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(rsqrt1, s)
+
+uint32_t do_float_rsqrt1_s(uint32_t fst0)
{
+ uint32_t fst2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+ fst2 = float32_sqrt(fst0, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status);
update_fcr31();
+ return fst2;
}
-FLOAT_OP(rsqrt1, ps)
+
+uint64_t do_float_rsqrt1_ps(uint64_t fdt0)
{
+ uint32_t fst2;
+ uint32_t fsth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
- FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
- FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
- FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
+ fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->fpu->fp_status);
+ fsth2 = float32_sqrt(fdt0 >> 32, &env->fpu->fp_status);
+ fst2 = float32_div(FLOAT_ONE32, fst2, &env->fpu->fp_status);
+ fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->fpu->fp_status);
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
+#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
+
/* binary operations */
-#define FLOAT_BINOP(name) \
-FLOAT_OP(name, d) \
-{ \
+#define FLOAT_BINOP(name) \
+uint64_t do_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \
+{ \
+ uint64_t dt2; \
+ \
set_float_exception_flags(0, &env->fpu->fp_status); \
- FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \
+ dt2 = float64_ ## name (fdt0, fdt1, &env->fpu->fp_status); \
update_fcr31(); \
if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \
- DT2 = FLOAT_QNAN64; \
-} \
-FLOAT_OP(name, s) \
-{ \
+ dt2 = FLOAT_QNAN64; \
+ return dt2; \
+} \
+ \
+uint32_t do_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \
+{ \
+ uint32_t wt2; \
+ \
set_float_exception_flags(0, &env->fpu->fp_status); \
- FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \
+ wt2 = float32_ ## name (fst0, fst1, &env->fpu->fp_status); \
update_fcr31(); \
if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \
- WT2 = FLOAT_QNAN32; \
-} \
-FLOAT_OP(name, ps) \
-{ \
+ wt2 = FLOAT_QNAN32; \
+ return wt2; \
+} \
+ \
+uint64_t do_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \
+{ \
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
+ uint32_t fsth0 = fdt0 >> 32; \
+ uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
+ uint32_t fsth1 = fdt1 >> 32; \
+ uint32_t wt2; \
+ uint32_t wth2; \
+ \
set_float_exception_flags(0, &env->fpu->fp_status); \
- FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \
- FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
- update_fcr31(); \
+ wt2 = float32_ ## name (fst0, fst1, &env->fpu->fp_status); \
+ wth2 = float32_ ## name (fsth0, fsth1, &env->fpu->fp_status); \
+ update_fcr31(); \
if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \
- WT2 = FLOAT_QNAN32; \
- WTH2 = FLOAT_QNAN32; \
- } \
+ wt2 = FLOAT_QNAN32; \
+ wth2 = FLOAT_QNAN32; \
+ } \
+ return ((uint64_t)wth2 << 32) | wt2; \
}
+
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
FLOAT_BINOP(mul)
@@ -2392,146 +2677,210 @@ FLOAT_BINOP(div)
#undef FLOAT_BINOP
/* ternary operations */
-#define FLOAT_TERNOP(name1, name2) \
-FLOAT_OP(name1 ## name2, d) \
-{ \
- FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \
- FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \
-} \
-FLOAT_OP(name1 ## name2, s) \
-{ \
- FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
- FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
-} \
-FLOAT_OP(name1 ## name2, ps) \
-{ \
- FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
- FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
- FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
- FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
+#define FLOAT_TERNOP(name1, name2) \
+uint64_t do_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
+ uint64_t fdt2) \
+{ \
+ fdt0 = float64_ ## name1 (fdt0, fdt1, &env->fpu->fp_status); \
+ return float64_ ## name2 (fdt0, fdt2, &env->fpu->fp_status); \
+} \
+ \
+uint32_t do_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
+ uint32_t fst2) \
+{ \
+ fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \
+ return float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \
+} \
+ \
+uint64_t do_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
+ uint64_t fdt2) \
+{ \
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
+ uint32_t fsth0 = fdt0 >> 32; \
+ uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
+ uint32_t fsth1 = fdt1 >> 32; \
+ uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
+ uint32_t fsth2 = fdt2 >> 32; \
+ \
+ fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \
+ fsth0 = float32_ ## name1 (fsth0, fsth1, &env->fpu->fp_status); \
+ fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \
+ fsth2 = float32_ ## name2 (fsth0, fsth2, &env->fpu->fp_status); \
+ return ((uint64_t)fsth2 << 32) | fst2; \
}
+
FLOAT_TERNOP(mul, add)
FLOAT_TERNOP(mul, sub)
#undef FLOAT_TERNOP
/* negated ternary operations */
-#define FLOAT_NTERNOP(name1, name2) \
-FLOAT_OP(n ## name1 ## name2, d) \
-{ \
- FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \
- FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \
- FDT2 = float64_chs(FDT2); \
-} \
-FLOAT_OP(n ## name1 ## name2, s) \
-{ \
- FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
- FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
- FST2 = float32_chs(FST2); \
-} \
-FLOAT_OP(n ## name1 ## name2, ps) \
-{ \
- FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \
- FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
- FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \
- FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
- FST2 = float32_chs(FST2); \
- FSTH2 = float32_chs(FSTH2); \
+#define FLOAT_NTERNOP(name1, name2) \
+uint64_t do_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
+ uint64_t fdt2) \
+{ \
+ fdt0 = float64_ ## name1 (fdt0, fdt1, &env->fpu->fp_status); \
+ fdt2 = float64_ ## name2 (fdt0, fdt2, &env->fpu->fp_status); \
+ return float64_chs(fdt2); \
+} \
+ \
+uint32_t do_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
+ uint32_t fst2) \
+{ \
+ fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \
+ fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \
+ return float32_chs(fst2); \
+} \
+ \
+uint64_t do_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
+ uint64_t fdt2) \
+{ \
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
+ uint32_t fsth0 = fdt0 >> 32; \
+ uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
+ uint32_t fsth1 = fdt1 >> 32; \
+ uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
+ uint32_t fsth2 = fdt2 >> 32; \
+ \
+ fst0 = float32_ ## name1 (fst0, fst1, &env->fpu->fp_status); \
+ fsth0 = float32_ ## name1 (fsth0, fsth1, &env->fpu->fp_status); \
+ fst2 = float32_ ## name2 (fst0, fst2, &env->fpu->fp_status); \
+ fsth2 = float32_ ## name2 (fsth0, fsth2, &env->fpu->fp_status); \
+ fst2 = float32_chs(fst2); \
+ fsth2 = float32_chs(fsth2); \
+ return ((uint64_t)fsth2 << 32) | fst2; \
}
+
FLOAT_NTERNOP(mul, add)
FLOAT_NTERNOP(mul, sub)
#undef FLOAT_NTERNOP
/* MIPS specific binary operations */
-FLOAT_OP(recip2, d)
+uint64_t do_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
{
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
- FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status));
+ fdt2 = float64_mul(fdt0, fdt2, &env->fpu->fp_status);
+ fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->fpu->fp_status));
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(recip2, s)
+
+uint32_t do_float_recip2_s(uint32_t fst0, uint32_t fst2)
{
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
- FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
+ fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status);
+ fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status));
update_fcr31();
+ return fst2;
}
-FLOAT_OP(recip2, ps)
+
+uint64_t do_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
{
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
- FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
- FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
- FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status));
+ fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status);
+ fsth2 = float32_mul(fsth0, fsth2, &env->fpu->fp_status);
+ fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status));
+ fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->fpu->fp_status));
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
-FLOAT_OP(rsqrt2, d)
+uint64_t do_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
{
set_float_exception_flags(0, &env->fpu->fp_status);
- FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
- FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
- FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status));
+ fdt2 = float64_mul(fdt0, fdt2, &env->fpu->fp_status);
+ fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->fpu->fp_status);
+ fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->fpu->fp_status));
update_fcr31();
+ return fdt2;
}
-FLOAT_OP(rsqrt2, s)
+
+uint32_t do_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
{
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
- FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
- FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
+ fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status);
+ fst2 = float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status);
+ fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->fpu->fp_status));
update_fcr31();
+ return fst2;
}
-FLOAT_OP(rsqrt2, ps)
+
+uint64_t do_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
{
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fst2 = fdt2 & 0XFFFFFFFF;
+ uint32_t fsth2 = fdt2 >> 32;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
- FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
- FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
- FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
- FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
- FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status));
+ fst2 = float32_mul(fst0, fst2, &env->fpu->fp_status);
+ fsth2 = float32_mul(fsth0, fsth2, &env->fpu->fp_status);
+ fst2 = float32_sub(fst2, FLOAT_ONE32, &env->fpu->fp_status);
+ fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->fpu->fp_status);
+ fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->fpu->fp_status));
+ fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->fpu->fp_status));
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
-FLOAT_OP(addr, ps)
+uint64_t do_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
{
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fst2;
+ uint32_t fsth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
- FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
+ fst2 = float32_add (fst0, fsth0, &env->fpu->fp_status);
+ fsth2 = float32_add (fst1, fsth1, &env->fpu->fp_status);
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
-FLOAT_OP(mulr, ps)
+uint64_t do_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
{
+ uint32_t fst0 = fdt0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fdt0 >> 32;
+ uint32_t fst1 = fdt1 & 0XFFFFFFFF;
+ uint32_t fsth1 = fdt1 >> 32;
+ uint32_t fst2;
+ uint32_t fsth2;
+
set_float_exception_flags(0, &env->fpu->fp_status);
- FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
- FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
+ fst2 = float32_mul (fst0, fsth0, &env->fpu->fp_status);
+ fsth2 = float32_mul (fst1, fsth1, &env->fpu->fp_status);
update_fcr31();
+ return ((uint64_t)fsth2 << 32) | fst2;
}
/* compare operations */
-#define FOP_COND_D(op, cond) \
-void do_cmp_d_ ## op (long cc) \
-{ \
- int c = cond; \
- update_fcr31(); \
- if (c) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
-} \
-void do_cmpabs_d_ ## op (long cc) \
-{ \
- int c; \
- FDT0 = float64_abs(FDT0); \
- FDT1 = float64_abs(FDT1); \
- c = cond; \
- update_fcr31(); \
- if (c) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
+#define FOP_COND_D(op, cond) \
+void do_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{ \
+ int c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
+} \
+void do_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{ \
+ int c; \
+ fdt0 = float64_abs(fdt0); \
+ fdt1 = float64_abs(fdt1); \
+ c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
}
int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
@@ -2550,46 +2899,46 @@ int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
-FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
-FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status), 0))
+FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status))
+FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_eq(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_eq(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_lt(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_lt(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) && float64_le(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->fpu->fp_status) || float64_le(fdt0, fdt1, &env->fpu->fp_status))
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
-FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
-FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
-FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status))
-
-#define FOP_COND_S(op, cond) \
-void do_cmp_s_ ## op (long cc) \
-{ \
- int c = cond; \
- update_fcr31(); \
- if (c) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
-} \
-void do_cmpabs_s_ ## op (long cc) \
-{ \
- int c; \
- FST0 = float32_abs(FST0); \
- FST1 = float32_abs(FST1); \
- c = cond; \
- update_fcr31(); \
- if (c) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
+FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status), 0))
+FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status))
+FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_eq(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_eq(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_lt(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_lt(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) && float64_le(fdt0, fdt1, &env->fpu->fp_status))
+FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->fpu->fp_status) || float64_le(fdt0, fdt1, &env->fpu->fp_status))
+
+#define FOP_COND_S(op, cond) \
+void do_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
+{ \
+ int c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
+} \
+void do_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
+{ \
+ int c; \
+ fst0 = float32_abs(fst0); \
+ fst1 = float32_abs(fst1); \
+ c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
}
flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
@@ -2608,93 +2957,98 @@ flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0))
-FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
-FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status), 0))
+FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status))
+FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status))
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0))
-FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
-FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
-FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status))
-
-#define FOP_COND_PS(op, condl, condh) \
-void do_cmp_ps_ ## op (long cc) \
-{ \
- int cl = condl; \
- int ch = condh; \
- update_fcr31(); \
- if (cl) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
- if (ch) \
- SET_FP_COND(cc + 1, env->fpu); \
- else \
- CLEAR_FP_COND(cc + 1, env->fpu); \
-} \
-void do_cmpabs_ps_ ## op (long cc) \
-{ \
- int cl, ch; \
- FST0 = float32_abs(FST0); \
- FSTH0 = float32_abs(FSTH0); \
- FST1 = float32_abs(FST1); \
- FSTH1 = float32_abs(FSTH1); \
- cl = condl; \
- ch = condh; \
- update_fcr31(); \
- if (cl) \
- SET_FP_COND(cc, env->fpu); \
- else \
- CLEAR_FP_COND(cc, env->fpu); \
- if (ch) \
- SET_FP_COND(cc + 1, env->fpu); \
- else \
- CLEAR_FP_COND(cc + 1, env->fpu); \
+FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status), 0))
+FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status))
+FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status))
+FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status))
+
+#define FOP_COND_PS(op, condl, condh) \
+void do_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{ \
+ uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
+ uint32_t fsth0 = float32_abs(fdt0 >> 32); \
+ uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
+ uint32_t fsth1 = float32_abs(fdt1 >> 32); \
+ int cl = condl; \
+ int ch = condh; \
+ \
+ update_fcr31(); \
+ if (cl) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
+ if (ch) \
+ SET_FP_COND(cc + 1, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc + 1, env->fpu); \
+} \
+void do_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
+{ \
+ uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
+ uint32_t fsth0 = float32_abs(fdt0 >> 32); \
+ uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
+ uint32_t fsth1 = float32_abs(fdt1 >> 32); \
+ int cl = condl; \
+ int ch = condh; \
+ \
+ update_fcr31(); \
+ if (cl) \
+ SET_FP_COND(cc, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc, env->fpu); \
+ if (ch) \
+ SET_FP_COND(cc + 1, env->fpu); \
+ else \
+ CLEAR_FP_COND(cc + 1, env->fpu); \
}
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
- (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
-FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
- float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
-FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status), 0),
+ (float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status), 0))
+FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status),
+ float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status))
+FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_eq(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_eq(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_lt(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_lt(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) && float32_le(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(0, fsth1, fsth0, &env->fpu->fp_status) || float32_le(fsth0, fsth1, &env->fpu->fp_status))
/* NOTE: the comma operator will make "cond" to eval to false,
* but float*_is_unordered() is still called. */
-FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
- (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
-FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
- float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
-FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status),
- !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
-FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status),
- float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status), 0),
+ (float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status), 0))
+FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status),
+ float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status))
+FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_eq(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_eq(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_eq(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_eq(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_lt(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_lt(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_lt(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_lt(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) && float32_le(fst0, fst1, &env->fpu->fp_status),
+ !float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) && float32_le(fsth0, fsth1, &env->fpu->fp_status))
+FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->fpu->fp_status) || float32_le(fst0, fst1, &env->fpu->fp_status),
+ float32_is_unordered(1, fsth1, fsth0, &env->fpu->fp_status) || float32_le(fsth0, fsth1, &env->fpu->fp_status))
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 41a27b4e2..bdc0f7b21 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -423,10 +423,9 @@ enum {
};
/* global register indices */
-static TCGv cpu_env, current_tc_gprs, current_tc_hi, current_fpu;
+static TCGv cpu_env, bcond, btarget, current_fpu;
-/* FPU TNs, global for now. */
-static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3];
+#include "gen-icount.h"
static inline void tcg_gen_helper_0_i(void *func, TCGv arg)
{
@@ -462,12 +461,12 @@ static inline void tcg_gen_helper_0_2i(void *func, TCGv arg1, TCGv arg2, TCGv ar
tcg_temp_free(tmp);
}
-static inline void tcg_gen_helper_0_2ii(void *func, TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg4)
+static inline void tcg_gen_helper_0_1ii(void *func, TCGv arg1, TCGv arg2, TCGv arg3)
{
- TCGv tmp1 = tcg_const_i32(arg3);
+ TCGv tmp1 = tcg_const_i32(arg2);
TCGv tmp2 = tcg_const_i32(arg3);
- tcg_gen_helper_0_4(func, arg1, arg2, tmp1, tmp2);
+ tcg_gen_helper_0_3(func, arg1, tmp1, tmp2);
tcg_temp_free(tmp1);
tcg_temp_free(tmp2);
}
@@ -488,6 +487,16 @@ static inline void tcg_gen_helper_1_1i(void *func, TCGv ret, TCGv arg1, TCGv arg
tcg_temp_free(tmp);
}
+static inline void tcg_gen_helper_1_1ii(void *func, TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3)
+{
+ TCGv tmp1 = tcg_const_i32(arg2);
+ TCGv tmp2 = tcg_const_i32(arg3);
+
+ tcg_gen_helper_1_3(func, ret, arg1, tmp1, tmp2);
+ tcg_temp_free(tmp1);
+ tcg_temp_free(tmp2);
+}
+
static inline void tcg_gen_helper_1_2i(void *func, TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3)
{
TCGv tmp = tcg_const_i32(arg3);
@@ -499,7 +508,7 @@ static inline void tcg_gen_helper_1_2i(void *func, TCGv ret, TCGv arg1, TCGv arg
static inline void tcg_gen_helper_1_2ii(void *func, TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg4)
{
TCGv tmp1 = tcg_const_i32(arg3);
- TCGv tmp2 = tcg_const_i32(arg3);
+ TCGv tmp2 = tcg_const_i32(arg4);
tcg_gen_helper_1_4(func, ret, arg1, arg2, tmp1, tmp2);
tcg_temp_free(tmp1);
@@ -520,8 +529,7 @@ typedef struct DisasContext {
enum {
BS_NONE = 0, /* We go out of the TB without reaching a branch or an
- * exception condition
- */
+ * exception condition */
BS_STOP = 1, /* We want to stop translation for any reason */
BS_BRANCH = 2, /* We reached a branch condition */
BS_EXCP = 3, /* We reached an exception condition */
@@ -563,40 +571,40 @@ static inline void gen_load_gpr (TCGv t, int reg)
if (reg == 0)
tcg_gen_movi_tl(t, 0);
else
- tcg_gen_ld_tl(t, current_tc_gprs, sizeof(target_ulong) * reg);
+ tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.gpr) +
+ sizeof(target_ulong) * reg);
}
static inline void gen_store_gpr (TCGv t, int reg)
{
if (reg != 0)
- tcg_gen_st_tl(t, current_tc_gprs, sizeof(target_ulong) * reg);
+ tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.gpr) +
+ sizeof(target_ulong) * reg);
}
/* Moves to/from HI and LO registers. */
static inline void gen_load_LO (TCGv t, int reg)
{
- tcg_gen_ld_tl(t, current_tc_hi,
- offsetof(CPUState, LO)
- - offsetof(CPUState, HI)
- + sizeof(target_ulong) * reg);
+ tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.LO) +
+ sizeof(target_ulong) * reg);
}
static inline void gen_store_LO (TCGv t, int reg)
{
- tcg_gen_st_tl(t, current_tc_hi,
- offsetof(CPUState, LO)
- - offsetof(CPUState, HI)
- + sizeof(target_ulong) * reg);
+ tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.LO) +
+ sizeof(target_ulong) * reg);
}
static inline void gen_load_HI (TCGv t, int reg)
{
- tcg_gen_ld_tl(t, current_tc_hi, sizeof(target_ulong) * reg);
+ tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.HI) +
+ sizeof(target_ulong) * reg);
}
static inline void gen_store_HI (TCGv t, int reg)
{
- tcg_gen_st_tl(t, current_tc_hi, sizeof(target_ulong) * reg);
+ tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.HI) +
+ sizeof(target_ulong) * reg);
}
/* Moves to/from shadow registers. */
@@ -712,41 +720,44 @@ static inline void get_fp_cond (TCGv t)
tcg_temp_free(r_tmp2);
}
-#define FOP_CONDS(type, fmt) \
-static GenOpFunc1 * fcmp ## type ## _ ## fmt ## _table[16] = { \
- do_cmp ## type ## _ ## fmt ## _f, \
- do_cmp ## type ## _ ## fmt ## _un, \
- do_cmp ## type ## _ ## fmt ## _eq, \
- do_cmp ## type ## _ ## fmt ## _ueq, \
- do_cmp ## type ## _ ## fmt ## _olt, \
- do_cmp ## type ## _ ## fmt ## _ult, \
- do_cmp ## type ## _ ## fmt ## _ole, \
- do_cmp ## type ## _ ## fmt ## _ule, \
- do_cmp ## type ## _ ## fmt ## _sf, \
- do_cmp ## type ## _ ## fmt ## _ngle, \
- do_cmp ## type ## _ ## fmt ## _seq, \
- do_cmp ## type ## _ ## fmt ## _ngl, \
- do_cmp ## type ## _ ## fmt ## _lt, \
- do_cmp ## type ## _ ## fmt ## _nge, \
- do_cmp ## type ## _ ## fmt ## _le, \
- do_cmp ## type ## _ ## fmt ## _ngt, \
-}; \
-static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \
-{ \
- tcg_gen_helper_0_i(fcmp ## type ## _ ## fmt ## _table[n], cc); \
+typedef void (fcmp_fun32)(uint32_t, uint32_t, int);
+typedef void (fcmp_fun64)(uint64_t, uint64_t, int);
+
+#define FOP_CONDS(fcmp_fun, type, arg0, arg1, fmt) \
+static fcmp_fun * fcmp ## type ## _ ## fmt ## _table[16] = { \
+ do_cmp ## type ## _ ## fmt ## _f, \
+ do_cmp ## type ## _ ## fmt ## _un, \
+ do_cmp ## type ## _ ## fmt ## _eq, \
+ do_cmp ## type ## _ ## fmt ## _ueq, \
+ do_cmp ## type ## _ ## fmt ## _olt, \
+ do_cmp ## type ## _ ## fmt ## _ult, \
+ do_cmp ## type ## _ ## fmt ## _ole, \
+ do_cmp ## type ## _ ## fmt ## _ule, \
+ do_cmp ## type ## _ ## fmt ## _sf, \
+ do_cmp ## type ## _ ## fmt ## _ngle, \
+ do_cmp ## type ## _ ## fmt ## _seq, \
+ do_cmp ## type ## _ ## fmt ## _ngl, \
+ do_cmp ## type ## _ ## fmt ## _lt, \
+ do_cmp ## type ## _ ## fmt ## _nge, \
+ do_cmp ## type ## _ ## fmt ## _le, \
+ do_cmp ## type ## _ ## fmt ## _ngt, \
+}; \
+static inline void gen_cmp ## type ## _ ## fmt(int n, arg0 a, arg1 b, int cc) \
+{ \
+ tcg_gen_helper_0_2i(fcmp ## type ## _ ## fmt ## _table[n], a, b, cc); \
}
-FOP_CONDS(, d)
-FOP_CONDS(abs, d)
-FOP_CONDS(, s)
-FOP_CONDS(abs, s)
-FOP_CONDS(, ps)
-FOP_CONDS(abs, ps)
+FOP_CONDS(fcmp_fun64, , uint64_t, uint64_t, d)
+FOP_CONDS(fcmp_fun64, abs, uint64_t, uint64_t, d)
+FOP_CONDS(fcmp_fun32, , uint32_t, uint32_t, s)
+FOP_CONDS(fcmp_fun32, abs, uint32_t, uint32_t, s)
+FOP_CONDS(fcmp_fun64, , uint64_t, uint64_t, ps)
+FOP_CONDS(fcmp_fun64, abs, uint64_t, uint64_t, ps)
#undef FOP_CONDS
/* Tests */
#define OP_COND(name, cond) \
-void glue(gen_op_, name) (TCGv t0, TCGv t1) \
+static inline void glue(gen_op_, name) (TCGv t0, TCGv t1) \
{ \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
@@ -767,7 +778,7 @@ OP_COND(ltu, TCG_COND_LTU);
#undef OP_COND
#define OP_CONDI(name, cond) \
-void glue(gen_op_, name) (TCGv t, target_ulong val) \
+static inline void glue(gen_op_, name) (TCGv t, target_ulong val) \
{ \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
@@ -784,7 +795,7 @@ OP_CONDI(ltiu, TCG_COND_LTU);
#undef OP_CONDI
#define OP_CONDZ(name, cond) \
-void glue(gen_op_, name) (TCGv t) \
+static inline void glue(gen_op_, name) (TCGv t) \
{ \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
@@ -805,60 +816,13 @@ OP_CONDZ(ltz, TCG_COND_LT);
static inline void gen_save_pc(target_ulong pc)
{
TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
- TCGv r_tc_off = tcg_temp_new(TCG_TYPE_I32);
- TCGv r_tc_off_ptr = tcg_temp_new(TCG_TYPE_PTR);
- TCGv r_ptr = tcg_temp_new(TCG_TYPE_PTR);
tcg_gen_movi_tl(r_tmp, pc);
- tcg_gen_ld_i32(r_tc_off, cpu_env, offsetof(CPUState, current_tc));
- tcg_gen_muli_i32(r_tc_off, r_tc_off, sizeof(target_ulong));
- tcg_gen_ext_i32_ptr(r_tc_off_ptr, r_tc_off);
- tcg_gen_add_ptr(r_ptr, cpu_env, r_tc_off_ptr);
- tcg_gen_st_tl(r_tmp, r_ptr, offsetof(CPUState, PC));
- tcg_temp_free(r_tc_off);
- tcg_temp_free(r_tc_off_ptr);
- tcg_temp_free(r_ptr);
- tcg_temp_free(r_tmp);
-}
-
-static inline void gen_breg_pc(void)
-{
- TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
- TCGv r_tc_off = tcg_temp_new(TCG_TYPE_I32);
- TCGv r_tc_off_ptr = tcg_temp_new(TCG_TYPE_PTR);
- TCGv r_ptr = tcg_temp_new(TCG_TYPE_PTR);
-
- tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, btarget));
- tcg_gen_ld_i32(r_tc_off, cpu_env, offsetof(CPUState, current_tc));
- tcg_gen_muli_i32(r_tc_off, r_tc_off, sizeof(target_ulong));
- tcg_gen_ext_i32_ptr(r_tc_off_ptr, r_tc_off);
- tcg_gen_add_ptr(r_ptr, cpu_env, r_tc_off_ptr);
- tcg_gen_st_tl(r_tmp, r_ptr, offsetof(CPUState, PC));
- tcg_temp_free(r_tc_off);
- tcg_temp_free(r_tc_off_ptr);
- tcg_temp_free(r_ptr);
- tcg_temp_free(r_tmp);
-}
-
-static inline void gen_save_btarget(target_ulong btarget)
-{
- TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
-
- tcg_gen_movi_tl(r_tmp, btarget);
- tcg_gen_st_tl(r_tmp, cpu_env, offsetof(CPUState, btarget));
- tcg_temp_free(r_tmp);
-}
-
-static always_inline void gen_save_breg_target(int reg)
-{
- TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
-
- gen_load_gpr(r_tmp, reg);
- tcg_gen_st_tl(r_tmp, cpu_env, offsetof(CPUState, btarget));
+ tcg_gen_st_tl(r_tmp, cpu_env, offsetof(CPUState, active_tc.PC));
tcg_temp_free(r_tmp);
}
-static always_inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
+static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
{
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
@@ -883,13 +847,13 @@ static always_inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
case MIPS_HFLAG_BC:
case MIPS_HFLAG_BL:
case MIPS_HFLAG_B:
- gen_save_btarget(ctx->btarget);
+ tcg_gen_movi_tl(btarget, ctx->btarget);
break;
}
}
}
-static always_inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
+static inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
{
ctx->saved_hflags = ctx->hflags;
switch (ctx->hflags & MIPS_HFLAG_BMASK) {
@@ -903,7 +867,7 @@ static always_inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
}
}
-static always_inline void
+static inline void
generate_exception_err (DisasContext *ctx, int excp, int err)
{
save_cpu_state(ctx, 1);
@@ -912,7 +876,7 @@ generate_exception_err (DisasContext *ctx, int excp, int err)
tcg_gen_exit_tb(0);
}
-static always_inline void
+static inline void
generate_exception (DisasContext *ctx, int excp)
{
save_cpu_state(ctx, 1);
@@ -947,13 +911,13 @@ static inline void gen_op_addr_add (TCGv t0, TCGv t1)
#endif
}
-static always_inline void check_cp0_enabled(DisasContext *ctx)
+static inline void check_cp0_enabled(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
generate_exception_err(ctx, EXCP_CpU, 1);
}
-static always_inline void check_cp1_enabled(DisasContext *ctx)
+static inline void check_cp1_enabled(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU)))
generate_exception_err(ctx, EXCP_CpU, 1);
@@ -963,7 +927,7 @@ static always_inline void check_cp1_enabled(DisasContext *ctx)
This is associated with the nabla symbol in the MIPS32 and MIPS64
opcode tables. */
-static always_inline void check_cop1x(DisasContext *ctx)
+static inline void check_cop1x(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X)))
generate_exception(ctx, EXCP_RI);
@@ -972,7 +936,7 @@ static always_inline void check_cop1x(DisasContext *ctx)
/* Verify that the processor is running with 64-bit floating-point
operations enabled. */
-static always_inline void check_cp1_64bitmode(DisasContext *ctx)
+static inline void check_cp1_64bitmode(DisasContext *ctx)
{
if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X)))
generate_exception(ctx, EXCP_RI);
@@ -989,7 +953,7 @@ static always_inline void check_cp1_64bitmode(DisasContext *ctx)
* Multiple 64 bit wide registers can be checked by calling
* gen_op_cp1_registers(freg1 | freg2 | ... | fregN);
*/
-void check_cp1_registers(DisasContext *ctx, int regs)
+static inline void check_cp1_registers(DisasContext *ctx, int regs)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)))
generate_exception(ctx, EXCP_RI);
@@ -997,7 +961,7 @@ void check_cp1_registers(DisasContext *ctx, int regs)
/* This code generates a "reserved instruction" exception if the
CPU does not support the instruction set corresponding to flags. */
-static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
+static inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
{
if (unlikely(!(env->insn_flags & flags)))
generate_exception(ctx, EXCP_RI);
@@ -1005,7 +969,7 @@ static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags
/* This code generates a "reserved instruction" exception if 64-bit
instructions are not enabled. */
-static always_inline void check_mips_64(DisasContext *ctx)
+static inline void check_mips_64(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_64)))
generate_exception(ctx, EXCP_RI);
@@ -1013,7 +977,7 @@ static always_inline void check_mips_64(DisasContext *ctx)
/* load/store instructions. */
#define OP_LD(insn,fname) \
-void inline op_ldst_##insn(TCGv t0, DisasContext *ctx) \
+static inline void op_ldst_##insn(TCGv t0, DisasContext *ctx) \
{ \
tcg_gen_qemu_##fname(t0, t0, ctx->mem_idx); \
}
@@ -1029,7 +993,7 @@ OP_LD(ld,ld64);
#undef OP_LD
#define OP_ST(insn,fname) \
-void inline op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
+static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
{ \
tcg_gen_qemu_##fname(t1, t0, ctx->mem_idx); \
}
@@ -1042,7 +1006,7 @@ OP_ST(sd,st64);
#undef OP_ST
#define OP_LD_ATOMIC(insn,fname) \
-void inline op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
+static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
{ \
tcg_gen_mov_tl(t1, t0); \
tcg_gen_qemu_##fname(t0, t0, ctx->mem_idx); \
@@ -1055,7 +1019,7 @@ OP_LD_ATOMIC(lld,ld64);
#undef OP_LD_ATOMIC
#define OP_ST_ATOMIC(insn,fname,almask) \
-void inline op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
+static inline void op_ldst_##insn(TCGv t0, TCGv t1, DisasContext *ctx) \
{ \
TCGv r_tmp = tcg_temp_local_new(TCG_TYPE_TL); \
int l1 = gen_new_label(); \
@@ -1249,7 +1213,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
/* Load and store */
static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
- int base, int16_t offset)
+ int base, int16_t offset)
{
const char *opn = "flt_ldst";
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
@@ -1270,23 +1234,43 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
memory access. */
switch (opc) {
case OPC_LWC1:
- tcg_gen_qemu_ld32s(fpu32_T[0], t0, ctx->mem_idx);
- gen_store_fpr32(fpu32_T[0], ft);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_qemu_ld32s(fp0, t0, ctx->mem_idx);
+ gen_store_fpr32(fp0, ft);
+ tcg_temp_free(fp0);
+ }
opn = "lwc1";
break;
case OPC_SWC1:
- gen_load_fpr32(fpu32_T[0], ft);
- tcg_gen_qemu_st32(fpu32_T[0], t0, ctx->mem_idx);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, ft);
+ tcg_gen_qemu_st32(fp0, t0, ctx->mem_idx);
+ tcg_temp_free(fp0);
+ }
opn = "swc1";
break;
case OPC_LDC1:
- tcg_gen_qemu_ld64(fpu64_T[0], t0, ctx->mem_idx);
- gen_store_fpr64(ctx, fpu64_T[0], ft);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+ gen_store_fpr64(ctx, fp0, ft);
+ tcg_temp_free(fp0);
+ }
opn = "ldc1";
break;
case OPC_SDC1:
- gen_load_fpr64(ctx, fpu64_T[0], ft);
- tcg_gen_qemu_st64(fpu64_T[0], t0, ctx->mem_idx);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, ft);
+ tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+ tcg_temp_free(fp0);
+ }
opn = "sdc1";
break;
default:
@@ -2495,7 +2479,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc,
tcg_temp_free(t1);
}
-static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
TranslationBlock *tb;
tb = ctx->tb;
@@ -2513,7 +2497,7 @@ static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong des
static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
int rs, int rt, int32_t offset)
{
- target_ulong btarget = -1;
+ target_ulong btgt = -1;
int blink = 0;
int bcond = 0;
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
@@ -2543,7 +2527,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
gen_load_gpr(t1, rt);
bcond = 1;
}
- btarget = ctx->pc + 4 + offset;
+ btgt = ctx->pc + 4 + offset;
break;
case OPC_BGEZ:
case OPC_BGEZAL:
@@ -2562,12 +2546,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
gen_load_gpr(t0, rs);
bcond = 1;
}
- btarget = ctx->pc + 4 + offset;
+ btgt = ctx->pc + 4 + offset;
break;
case OPC_J:
case OPC_JAL:
/* Jump to immediate */
- btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset;
+ btgt = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset;
break;
case OPC_JR:
case OPC_JALR:
@@ -2579,7 +2563,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
generate_exception(ctx, EXCP_RI);
goto out;
}
- gen_save_breg_target(rs);
+ gen_load_gpr(btarget, rs);
break;
default:
MIPS_INVAL("branch/jump");
@@ -2633,12 +2617,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
goto out;
case OPC_J:
ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("j " TARGET_FMT_lx, btarget);
+ MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
break;
case OPC_JAL:
blink = 31;
ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("jal " TARGET_FMT_lx, btarget);
+ MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
break;
case OPC_JR:
ctx->hflags |= MIPS_HFLAG_BR;
@@ -2659,80 +2643,80 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_BEQ:
gen_op_eq(t0, t1);
MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx,
- regnames[rs], regnames[rt], btarget);
+ regnames[rs], regnames[rt], btgt);
goto not_likely;
case OPC_BEQL:
gen_op_eq(t0, t1);
MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx,
- regnames[rs], regnames[rt], btarget);
+ regnames[rs], regnames[rt], btgt);
goto likely;
case OPC_BNE:
gen_op_ne(t0, t1);
MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx,
- regnames[rs], regnames[rt], btarget);
+ regnames[rs], regnames[rt], btgt);
goto not_likely;
case OPC_BNEL:
gen_op_ne(t0, t1);
MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
- regnames[rs], regnames[rt], btarget);
+ regnames[rs], regnames[rt], btgt);
goto likely;
case OPC_BGEZ:
gen_op_gez(t0);
- MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto not_likely;
case OPC_BGEZL:
gen_op_gez(t0);
- MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
case OPC_BGEZAL:
gen_op_gez(t0);
- MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
blink = 31;
goto not_likely;
case OPC_BGEZALL:
gen_op_gez(t0);
blink = 31;
- MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
case OPC_BGTZ:
gen_op_gtz(t0);
- MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto not_likely;
case OPC_BGTZL:
gen_op_gtz(t0);
- MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
case OPC_BLEZ:
gen_op_lez(t0);
- MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto not_likely;
case OPC_BLEZL:
gen_op_lez(t0);
- MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
case OPC_BLTZ:
gen_op_ltz(t0);
- MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto not_likely;
case OPC_BLTZL:
gen_op_ltz(t0);
- MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
case OPC_BLTZAL:
gen_op_ltz(t0);
blink = 31;
- MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
not_likely:
ctx->hflags |= MIPS_HFLAG_BC;
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, bcond));
+ tcg_gen_trunc_tl_i32(bcond, t0);
break;
case OPC_BLTZALL:
gen_op_ltz(t0);
blink = 31;
- MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btarget);
+ MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btgt);
likely:
ctx->hflags |= MIPS_HFLAG_BL;
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, bcond));
+ tcg_gen_trunc_tl_i32(bcond, t0);
break;
default:
MIPS_INVAL("conditional branch/jump");
@@ -2741,9 +2725,9 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
}
}
MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
- blink, ctx->hflags, btarget);
+ blink, ctx->hflags, btgt);
- ctx->btarget = btarget;
+ ctx->btarget = btgt;
if (blink > 0) {
tcg_gen_movi_tl(t0, ctx->pc + 8);
gen_store_gpr(t0, blink);
@@ -2756,7 +2740,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
/* special3 bitfield operations */
static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
- int rs, int lsb, int msb)
+ int rs, int lsb, int msb)
{
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
TCGv t1 = tcg_temp_local_new(TCG_TYPE_TL);
@@ -2766,23 +2750,23 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
case OPC_EXT:
if (lsb + msb > 31)
goto fail;
- tcg_gen_helper_1_2ii(do_ext, t0, t0, t1, lsb, msb + 1);
+ tcg_gen_helper_1_1ii(do_ext, t0, t1, lsb, msb + 1);
break;
#if defined(TARGET_MIPS64)
case OPC_DEXTM:
if (lsb + msb > 63)
goto fail;
- tcg_gen_helper_1_2ii(do_dext, t0, t0, t1, lsb, msb + 1 + 32);
+ tcg_gen_helper_1_1ii(do_dext, t0, t1, lsb, msb + 1 + 32);
break;
case OPC_DEXTU:
if (lsb + msb > 63)
goto fail;
- tcg_gen_helper_1_2ii(do_dext, t0, t0, t1, lsb + 32, msb + 1);
+ tcg_gen_helper_1_1ii(do_dext, t0, t1, lsb + 32, msb + 1);
break;
case OPC_DEXT:
if (lsb + msb > 63)
goto fail;
- tcg_gen_helper_1_2ii(do_dext, t0, t0, t1, lsb, msb + 1);
+ tcg_gen_helper_1_1ii(do_dext, t0, t1, lsb, msb + 1);
break;
#endif
case OPC_INS:
@@ -3081,7 +3065,14 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
case 9:
switch (sel) {
case 0:
+ /* Mark as an IO operation because we read the time. */
+ if (use_icount)
+ gen_io_start();
tcg_gen_helper_1_0(do_mfc0_count, t0);
+ if (use_icount) {
+ gen_io_end();
+ ctx->bstate = BS_STOP;
+ }
rn = "Count";
break;
/* 6,7 are implementation dependent */
@@ -3442,6 +3433,9 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
if (sel != 0)
check_insn(env, ctx, ISA_MIPS32);
+ if (use_icount)
+ gen_io_start();
+
switch (reg) {
case 0:
switch (sel) {
@@ -4024,6 +4018,11 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int se
rn, reg, sel);
}
#endif
+ /* For simplicity assume that all writes can cause interrupts. */
+ if (use_icount) {
+ gen_io_end();
+ ctx->bstate = BS_STOP;
+ }
return;
die:
@@ -4258,7 +4257,14 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
case 9:
switch (sel) {
case 0:
+ /* Mark as an IO operation because we read the time. */
+ if (use_icount)
+ gen_io_start();
tcg_gen_helper_1_0(do_mfc0_count, t0);
+ if (use_icount) {
+ gen_io_end();
+ ctx->bstate = BS_STOP;
+ }
rn = "Count";
break;
/* 6,7 are implementation dependent */
@@ -4611,6 +4617,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
if (sel != 0)
check_insn(env, ctx, ISA_MIPS64);
+ if (use_icount)
+ gen_io_start();
+
switch (reg) {
case 0:
switch (sel) {
@@ -5181,6 +5190,11 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv t0, int reg, int s
}
#endif
tcg_temp_free(t0);
+ /* For simplicity assume that all writes can cause interrupts. */
+ if (use_icount) {
+ gen_io_end();
+ ctx->bstate = BS_STOP;
+ }
return;
die:
@@ -5202,8 +5216,8 @@ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd,
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
- ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
- (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+ ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+ (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
tcg_gen_movi_tl(t0, -1);
else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
(env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
@@ -5324,11 +5338,17 @@ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd,
case 2:
/* XXX: For now we support only a single FPU context. */
if (h == 0) {
- gen_load_fpr32(fpu32_T[0], rt);
- tcg_gen_ext_i32_tl(t0, fpu32_T[0]);
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, rt);
+ tcg_gen_ext_i32_tl(t0, fp0);
+ tcg_temp_free(fp0);
} else {
- gen_load_fpr32h(fpu32h_T[0], rt);
- tcg_gen_ext_i32_tl(t0, fpu32h_T[0]);
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32h(fp0, rt);
+ tcg_gen_ext_i32_tl(t0, fp0);
+ tcg_temp_free(fp0);
}
break;
case 3:
@@ -5371,8 +5391,8 @@ static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt,
gen_load_gpr(t0, rt);
if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
- ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
- (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+ ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+ (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
/* NOP */ ;
else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
(env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
@@ -5493,11 +5513,17 @@ static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt,
case 2:
/* XXX: For now we support only a single FPU context. */
if (h == 0) {
- tcg_gen_trunc_tl_i32(fpu32_T[0], t0);
- gen_store_fpr32(fpu32_T[0], rd);
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_trunc_tl_i32(fp0, t0);
+ gen_store_fpr32(fp0, rd);
+ tcg_temp_free(fp0);
} else {
- tcg_gen_trunc_tl_i32(fpu32h_T[0], t0);
- gen_store_fpr32h(fpu32h_T[0], rd);
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_trunc_tl_i32(fp0, t0);
+ gen_store_fpr32h(fp0, rd);
+ tcg_temp_free(fp0);
}
break;
case 3:
@@ -5767,7 +5793,7 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
opn = "bc1tl";
likely:
ctx->hflags |= MIPS_HFLAG_BL;
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, bcond));
+ tcg_gen_trunc_tl_i32(bcond, t0);
break;
case OPC_BC1FANY2:
{
@@ -5852,7 +5878,7 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
opn = "bc1any4t";
not_likely:
ctx->hflags |= MIPS_HFLAG_BC;
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, bcond));
+ tcg_gen_trunc_tl_i32(bcond, t0);
break;
default:
MIPS_INVAL(opn);
@@ -5879,15 +5905,25 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
switch (opc) {
case OPC_MFC1:
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_ext_i32_tl(t0, fpu32_T[0]);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_ext_i32_tl(t0, fp0);
+ tcg_temp_free(fp0);
+ }
gen_store_gpr(t0, rt);
opn = "mfc1";
break;
case OPC_MTC1:
gen_load_gpr(t0, rt);
- tcg_gen_trunc_tl_i32(fpu32_T[0], t0);
- gen_store_fpr32(fpu32_T[0], fs);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_trunc_tl_i32(fp0, t0);
+ gen_store_fpr32(fp0, fs);
+ tcg_temp_free(fp0);
+ }
opn = "mtc1";
break;
case OPC_CFC1:
@@ -5901,27 +5937,47 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
opn = "ctc1";
break;
case OPC_DMFC1:
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_mov_tl(t0, fpu64_T[0]);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_mov_tl(t0, fp0);
+ tcg_temp_free(fp0);
+ }
gen_store_gpr(t0, rt);
opn = "dmfc1";
break;
case OPC_DMTC1:
gen_load_gpr(t0, rt);
- tcg_gen_mov_tl(fpu64_T[0], t0);
- gen_store_fpr64(ctx, fpu64_T[0], fs);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ tcg_gen_mov_tl(fp0, t0);
+ gen_store_fpr64(ctx, fp0, fs);
+ tcg_temp_free(fp0);
+ }
opn = "dmtc1";
break;
case OPC_MFHC1:
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_ext_i32_tl(t0, fpu32h_T[0]);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32h(fp0, fs);
+ tcg_gen_ext_i32_tl(t0, fp0);
+ tcg_temp_free(fp0);
+ }
gen_store_gpr(t0, rt);
opn = "mfhc1";
break;
case OPC_MTHC1:
gen_load_gpr(t0, rt);
- tcg_gen_trunc_tl_i32(fpu32h_T[0], t0);
- gen_store_fpr32h(fpu32h_T[0], fs);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_trunc_tl_i32(fp0, t0);
+ gen_store_fpr32h(fp0, fs);
+ tcg_temp_free(fp0);
+ }
opn = "mthc1";
break;
default:
@@ -5973,11 +6029,13 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
tcg_temp_free(t0);
}
-static inline void gen_movcf_s (int cc, int tf)
+static inline void gen_movcf_s (int fs, int fd, int cc, int tf)
{
uint32_t ccbit;
int cond;
- TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv r_tmp1 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_local_new(TCG_TYPE_I32);
int l1 = gen_new_label();
if (cc)
@@ -5990,19 +6048,26 @@ static inline void gen_movcf_s (int cc, int tf)
else
cond = TCG_COND_NE;
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, fd);
tcg_gen_ld_i32(r_tmp1, current_fpu, offsetof(CPUMIPSFPUContext, fcr31));
tcg_gen_andi_i32(r_tmp1, r_tmp1, ccbit);
tcg_gen_brcondi_i32(cond, r_tmp1, 0, l1);
- tcg_gen_movi_i32(fpu32_T[2], fpu32_T[0]);
+ tcg_gen_movi_i32(fp1, fp0);
+ tcg_temp_free(fp0);
gen_set_label(l1);
tcg_temp_free(r_tmp1);
+ gen_store_fpr32(fp1, fd);
+ tcg_temp_free(fp1);
}
-static inline void gen_movcf_d (int cc, int tf)
+static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf)
{
uint32_t ccbit;
int cond;
- TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv r_tmp1 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_local_new(TCG_TYPE_I64);
int l1 = gen_new_label();
if (cc)
@@ -6015,19 +6080,28 @@ static inline void gen_movcf_d (int cc, int tf)
else
cond = TCG_COND_NE;
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, fd);
tcg_gen_ld_i32(r_tmp1, current_fpu, offsetof(CPUMIPSFPUContext, fcr31));
tcg_gen_andi_i32(r_tmp1, r_tmp1, ccbit);
tcg_gen_brcondi_i32(cond, r_tmp1, 0, l1);
- tcg_gen_movi_i64(fpu64_T[2], fpu64_T[0]);
+ tcg_gen_movi_i64(fp1, fp0);
+ tcg_temp_free(fp0);
gen_set_label(l1);
tcg_temp_free(r_tmp1);
+ gen_store_fpr64(ctx, fp1, fd);
+ tcg_temp_free(fp1);
}
-static inline void gen_movcf_ps (int cc, int tf)
+static inline void gen_movcf_ps (int fs, int fd, int cc, int tf)
{
int cond;
TCGv r_tmp1 = tcg_temp_local_new(TCG_TYPE_I32);
TCGv r_tmp2 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph1 = tcg_temp_local_new(TCG_TYPE_I32);
int l1 = gen_new_label();
int l2 = gen_new_label();
@@ -6036,18 +6110,28 @@ static inline void gen_movcf_ps (int cc, int tf)
else
cond = TCG_COND_NE;
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32h(fph0, fs);
+ gen_load_fpr32(fp1, fd);
+ gen_load_fpr32h(fph1, fd);
get_fp_cond(r_tmp1);
tcg_gen_shri_i32(r_tmp1, r_tmp1, cc);
tcg_gen_andi_i32(r_tmp2, r_tmp1, 0x1);
tcg_gen_brcondi_i32(cond, r_tmp2, 0, l1);
- tcg_gen_movi_i32(fpu32_T[2], fpu32_T[0]);
+ tcg_gen_movi_i32(fp1, fp0);
+ tcg_temp_free(fp0);
gen_set_label(l1);
tcg_gen_andi_i32(r_tmp2, r_tmp1, 0x2);
tcg_gen_brcondi_i32(cond, r_tmp2, 0, l2);
- tcg_gen_movi_i32(fpu32h_T[2], fpu32h_T[0]);
+ tcg_gen_movi_i32(fph1, fph0);
+ tcg_temp_free(fph0);
gen_set_label(l2);
tcg_temp_free(r_tmp1);
tcg_temp_free(r_tmp2);
+ gen_store_fpr32(fp1, fd);
+ gen_store_fpr32h(fph1, fd);
+ tcg_temp_free(fp1);
+ tcg_temp_free(fph1);
}
@@ -6096,224 +6180,381 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
switch (ctx->opcode & FOP(0x3f, 0x1f)) {
case FOP(0, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- tcg_gen_helper_0_0(do_float_add_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ tcg_gen_helper_1_2(do_float_add_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "add.s";
optype = BINOP;
break;
case FOP(1, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- tcg_gen_helper_0_0(do_float_sub_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ tcg_gen_helper_1_2(do_float_sub_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "sub.s";
optype = BINOP;
break;
case FOP(2, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- tcg_gen_helper_0_0(do_float_mul_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ tcg_gen_helper_1_2(do_float_mul_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mul.s";
optype = BINOP;
break;
case FOP(3, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- tcg_gen_helper_0_0(do_float_div_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ tcg_gen_helper_1_2(do_float_div_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "div.s";
optype = BINOP;
break;
case FOP(4, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_sqrt_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_sqrt_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "sqrt.s";
break;
case FOP(5, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_abs_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_abs_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "abs.s";
break;
case FOP(6, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_store_fpr32(fpu32_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mov.s";
break;
case FOP(7, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_chs_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_chs_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "neg.s";
break;
case FOP(8, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_roundl_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_roundl_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "round.l.s";
break;
case FOP(9, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_truncl_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_truncl_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "trunc.l.s";
break;
case FOP(10, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_ceill_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_ceill_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "ceil.l.s";
break;
case FOP(11, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_floorl_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_floorl_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "floor.l.s";
break;
case FOP(12, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_roundw_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_roundw_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "round.w.s";
break;
case FOP(13, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_truncw_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_truncw_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "trunc.w.s";
break;
case FOP(14, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_ceilw_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_ceilw_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "ceil.w.s";
break;
case FOP(15, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_floorw_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_floorw_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "floor.w.s";
break;
case FOP(17, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- gen_movcf_s((ft >> 2) & 0x7, ft & 0x1);
- gen_store_fpr32(fpu32_T[2], fd);
+ gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.s";
break;
case FOP(18, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i32(fpu32_T[2], fpu32_T[0]);
+ gen_load_fpr32(fp0, fs);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
gen_set_label(l1);
}
- gen_store_fpr32(fpu32_T[2], fd);
opn = "movz.s";
break;
case FOP(19, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i32(fpu32_T[2], fpu32_T[0]);
+ gen_load_fpr32(fp0, fs);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
gen_set_label(l1);
}
- gen_store_fpr32(fpu32_T[2], fd);
opn = "movn.s";
break;
case FOP(21, 16):
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_recip_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_recip_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip.s";
break;
case FOP(22, 16):
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_rsqrt_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_rsqrt_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt.s";
break;
case FOP(28, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- tcg_gen_helper_0_0(do_float_recip2_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, fd);
+ tcg_gen_helper_1_2(do_float_recip2_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip2.s";
break;
case FOP(29, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_recip1_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_recip1_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip1.s";
break;
case FOP(30, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_rsqrt1_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_rsqrt1_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt1.s";
break;
case FOP(31, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[2], ft);
- tcg_gen_helper_0_0(do_float_rsqrt2_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ tcg_gen_helper_1_2(do_float_rsqrt2_s, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt2.s";
break;
case FOP(33, 16):
check_cp1_registers(ctx, fd);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtd_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_cvtd_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "cvt.d.s";
break;
case FOP(36, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtw_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvtw_s, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.w.s";
break;
case FOP(37, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtl_s);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_cvtl_s, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "cvt.l.s";
break;
case FOP(38, 16):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- tcg_gen_extu_i32_i64(fpu64_T[0], fpu32_T[0]);
- tcg_gen_extu_i32_i64(fpu64_T[1], fpu32_T[1]);
- tcg_gen_shli_i64(fpu64_T[1], fpu64_T[1], 32);
- tcg_gen_or_i64(fpu64_T[2], fpu64_T[0], fpu64_T[1]);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp64_0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp64_1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp32_0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp32_1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp32_0, fs);
+ gen_load_fpr32(fp32_1, ft);
+ tcg_gen_extu_i32_i64(fp64_0, fp32_0);
+ tcg_gen_extu_i32_i64(fp64_1, fp32_1);
+ tcg_temp_free(fp32_0);
+ tcg_temp_free(fp32_1);
+ tcg_gen_shli_i64(fp64_1, fp64_1, 32);
+ tcg_gen_or_i64(fp64_0, fp64_0, fp64_1);
+ tcg_temp_free(fp64_1);
+ gen_store_fpr64(ctx, fp64_0, fd);
+ tcg_temp_free(fp64_0);
+ }
opn = "cvt.ps.s";
break;
case FOP(48, 16):
@@ -6332,217 +6573,351 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
case FOP(61, 16):
case FOP(62, 16):
case FOP(63, 16):
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- if (ctx->opcode & (1 << 6)) {
- check_cop1x(ctx);
- gen_cmpabs_s(func-48, cc);
- opn = condnames_abs[func-48];
- } else {
- gen_cmp_s(func-48, cc);
- opn = condnames[func-48];
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ if (ctx->opcode & (1 << 6)) {
+ check_cop1x(ctx);
+ gen_cmpabs_s(func-48, fp0, fp1, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ gen_cmp_s(func-48, fp0, fp1, cc);
+ opn = condnames[func-48];
+ }
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
}
break;
case FOP(0, 17):
check_cp1_registers(ctx, fs | ft | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- tcg_gen_helper_0_0(do_float_add_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_add_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "add.d";
optype = BINOP;
break;
case FOP(1, 17):
check_cp1_registers(ctx, fs | ft | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- tcg_gen_helper_0_0(do_float_sub_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_sub_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "sub.d";
optype = BINOP;
break;
case FOP(2, 17):
check_cp1_registers(ctx, fs | ft | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- tcg_gen_helper_0_0(do_float_mul_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_mul_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mul.d";
optype = BINOP;
break;
case FOP(3, 17):
check_cp1_registers(ctx, fs | ft | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- tcg_gen_helper_0_0(do_float_div_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_div_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "div.d";
optype = BINOP;
break;
case FOP(4, 17):
check_cp1_registers(ctx, fs | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_sqrt_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_sqrt_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "sqrt.d";
break;
case FOP(5, 17):
check_cp1_registers(ctx, fs | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_abs_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_abs_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "abs.d";
break;
case FOP(6, 17):
check_cp1_registers(ctx, fs | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_store_fpr64(ctx, fpu64_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mov.d";
break;
case FOP(7, 17):
check_cp1_registers(ctx, fs | fd);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_chs_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_chs_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "neg.d";
break;
case FOP(8, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_roundl_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_roundl_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "round.l.d";
break;
case FOP(9, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_truncl_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_truncl_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "trunc.l.d";
break;
case FOP(10, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_ceill_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_ceill_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "ceil.l.d";
break;
case FOP(11, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_floorl_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_floorl_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "floor.l.d";
break;
case FOP(12, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_roundw_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_roundw_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "round.w.d";
break;
case FOP(13, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_truncw_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_truncw_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "trunc.w.d";
break;
case FOP(14, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_ceilw_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_ceilw_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "ceil.w.d";
break;
case FOP(15, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_floorw_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_floorw_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "floor.w.d";
break;
case FOP(17, 17):
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[2], fd);
- gen_movcf_d((ft >> 2) & 0x7, ft & 0x1);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.d";
break;
case FOP(18, 17):
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i64(fpu64_T[2], fpu64_T[0]);
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
gen_set_label(l1);
}
- gen_store_fpr64(ctx, fpu64_T[2], fd);
opn = "movz.d";
break;
case FOP(19, 17):
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I64);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i64(fpu64_T[2], fpu64_T[0]);
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
gen_set_label(l1);
}
- gen_store_fpr64(ctx, fpu64_T[2], fd);
opn = "movn.d";
break;
case FOP(21, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_recip_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_recip_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip.d";
break;
case FOP(22, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_rsqrt_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_rsqrt_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt.d";
break;
case FOP(28, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[2], ft);
- tcg_gen_helper_0_0(do_float_recip2_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_recip2_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip2.d";
break;
case FOP(29, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_recip1_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_recip1_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip1.d";
break;
case FOP(30, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_rsqrt1_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_rsqrt1_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt1.d";
break;
case FOP(31, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[2], ft);
- tcg_gen_helper_0_0(do_float_rsqrt2_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_rsqrt2_d, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt2.d";
break;
case FOP(48, 17):
@@ -6561,303 +6936,434 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
case FOP(61, 17):
case FOP(62, 17):
case FOP(63, 17):
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- if (ctx->opcode & (1 << 6)) {
- check_cop1x(ctx);
- check_cp1_registers(ctx, fs | ft);
- gen_cmpabs_d(func-48, cc);
- opn = condnames_abs[func-48];
- } else {
- check_cp1_registers(ctx, fs | ft);
- gen_cmp_d(func-48, cc);
- opn = condnames[func-48];
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ if (ctx->opcode & (1 << 6)) {
+ check_cop1x(ctx);
+ check_cp1_registers(ctx, fs | ft);
+ gen_cmpabs_d(func-48, fp0, fp1, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ check_cp1_registers(ctx, fs | ft);
+ gen_cmp_d(func-48, fp0, fp1, cc);
+ opn = condnames[func-48];
+ }
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
}
break;
case FOP(32, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvts_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_cvts_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "cvt.s.d";
break;
case FOP(36, 17):
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtw_d);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_cvtw_d, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "cvt.w.d";
break;
case FOP(37, 17):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtl_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvtl_d, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.l.d";
break;
case FOP(32, 20):
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvts_w);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvts_w, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.s.w";
break;
case FOP(33, 20):
check_cp1_registers(ctx, fd);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtd_w);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr32(fp32, fs);
+ tcg_gen_helper_1_1(do_float_cvtd_w, fp64, fp32);
+ tcg_temp_free(fp32);
+ gen_store_fpr64(ctx, fp64, fd);
+ tcg_temp_free(fp64);
+ }
opn = "cvt.d.w";
break;
case FOP(32, 21):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvts_l);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp32 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp64 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp64, fs);
+ tcg_gen_helper_1_1(do_float_cvts_l, fp32, fp64);
+ tcg_temp_free(fp64);
+ gen_store_fpr32(fp32, fd);
+ tcg_temp_free(fp32);
+ }
opn = "cvt.s.l";
break;
case FOP(33, 21):
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtd_l);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvtd_l, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.d.l";
break;
case FOP(38, 20):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtps_pw);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvtps_pw, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.ps.pw";
break;
case FOP(0, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- tcg_gen_helper_0_0(do_float_add_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_add_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "add.ps";
break;
case FOP(1, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- tcg_gen_helper_0_0(do_float_sub_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_sub_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "sub.ps";
break;
case FOP(2, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- tcg_gen_helper_0_0(do_float_mul_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_mul_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mul.ps";
break;
case FOP(5, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_abs_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_abs_ps, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "abs.ps";
break;
case FOP(6, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_store_fpr32(fpu32_T[0], fd);
- gen_store_fpr32h(fpu32h_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mov.ps";
break;
case FOP(7, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_chs_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_chs_ps, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "neg.ps";
break;
case FOP(17, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- gen_load_fpr32h(fpu32h_T[2], fd);
- gen_movcf_ps((ft >> 2) & 0x7, ft & 0x1);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.ps";
break;
case FOP(18, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- gen_load_fpr32h(fpu32h_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i32(fpu32_T[2], fpu32_T[0]);
- tcg_gen_mov_i32(fpu32h_T[2], fpu32h_T[0]);
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32h(fph0, fs);
+ gen_store_fpr32(fp0, fd);
+ gen_store_fpr32h(fph0, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fph0);
gen_set_label(l1);
}
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
opn = "movz.ps";
break;
case FOP(19, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- gen_load_fpr32h(fpu32h_T[2], fd);
{
int l1 = gen_new_label();
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32);
gen_load_gpr(t0, ft);
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
tcg_temp_free(t0);
- tcg_gen_mov_i32(fpu32_T[2], fpu32_T[0]);
- tcg_gen_mov_i32(fpu32h_T[2], fpu32h_T[0]);
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32h(fph0, fs);
+ gen_store_fpr32(fp0, fd);
+ gen_store_fpr32h(fph0, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fph0);
gen_set_label(l1);
}
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
opn = "movn.ps";
break;
case FOP(24, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], ft);
- gen_load_fpr32h(fpu32h_T[0], ft);
- gen_load_fpr32(fpu32_T[1], fs);
- gen_load_fpr32h(fpu32h_T[1], fs);
- tcg_gen_helper_0_0(do_float_addr_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, ft);
+ gen_load_fpr64(ctx, fp1, fs);
+ tcg_gen_helper_1_2(do_float_addr_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "addr.ps";
break;
case FOP(26, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], ft);
- gen_load_fpr32h(fpu32h_T[0], ft);
- gen_load_fpr32(fpu32_T[1], fs);
- gen_load_fpr32h(fpu32h_T[1], fs);
- tcg_gen_helper_0_0(do_float_mulr_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, ft);
+ gen_load_fpr64(ctx, fp1, fs);
+ tcg_gen_helper_1_2(do_float_mulr_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "mulr.ps";
break;
case FOP(28, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[2], fd);
- gen_load_fpr32h(fpu32h_T[2], fd);
- tcg_gen_helper_0_0(do_float_recip2_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, fd);
+ tcg_gen_helper_1_2(do_float_recip2_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip2.ps";
break;
case FOP(29, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_recip1_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_recip1_ps, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "recip1.ps";
break;
case FOP(30, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_rsqrt1_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_rsqrt1_ps, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt1.ps";
break;
case FOP(31, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[2], ft);
- gen_load_fpr32h(fpu32h_T[2], ft);
- tcg_gen_helper_0_0(do_float_rsqrt2_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ tcg_gen_helper_1_2(do_float_rsqrt2_ps, fp0, fp0, fp1);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "rsqrt2.ps";
break;
case FOP(32, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvts_pu);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32h(fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvts_pu, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.s.pu";
break;
case FOP(36, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvtpw_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvtpw_ps, fp0, fp0);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.pw.ps";
break;
case FOP(40, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_helper_0_0(do_float_cvts_pl);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_helper_1_1(do_float_cvts_pl, fp0, fp0);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "cvt.s.pl";
break;
case FOP(44, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_store_fpr32h(fpu32_T[0], fd);
- gen_store_fpr32(fpu32_T[1], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_store_fpr32h(fp0, fd);
+ gen_store_fpr32(fp1, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ }
opn = "pll.ps";
break;
case FOP(45, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_store_fpr32(fpu32h_T[1], fd);
- gen_store_fpr32h(fpu32_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32h(fp1, ft);
+ gen_store_fpr32(fp1, fd);
+ gen_store_fpr32h(fp0, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ }
opn = "plu.ps";
break;
case FOP(46, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_store_fpr32(fpu32_T[1], fd);
- gen_store_fpr32h(fpu32h_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32h(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_store_fpr32(fp1, fd);
+ gen_store_fpr32h(fp0, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ }
opn = "pul.ps";
break;
case FOP(47, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_store_fpr32(fpu32h_T[1], fd);
- gen_store_fpr32h(fpu32h_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32h(fp0, fs);
+ gen_load_fpr32h(fp1, ft);
+ gen_store_fpr32(fp1, fd);
+ gen_store_fpr32h(fp0, fd);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ }
opn = "puu.ps";
break;
case FOP(48, 22):
@@ -6877,16 +7383,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
case FOP(62, 22):
case FOP(63, 22):
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- if (ctx->opcode & (1 << 6)) {
- gen_cmpabs_ps(func-48, cc);
- opn = condnames_abs[func-48];
- } else {
- gen_cmp_ps(func-48, cc);
- opn = condnames[func-48];
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ if (ctx->opcode & (1 << 6)) {
+ gen_cmpabs_ps(func-48, fp0, fp1, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ gen_cmp_ps(func-48, fp0, fp1, cc);
+ opn = condnames[func-48];
+ }
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
}
break;
default:
@@ -6930,44 +7441,74 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
switch (opc) {
case OPC_LWXC1:
check_cop1x(ctx);
- tcg_gen_qemu_ld32s(fpu32_T[0], t0, ctx->mem_idx);
- gen_store_fpr32(fpu32_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ tcg_gen_qemu_ld32s(fp0, t0, ctx->mem_idx);
+ gen_store_fpr32(fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "lwxc1";
break;
case OPC_LDXC1:
check_cop1x(ctx);
check_cp1_registers(ctx, fd);
- tcg_gen_qemu_ld64(fpu64_T[0], t0, ctx->mem_idx);
- gen_store_fpr64(ctx, fpu64_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "ldxc1";
break;
case OPC_LUXC1:
check_cp1_64bitmode(ctx);
tcg_gen_andi_tl(t0, t0, ~0x7);
- tcg_gen_qemu_ld64(fpu64_T[0], t0, ctx->mem_idx);
- gen_store_fpr64(ctx, fpu64_T[0], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
+ gen_store_fpr64(ctx, fp0, fd);
+ tcg_temp_free(fp0);
+ }
opn = "luxc1";
break;
case OPC_SWXC1:
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- tcg_gen_qemu_st32(fpu32_T[0], t0, ctx->mem_idx);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ tcg_gen_qemu_st32(fp0, t0, ctx->mem_idx);
+ tcg_temp_free(fp0);
+ }
opn = "swxc1";
store = 1;
break;
case OPC_SDXC1:
check_cop1x(ctx);
check_cp1_registers(ctx, fs);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- tcg_gen_qemu_st64(fpu64_T[0], t0, ctx->mem_idx);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+ tcg_temp_free(fp0);
+ }
opn = "sdxc1";
store = 1;
break;
case OPC_SUXC1:
check_cp1_64bitmode(ctx);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
tcg_gen_andi_tl(t0, t0, ~0x7);
- tcg_gen_qemu_st64(fpu64_T[0], t0, ctx->mem_idx);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
+ tcg_temp_free(fp0);
+ }
opn = "suxc1";
store = 1;
break;
@@ -6994,162 +7535,260 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
check_cp1_64bitmode(ctx);
{
TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
+ TCGv fp0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph0 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_local_new(TCG_TYPE_I32);
+ TCGv fph1 = tcg_temp_local_new(TCG_TYPE_I32);
int l1 = gen_new_label();
int l2 = gen_new_label();
gen_load_gpr(t0, fr);
tcg_gen_andi_tl(t0, t0, 0x7);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32h(fph0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_load_fpr32h(fph1, ft);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
- tcg_gen_mov_i32(fpu32_T[2], fpu32_T[0]);
- tcg_gen_mov_i32(fpu32h_T[2], fpu32h_T[0]);
+ gen_store_fpr32(fp0, fd);
+ gen_store_fpr32h(fph0, fd);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2);
tcg_temp_free(t0);
#ifdef TARGET_WORDS_BIGENDIAN
- tcg_gen_mov_i32(fpu32h_T[2], fpu32_T[0]);
- tcg_gen_mov_i32(fpu32_T[2], fpu32h_T[1]);
+ gen_store_fpr32(fph1, fd);
+ gen_store_fpr32h(fp0, fd);
#else
- tcg_gen_mov_i32(fpu32h_T[2], fpu32_T[1]);
- tcg_gen_mov_i32(fpu32_T[2], fpu32h_T[0]);
+ gen_store_fpr32(fph0, fd);
+ gen_store_fpr32h(fp1, fd);
#endif
gen_set_label(l2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fph0);
+ tcg_temp_free(fp1);
+ tcg_temp_free(fph1);
}
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
opn = "alnv.ps";
break;
case OPC_MADD_S:
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- tcg_gen_helper_0_0(do_float_muladd_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_load_fpr32(fp2, fr);
+ tcg_gen_helper_1_3(do_float_muladd_s, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "madd.s";
break;
case OPC_MADD_D:
check_cop1x(ctx);
check_cp1_registers(ctx, fd | fs | ft | fr);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- gen_load_fpr64(ctx, fpu64_T[2], fr);
- tcg_gen_helper_0_0(do_float_muladd_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_muladd_d, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "madd.d";
break;
case OPC_MADD_PS:
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- gen_load_fpr32h(fpu32h_T[2], fr);
- tcg_gen_helper_0_0(do_float_muladd_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_muladd_ps, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "madd.ps";
break;
case OPC_MSUB_S:
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- tcg_gen_helper_0_0(do_float_mulsub_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_load_fpr32(fp2, fr);
+ tcg_gen_helper_1_3(do_float_mulsub_s, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "msub.s";
break;
case OPC_MSUB_D:
check_cop1x(ctx);
check_cp1_registers(ctx, fd | fs | ft | fr);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- gen_load_fpr64(ctx, fpu64_T[2], fr);
- tcg_gen_helper_0_0(do_float_mulsub_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_mulsub_d, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "msub.d";
break;
case OPC_MSUB_PS:
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- gen_load_fpr32h(fpu32h_T[2], fr);
- tcg_gen_helper_0_0(do_float_mulsub_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_mulsub_ps, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "msub.ps";
break;
case OPC_NMADD_S:
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmuladd_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_load_fpr32(fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmuladd_s, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmadd.s";
break;
case OPC_NMADD_D:
check_cop1x(ctx);
check_cp1_registers(ctx, fd | fs | ft | fr);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- gen_load_fpr64(ctx, fpu64_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmuladd_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmuladd_d, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmadd.d";
break;
case OPC_NMADD_PS:
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- gen_load_fpr32h(fpu32h_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmuladd_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmuladd_ps, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmadd.ps";
break;
case OPC_NMSUB_S:
check_cop1x(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmulsub_s);
- gen_store_fpr32(fpu32_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I32);
+
+ gen_load_fpr32(fp0, fs);
+ gen_load_fpr32(fp1, ft);
+ gen_load_fpr32(fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmulsub_s, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr32(fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmsub.s";
break;
case OPC_NMSUB_D:
check_cop1x(ctx);
check_cp1_registers(ctx, fd | fs | ft | fr);
- gen_load_fpr64(ctx, fpu64_T[0], fs);
- gen_load_fpr64(ctx, fpu64_T[1], ft);
- gen_load_fpr64(ctx, fpu64_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmulsub_d);
- gen_store_fpr64(ctx, fpu64_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmulsub_d, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmsub.d";
break;
case OPC_NMSUB_PS:
check_cp1_64bitmode(ctx);
- gen_load_fpr32(fpu32_T[0], fs);
- gen_load_fpr32h(fpu32h_T[0], fs);
- gen_load_fpr32(fpu32_T[1], ft);
- gen_load_fpr32h(fpu32h_T[1], ft);
- gen_load_fpr32(fpu32_T[2], fr);
- gen_load_fpr32h(fpu32h_T[2], fr);
- tcg_gen_helper_0_0(do_float_nmulsub_ps);
- gen_store_fpr32(fpu32_T[2], fd);
- gen_store_fpr32h(fpu32h_T[2], fd);
+ {
+ TCGv fp0 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp1 = tcg_temp_new(TCG_TYPE_I64);
+ TCGv fp2 = tcg_temp_new(TCG_TYPE_I64);
+
+ gen_load_fpr64(ctx, fp0, fs);
+ gen_load_fpr64(ctx, fp1, ft);
+ gen_load_fpr64(ctx, fp2, fr);
+ tcg_gen_helper_1_3(do_float_nmulsub_ps, fp2, fp0, fp1, fp2);
+ tcg_temp_free(fp0);
+ tcg_temp_free(fp1);
+ gen_store_fpr64(ctx, fp2, fd);
+ tcg_temp_free(fp2);
+ }
opn = "nmsub.ps";
break;
default:
@@ -7187,19 +7826,16 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
/* Handle blikely not taken case */
if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
- TCGv r_tmp = tcg_temp_local_new(TCG_TYPE_TL);
int l1 = gen_new_label();
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
- tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, bcond));
- tcg_gen_brcondi_tl(TCG_COND_NE, r_tmp, 0, l1);
- tcg_temp_free(r_tmp);
+ tcg_gen_brcondi_i32(TCG_COND_NE, bcond, 0, l1);
{
- TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I32);
+ TCGv r_tmp = tcg_temp_new(TCG_TYPE_I32);
- tcg_gen_movi_i32(r_tmp2, ctx->hflags & ~MIPS_HFLAG_BMASK);
- tcg_gen_st_i32(r_tmp2, cpu_env, offsetof(CPUState, hflags));
- tcg_temp_free(r_tmp2);
+ tcg_gen_movi_i32(r_tmp, ctx->hflags & ~MIPS_HFLAG_BMASK);
+ tcg_gen_st_i32(r_tmp, cpu_env, offsetof(CPUState, hflags));
+ tcg_temp_free(r_tmp);
}
gen_goto_tb(ctx, 1, ctx->pc + 4);
gen_set_label(l1);
@@ -7376,7 +8012,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (op2) {
case OPC_WSBH:
gen_load_gpr(t1, rt);
- tcg_gen_helper_1_2(do_wsbh, t0, t0, t1);
+ tcg_gen_helper_1_1(do_wsbh, t0, t1);
gen_store_gpr(t0, rd);
break;
case OPC_SEB:
@@ -7406,19 +8042,19 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (rd) {
case 0:
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_rdhwr_cpunum, t0, t0);
+ tcg_gen_helper_1_0(do_rdhwr_cpunum, t0);
break;
case 1:
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_rdhwr_synci_step, t0, t0);
+ tcg_gen_helper_1_0(do_rdhwr_synci_step, t0);
break;
case 2:
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_rdhwr_cc, t0, t0);
+ tcg_gen_helper_1_0(do_rdhwr_cc, t0);
break;
case 3:
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_rdhwr_ccres, t0, t0);
+ tcg_gen_helper_1_0(do_rdhwr_ccres, t0);
break;
case 29:
#if defined (CONFIG_USER_ONLY)
@@ -7478,11 +8114,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (op2) {
case OPC_DSBH:
gen_load_gpr(t1, rt);
- tcg_gen_helper_1_2(do_dsbh, t0, t0, t1);
+ tcg_gen_helper_1_1(do_dsbh, t0, t1);
break;
case OPC_DSHD:
gen_load_gpr(t1, rt);
- tcg_gen_helper_1_2(do_dshd, t0, t0, t1);
+ tcg_gen_helper_1_1(do_dshd, t0, t1);
break;
default: /* Invalid */
MIPS_INVAL("dbshfl");
@@ -7568,14 +8204,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_DI:
check_insn(env, ctx, ISA_MIPS32R2);
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_di, t0, t0);
+ tcg_gen_helper_1_0(do_di, t0);
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break;
case OPC_EI:
check_insn(env, ctx, ISA_MIPS32R2);
save_cpu_state(ctx, 1);
- tcg_gen_helper_1_1(do_ei, t0, t0);
+ tcg_gen_helper_1_0(do_ei, t0);
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break;
@@ -7780,6 +8416,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
ctx->hflags &= ~MIPS_HFLAG_BMASK;
ctx->bstate = BS_BRANCH;
save_cpu_state(ctx, 0);
+ /* FIXME: Need to clear can_do_io. */
switch (hflags) {
case MIPS_HFLAG_B:
/* unconditional branch */
@@ -7795,12 +8432,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
/* Conditional branch */
MIPS_DEBUG("conditional branch");
{
- TCGv r_tmp = tcg_temp_local_new(TCG_TYPE_TL);
int l1 = gen_new_label();
- tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, bcond));
- tcg_gen_brcondi_tl(TCG_COND_NE, r_tmp, 0, l1);
- tcg_temp_free(r_tmp);
+ tcg_gen_brcondi_i32(TCG_COND_NE, bcond, 0, l1);
gen_goto_tb(ctx, 1, ctx->pc + 4);
gen_set_label(l1);
gen_goto_tb(ctx, 0, ctx->btarget);
@@ -7809,7 +8443,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case MIPS_HFLAG_BR:
/* unconditional branch to register */
MIPS_DEBUG("branch to register");
- gen_breg_pc();
+ tcg_gen_st_tl(btarget, cpu_env, offsetof(CPUState, active_tc.PC));
tcg_gen_exit_tb(0);
break;
default:
@@ -7819,7 +8453,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
}
}
-static always_inline int
+static inline int
gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int search_pc)
{
@@ -7827,6 +8461,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
target_ulong pc_start;
uint16_t *gen_opc_end;
int j, lj = -1;
+ int num_insns;
+ int max_insns;
if (search_pc && loglevel)
fprintf (logfile, "search pc %d\n", search_pc);
@@ -7846,6 +8482,10 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
#else
ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU;
#endif
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
#ifdef DEBUG_DISAS
if (loglevel & CPU_LOG_TB_CPU) {
fprintf(logfile, "------------------------------------------------\n");
@@ -7858,6 +8498,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
fprintf(logfile, "\ntb %p idx %d hflags %04x\n",
tb, ctx.mem_idx, ctx.hflags);
#endif
+ gen_icount_start();
while (ctx.bstate == BS_NONE) {
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
@@ -7883,10 +8524,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
gen_opc_pc[lj] = ctx.pc;
gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
ctx.opcode = ldl_code(ctx.pc);
decode_opc(env, &ctx);
ctx.pc += 4;
+ num_insns++;
if (env->singlestep_enabled)
break;
@@ -7897,13 +8542,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
if (gen_opc_ptr >= gen_opc_end)
break;
- if (gen_opc_ptr >= gen_opc_end)
+ if (num_insns >= max_insns)
break;
-
#if defined (MIPS_SINGLE_STEP)
break;
#endif
}
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
if (env->singlestep_enabled) {
save_cpu_state(&ctx, ctx.bstate == BS_NONE);
tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG);
@@ -7927,6 +8573,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
}
}
done_generating:
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (search_pc) {
j = gen_opc_ptr - gen_opc_buf;
@@ -7935,6 +8582,7 @@ done_generating:
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = ctx.pc - pc_start;
+ tb->icount = num_insns;
}
#ifdef DEBUG_DISAS
#if defined MIPS_DEBUG_DISAS
@@ -7991,9 +8639,6 @@ void fpu_dump_state(CPUState *env, FILE *f,
fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n",
env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status,
get_float_exception_flags(&env->fpu->fp_status));
- fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
- fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
- fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
fpu_fprintf(f, "%3s: ", fregnames[i]);
printfpr(&env->fpu->fpr[i]);
@@ -8009,8 +8654,8 @@ void dump_fpu (CPUState *env)
"pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
" LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx
" %04x\n",
- env->PC[env->current_tc], env->HI[env->current_tc][0],
- env->LO[env->current_tc][0], env->hflags, env->btarget,
+ env->active_tc.PC, env->active_tc.HI[0],
+ env->active_tc.LO[0], env->hflags, env->btarget,
env->bcond);
fpu_dump_state(env, logfile, fprintf, 0);
}
@@ -8018,7 +8663,7 @@ void dump_fpu (CPUState *env)
#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
/* Debug help: The architecture requires 32bit code to maintain proper
- sign-extened values on 64bit machines. */
+ sign-extended values on 64bit machines. */
#define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff))
@@ -8028,18 +8673,18 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
{
int i;
- if (!SIGN_EXT_P(env->PC[env->current_tc]))
- cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]);
- if (!SIGN_EXT_P(env->HI[env->current_tc][0]))
- cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc][0]);
- if (!SIGN_EXT_P(env->LO[env->current_tc][0]))
- cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc][0]);
+ if (!SIGN_EXT_P(env->active_tc.PC))
+ cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC);
+ if (!SIGN_EXT_P(env->active_tc.HI[0]))
+ cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]);
+ if (!SIGN_EXT_P(env->active_tc.LO[0]))
+ cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]);
if (!SIGN_EXT_P(env->btarget))
cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
for (i = 0; i < 32; i++) {
- if (!SIGN_EXT_P(env->gpr[env->current_tc][i]))
- cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[env->current_tc][i]);
+ if (!SIGN_EXT_P(env->active_tc.gpr[i]))
+ cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]);
}
if (!SIGN_EXT_P(env->CP0_EPC))
@@ -8056,11 +8701,11 @@ void cpu_dump_state (CPUState *env, FILE *f,
int i;
cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
- env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond);
+ env->active_tc.PC, env->active_tc.HI, env->active_tc.LO, env->hflags, env->btarget, env->bcond);
for (i = 0; i < 32; i++) {
if ((i & 3) == 0)
cpu_fprintf(f, "GPR%02d:", i);
- cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[env->current_tc][i]);
+ cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]);
if ((i & 3) == 3)
cpu_fprintf(f, "\n");
}
@@ -8085,14 +8730,10 @@ static void mips_tcg_init(void)
return;
cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
- current_tc_gprs = tcg_global_mem_new(TCG_TYPE_PTR,
- TCG_AREG0,
- offsetof(CPUState, current_tc_gprs),
- "current_tc_gprs");
- current_tc_hi = tcg_global_mem_new(TCG_TYPE_PTR,
- TCG_AREG0,
- offsetof(CPUState, current_tc_hi),
- "current_tc_hi");
+ bcond = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0,
+ offsetof(CPUState, bcond), "bcond");
+ btarget = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0,
+ offsetof(CPUState, btarget), "btarget");
current_fpu = tcg_global_mem_new(TCG_TYPE_PTR,
TCG_AREG0,
offsetof(CPUState, fpu),
@@ -8103,16 +8744,6 @@ static void mips_tcg_init(void)
#define DEF_HELPER(ret, name, params) tcg_register_helper(name, #name);
#include "helper.h"
- fpu32_T[0] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft0.w[FP_ENDIAN_IDX]), "WT0");
- fpu32_T[1] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft1.w[FP_ENDIAN_IDX]), "WT1");
- fpu32_T[2] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft2.w[FP_ENDIAN_IDX]), "WT2");
- fpu64_T[0] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, offsetof(CPUState, ft0.d), "DT0");
- fpu64_T[1] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, offsetof(CPUState, ft1.d), "DT1");
- fpu64_T[2] = tcg_global_mem_new(TCG_TYPE_I64, TCG_AREG0, offsetof(CPUState, ft2.d), "DT2");
- fpu32h_T[0] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft0.w[!FP_ENDIAN_IDX]), "WTH0");
- fpu32h_T[1] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft1.w[!FP_ENDIAN_IDX]), "WTH1");
- fpu32h_T[2] = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, ft2.w[!FP_ENDIAN_IDX]), "WTH2");
-
inited = 1;
}
@@ -8149,11 +8780,11 @@ void cpu_reset (CPUMIPSState *env)
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
* come back to the jump. */
- env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
+ env->CP0_ErrorEPC = env->active_tc.PC - 4;
} else {
- env->CP0_ErrorEPC = env->PC[env->current_tc];
+ env->CP0_ErrorEPC = env->active_tc.PC;
}
- env->PC[env->current_tc] = (int32_t)0xBFC00000;
+ env->active_tc.PC = (int32_t)0xBFC00000;
env->CP0_Wired = 0;
/* SMP not implemented */
env->CP0_EBase = 0x80000000;
@@ -8187,7 +8818,7 @@ void cpu_reset (CPUMIPSState *env)
void gen_pc_load(CPUState *env, TranslationBlock *tb,
unsigned long searched_pc, int pc_pos, void *puc)
{
- env->PC[env->current_tc] = gen_opc_pc[pc_pos];
+ env->active_tc.PC = gen_opc_pc[pc_pos];
env->hflags &= ~MIPS_HFLAG_BMASK;
env->hflags |= gen_opc_hflags[pc_pos];
}
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index d84bee01e..b7d68cc28 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -546,8 +546,6 @@ static int cpu_mips_register (CPUMIPSState *env, const mips_def_t *def)
env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
env->CP0_SRSCtl = def->CP0_SRSCtl;
env->current_tc = 0;
- env->current_tc_gprs = &env->gpr[env->current_tc][0];
- env->current_tc_hi = &env->HI[env->current_tc][0];
env->SEGBITS = def->SEGBITS;
env->SEGMask = (target_ulong)((1ULL << def->SEGBITS) - 1);
#if defined(TARGET_MIPS64)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 6d9873822..ff0bbfbd9 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -648,7 +648,6 @@ struct CPUPPCState {
uint32_t flags;
int error_code;
- int interrupt_request;
uint32_t pending_interrupts;
#if !defined(CONFIG_USER_ONLY)
/* This is the IRQ controller, which is implementation dependant
@@ -672,7 +671,6 @@ struct CPUPPCState {
opc_handler_t *opcodes[0x40];
/* Those resources are used only in Qemu core */
- int user_mode_only; /* user mode only simulation */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */
int mmu_idx; /* precomputed MMU index to speed up mem accesses */
@@ -698,6 +696,7 @@ struct mmu_ctx_t {
/*****************************************************************************/
CPUPPCState *cpu_ppc_init (const char *cpu_model);
+void ppc_translate_init(void);
int cpu_ppc_exec (CPUPPCState *s);
void cpu_ppc_close (CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
@@ -813,6 +812,8 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
#define cpu_signal_handler cpu_ppc_signal_handler
#define cpu_list ppc_cpu_list
+#define CPU_SAVE_VERSION 3
+
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _user
#define MMU_MODE1_SUFFIX _kernel
@@ -834,6 +835,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) env->nip = tb->pc
+
#include "cpu-all.h"
/*****************************************************************************/
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index feff961ec..a53b5acaf 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2978,6 +2978,7 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
if (!env)
return NULL;
cpu_exec_init(env);
+ ppc_translate_init();
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
cpu_ppc_reset(env);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 28cb6abdd..e0c318582 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -43,6 +43,19 @@
/*****************************************************************************/
/* Code translation helpers */
+static TCGv cpu_env;
+
+#include "gen-icount.h"
+
+void ppc_translate_init(void)
+{
+ static int done_init = 0;
+ if (done_init)
+ return;
+ cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
+ done_init = 1;
+}
+
#if defined(OPTIMIZE_FPRF_UPDATE)
static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
static uint16_t **gen_fprf_ptr;
@@ -6168,6 +6181,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
uint16_t *gen_opc_end;
int supervisor, little_endian;
int j, lj = -1;
+ int num_insns;
+ int max_insns;
pc_start = tb->pc;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -6211,6 +6226,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
/* Single step trace mode */
msr_se = 1;
#endif
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+
+ gen_icount_start();
/* Set env in case of segfault during code fetch */
while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
if (unlikely(env->nb_breakpoints > 0)) {
@@ -6230,6 +6251,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = ctx.nip;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
}
#if defined PPC_DEBUG_DISAS
@@ -6239,6 +6261,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
ctx.nip, supervisor, (int)msr_ir);
}
#endif
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
if (unlikely(little_endian)) {
ctx.opcode = bswap32(ldl_code(ctx.nip));
} else {
@@ -6253,6 +6277,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
#endif
ctx.nip += 4;
table = env->opcodes;
+ num_insns++;
handler = table[opc1(ctx.opcode)];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
@@ -6306,7 +6331,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
ctx.exception != POWERPC_EXCP_BRANCH)) {
GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
} else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled))) {
+ (env->singlestep_enabled) ||
+ num_insns >= max_insns)) {
/* if we reach a page boundary or are single stepping, stop
* generation
*/
@@ -6316,6 +6342,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
break;
#endif
}
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
if (ctx.exception == POWERPC_EXCP_NONE) {
gen_goto_tb(&ctx, 0, ctx.nip);
} else if (ctx.exception != POWERPC_EXCP_BRANCH) {
@@ -6326,6 +6354,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
/* Generate the return instruction */
tcg_gen_exit_tb(0);
}
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (unlikely(search_pc)) {
j = gen_opc_ptr - gen_opc_buf;
@@ -6334,6 +6363,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
gen_opc_instr_start[lj++] = 0;
} else {
tb->size = ctx.nip - pc_start;
+ tb->icount = num_insns;
}
#if defined(DEBUG_DISAS)
if (loglevel & CPU_LOG_TB_CPU) {
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index c349bc886..9dbadf4d3 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -114,8 +114,6 @@ typedef struct CPUSH4State {
uint32_t expevt; /* exception event register */
uint32_t intevt; /* interrupt event register */
- int user_mode_only;
- int interrupt_request;
CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */
tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
void *intc_handle;
@@ -152,6 +150,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) do { \
+ env->pc = tb->pc; \
+ env->flags = tb->flags; \
+ } while (0)
+
#include "cpu-all.h"
/* Memory access type */
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 3564a6761..0a6f4171f 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -56,6 +56,19 @@ enum {
BS_EXCP = 3, /* We reached an exception condition */
};
+static TCGv cpu_env;
+
+#include "gen-icount.h"
+
+static void sh4_translate_init()
+{
+ static int done_init = 0;
+ if (done_init)
+ return;
+ cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
+ done_init = 1;
+}
+
#ifdef CONFIG_USER_ONLY
#define GEN_OP_LD(width, reg) \
@@ -143,6 +156,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model)
if (!env)
return NULL;
cpu_exec_init(env);
+ sh4_translate_init();
cpu_sh4_reset(env);
tlb_flush(env, 1);
return env;
@@ -1189,6 +1203,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
target_ulong pc_start;
static uint16_t *gen_opc_end;
int i, ii;
+ int num_insns;
+ int max_insns;
pc_start = tb->pc;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -1213,6 +1229,11 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
#endif
ii = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+ gen_icount_start();
while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
if (env->nb_breakpoints > 0) {
for (i = 0; i < env->nb_breakpoints; i++) {
@@ -1235,22 +1256,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
gen_opc_pc[ii] = ctx.pc;
gen_opc_hflags[ii] = ctx.flags;
gen_opc_instr_start[ii] = 1;
+ gen_opc_icount[ii] = num_insns;
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
#if 0
fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc);
fflush(stderr);
#endif
ctx.opcode = lduw_code(ctx.pc);
decode_opc(&ctx);
+ num_insns++;
ctx.pc += 2;
if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
break;
if (env->singlestep_enabled)
break;
+ if (num_insns >= max_insns)
+ break;
#ifdef SH4_SINGLE_STEP
break;
#endif
}
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
if (env->singlestep_enabled) {
gen_op_debug();
} else {
@@ -1274,6 +1303,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
}
}
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (search_pc) {
i = gen_opc_ptr - gen_opc_buf;
@@ -1282,6 +1312,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
gen_opc_instr_start[ii++] = 0;
} else {
tb->size = ctx.pc - pc_start;
+ tb->icount = num_insns;
}
#ifdef DEBUG_DISAS
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index b56dc91ff..937ce6f96 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -215,9 +215,7 @@ typedef struct CPUSPARCState {
uint32_t pil_in; /* incoming interrupt level bitmap */
int psref; /* enable fpu */
target_ulong version;
- int user_mode_only;
int interrupt_index;
- int interrupt_request;
uint32_t mmu_bm;
uint32_t mmu_ctpr_mask;
uint32_t mmu_cxr_mask;
@@ -388,6 +386,8 @@ void cpu_check_irqs(CPUSPARCState *env);
#define cpu_signal_handler cpu_sparc_signal_handler
#define cpu_list sparc_cpu_list
+#define CPU_SAVE_VERSION 4
+
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _user
#define MMU_MODE1_SUFFIX _kernel
@@ -437,6 +437,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
}
#endif
+#define CPU_PC_FROM_TB(env, tb) do { \
+ env->pc = tb->pc; \
+ env->npc = tb->cs_base; \
+ } while(0)
+
#include "cpu-all.h"
#endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index a3e50bd4c..1cfe170de 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1603,7 +1603,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
for (i = 0; i < 32; i++) {
if ((i & 3) == 0)
cpu_fprintf(f, "%%f%02d:", i);
- cpu_fprintf(f, " %016lf", env->fpr[i]);
+ cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
if ((i & 3) == 3)
cpu_fprintf(f, "\n");
}
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index f15cc224b..54db5f4e4 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1687,6 +1687,16 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
}
break;
}
+ case 0x46: // D-cache data
+ case 0x47: // D-cache tag access
+ 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 0x59: // D-MMU 8k TSB pointer
case 0x5a: // D-MMU 64k TSB pointer
case 0x5b: // D-MMU data pointer
@@ -2040,6 +2050,16 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
case 0x49: // Interrupt data receive
// XXX
return;
+ case 0x46: // D-cache data
+ case 0x47: // D-cache tag access
+ 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
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 98c629150..49f998e90 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -48,6 +48,8 @@ static TCGv cpu_xcc;
/* local register indexes (only used inside old micro ops) */
static TCGv cpu_tmp0, cpu_tmp32, cpu_tmp64;
+#include "gen-icount.h"
+
typedef struct DisasContext {
target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
@@ -4719,6 +4721,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
uint16_t *gen_opc_end;
DisasContext dc1, *dc = &dc1;
int j, lj = -1;
+ int num_insns;
+ int max_insns;
memset(dc, 0, sizeof(DisasContext));
dc->tb = tb;
@@ -4747,6 +4751,11 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
cpu_val = tcg_temp_local_new(TCG_TYPE_TL);
cpu_addr = tcg_temp_local_new(TCG_TYPE_TL);
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0)
+ max_insns = CF_COUNT_MASK;
+ gen_icount_start();
do {
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
@@ -4771,10 +4780,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
gen_opc_pc[lj] = dc->pc;
gen_opc_npc[lj] = dc->npc;
gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
}
}
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+ gen_io_start();
last_pc = dc->pc;
disas_sparc_insn(dc);
+ num_insns++;
if (dc->is_br)
break;
@@ -4793,7 +4806,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
break;
}
} while ((gen_opc_ptr < gen_opc_end) &&
- (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+ (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) &&
+ num_insns < max_insns);
exit_gen_loop:
tcg_temp_free(cpu_addr);
@@ -4802,6 +4816,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
tcg_temp_free(cpu_tmp64);
tcg_temp_free(cpu_tmp32);
tcg_temp_free(cpu_tmp0);
+ if (tb->cflags & CF_LAST_IO)
+ gen_io_end();
if (!dc->is_br) {
if (dc->pc != DYNAMIC_PC &&
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
@@ -4814,6 +4830,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
tcg_gen_exit_tb(0);
}
}
+ gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
if (spc) {
j = gen_opc_ptr - gen_opc_buf;
@@ -4829,6 +4846,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
gen_opc_jump_pc[1] = dc->jump_pc[1];
} else {
tb->size = last_pc + 4 - pc_start;
+ tb->icount = num_insns;
}
#ifdef DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index cf453b3e4..a7bd74861 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -360,22 +360,22 @@ static void tcg_out_brcond2(TCGContext *s,
case TCG_COND_LT:
tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
tcg_out_jxx(s, JCC_JNE, label_next);
- tcg_out_brcond(s, TCG_COND_LT, args[0], args[2], const_args[2], args[5]);
+ tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]);
break;
case TCG_COND_LE:
tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
tcg_out_jxx(s, JCC_JNE, label_next);
- tcg_out_brcond(s, TCG_COND_LE, args[0], args[2], const_args[2], args[5]);
+ tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]);
break;
case TCG_COND_GT:
tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
tcg_out_jxx(s, JCC_JNE, label_next);
- tcg_out_brcond(s, TCG_COND_GT, args[0], args[2], const_args[2], args[5]);
+ tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]);
break;
case TCG_COND_GE:
tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
tcg_out_jxx(s, JCC_JNE, label_next);
- tcg_out_brcond(s, TCG_COND_GE, args[0], args[2], const_args[2], args[5]);
+ tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]);
break;
case TCG_COND_LTU:
tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 39319903c..0dcf61225 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -415,7 +415,7 @@ static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
disp = target - (tcg_target_long) s->code_ptr;
if ((disp << 6) >> 6 == disp)
- tcg_out32 (s, B | disp | mask);
+ tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
else {
tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target);
tcg_out32 (s, MTSPR | RS (0) | CTR);
@@ -987,14 +987,11 @@ static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args,
switch (cond) {
case TCG_COND_EQ:
- tcg_out_cmp (s, TCG_COND_EQ, args[0], args[2], const_args[2], 6);
- tcg_out_cmp (s, TCG_COND_EQ, args[1], args[3], const_args[3], 7);
- tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
- break;
case TCG_COND_NE:
- tcg_out_cmp (s, TCG_COND_NE, args[0], args[2], const_args[2], 6);
- tcg_out_cmp (s, TCG_COND_NE, args[1], args[3], const_args[3], 7);
- tcg_out32 (s, CRNAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
+ op = (cond == TCG_COND_EQ) ? CRAND : CRNAND;
+ tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6);
+ tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7);
+ tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
break;
case TCG_COND_LT:
case TCG_COND_LE:
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 492ed3d9a..58f86d35a 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -304,11 +304,10 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
{
#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
if (!check_fit_tl(arg, 32) && (arg & ~0xffffffffULL) != 0) {
- // XXX ret may be I5, need another temp
- tcg_out_movi_imm32(s, TCG_REG_I5, arg >> 32);
- tcg_out_arithi(s, TCG_REG_I5, TCG_REG_I5, 32, SHIFT_SLLX);
+ tcg_out_movi_imm32(s, TCG_REG_I4, arg >> 32);
+ tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX);
tcg_out_movi_imm32(s, ret, arg);
- tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR);
+ tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR);
} else
#endif
tcg_out_movi_imm32(s, ret, arg);
@@ -1137,6 +1136,9 @@ void tcg_target_init(TCGContext *s)
tcg_regset_clear(s->reserved_regs);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0);
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use
+#endif
tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use
tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 9299176ab..2ce36b878 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -143,6 +143,9 @@ typedef int TCGv;
#endif /* DEBUG_TCGV */
+/* Dummy definition to avoid compiler warnings. */
+#define TCGV_UNUSED(x) x = MAKE_TCGV(-1)
+
/* call flags */
#define TCG_CALL_TYPE_MASK 0x000f
#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */
diff --git a/translate-all.c b/translate-all.c
index 8b8b6a281..263649578 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -38,6 +38,7 @@ uint16_t gen_opc_buf[OPC_BUF_SIZE];
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
target_ulong gen_opc_pc[OPC_BUF_SIZE];
+uint16_t gen_opc_icount[OPC_BUF_SIZE];
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
@@ -158,6 +159,13 @@ int cpu_restore_state(TranslationBlock *tb,
if (gen_intermediate_code_pc(env, tb) < 0)
return -1;
+ if (use_icount) {
+ /* Reset the cycle counter to the start of the block. */
+ env->icount_decr.u16.low += tb->icount;
+ /* Clear the IO flag. */
+ env->can_do_io = 0;
+ }
+
/* find opc index corresponding to search_pc */
tc_ptr = (unsigned long)tb->tc_ptr;
if (searched_pc < tc_ptr)
@@ -177,6 +185,7 @@ int cpu_restore_state(TranslationBlock *tb,
/* now find start of instruction before */
while (gen_opc_instr_start[j] == 0)
j--;
+ env->icount_decr.u16.low -= gen_opc_icount[j];
gen_pc_load(env, tb, searched_pc, j, puc);
diff --git a/vl.c b/vl.c
index 3032eafe5..db7095f24 100644
--- a/vl.c
+++ b/vl.c
@@ -251,6 +251,14 @@ struct drive_opt drives_opt[MAX_DRIVES];
static CPUState *cur_cpu;
static CPUState *next_cpu;
static int event_pending = 1;
+/* 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;
+QEMUTimer *icount_rt_timer;
+QEMUTimer *icount_vm_timer;
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
@@ -768,9 +776,22 @@ static int64_t get_clock(void)
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
}
}
-
#endif
+/* Return the virtual CPU time, based on the instruction counter. */
+static 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);
+}
+
/***********************************************************/
/* guest cycle counter */
@@ -782,6 +803,9 @@ static int cpu_ticks_enabled;
/* return the host CPU cycle counter and handle stop/restart */
int64_t cpu_get_ticks(void)
{
+ if (use_icount) {
+ return cpu_get_icount();
+ }
if (!cpu_ticks_enabled) {
return cpu_ticks_offset;
} else {
@@ -913,6 +937,71 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t);
#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 (QEMU_TIMER_BASE / 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 (!vm_running)
+ return;
+
+ cur_time = cpu_get_clock();
+ cur_icount = qemu_get_clock(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(rt_clock) + 1000);
+ icount_adjust();
+}
+
+static void icount_adjust_vm(void * opaque)
+{
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+ icount_adjust();
+}
+
+static void init_icount_adjust(void)
+{
+ /* 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(rt_clock, icount_adjust_rt, NULL);
+ qemu_mod_timer(icount_rt_timer,
+ qemu_get_clock(rt_clock) + 1000);
+ icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+}
+
static struct qemu_alarm_timer alarm_timers[] = {
#ifndef _WIN32
#ifdef __linux__
@@ -949,6 +1038,7 @@ static void configure_alarms(char const *opt)
int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
char *arg;
char *name;
+ struct qemu_alarm_timer tmp;
if (!strcmp(opt, "?")) {
show_available_alarms();
@@ -960,8 +1050,6 @@ static void configure_alarms(char const *opt)
/* Reorder the array */
name = strtok(arg, ",");
while (name) {
- struct qemu_alarm_timer tmp;
-
for (i = 0; i < count && alarm_timers[i].name; i++) {
if (!strcmp(alarm_timers[i].name, name))
break;
@@ -989,7 +1077,7 @@ next:
free(arg);
if (cur) {
- /* Disable remaining timers */
+ /* Disable remaining timers */
for (i = cur; i < count; i++)
alarm_timers[i].name = NULL;
} else {
@@ -1074,9 +1162,15 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
*pt = ts;
/* Rearm if necessary */
- if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 &&
- pt == &active_timers[ts->clock->type])
- qemu_rearm_alarm_timer(alarm_timer);
+ if (pt == &active_timers[ts->clock->type]) {
+ if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) {
+ qemu_rearm_alarm_timer(alarm_timer);
+ }
+ /* Interrupt execution to force deadline recalculation. */
+ if (use_icount && cpu_single_env) {
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+ }
+ }
}
int qemu_timer_pending(QEMUTimer *ts)
@@ -1120,7 +1214,11 @@ int64_t qemu_get_clock(QEMUClock *clock)
return get_clock() / 1000000;
default:
case QEMU_TIMER_VIRTUAL:
- return cpu_get_clock();
+ if (use_icount) {
+ return cpu_get_icount();
+ } else {
+ return cpu_get_clock();
+ }
}
}
@@ -1219,9 +1317,10 @@ static void host_alarm_handler(int host_signum)
}
#endif
if (1 ||
- alarm_has_dynticks(alarm_timer) ||
- qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock)) ||
+ alarm_has_dynticks(alarm_timer) ||
+ (!use_icount &&
+ qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_get_clock(vm_clock))) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
#ifdef _WIN32
@@ -1245,28 +1344,45 @@ static void host_alarm_handler(int host_signum)
}
}
-static uint64_t qemu_next_deadline(void)
+static int64_t qemu_next_deadline(void)
{
- int64_t nearest_delta_us = INT64_MAX;
- int64_t vmdelta_us;
-
- if (active_timers[QEMU_TIMER_REALTIME])
- nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
- qemu_get_clock(rt_clock))*1000;
+ int64_t delta;
if (active_timers[QEMU_TIMER_VIRTUAL]) {
- /* round up */
- vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
- qemu_get_clock(vm_clock)+999)/1000;
- if (vmdelta_us < nearest_delta_us)
- nearest_delta_us = vmdelta_us;
+ delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
+ qemu_get_clock(vm_clock);
+ } else {
+ /* To avoid problems with overflow limit this to 2^32. */
+ delta = INT32_MAX;
+ }
+
+ if (delta < 0)
+ delta = 0;
+
+ return delta;
+}
+
+static uint64_t qemu_next_deadline_dyntick(void)
+{
+ int64_t delta;
+ int64_t rtdelta;
+
+ if (use_icount)
+ delta = INT32_MAX;
+ else
+ delta = (qemu_next_deadline() + 999) / 1000;
+
+ if (active_timers[QEMU_TIMER_REALTIME]) {
+ rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
+ qemu_get_clock(rt_clock))*1000;
+ if (rtdelta < delta)
+ delta = rtdelta;
}
- /* Avoid arming the timer to negative, zero, or too low values */
- if (nearest_delta_us <= MIN_TIMER_REARM_US)
- nearest_delta_us = MIN_TIMER_REARM_US;
+ if (delta < MIN_TIMER_REARM_US)
+ delta = MIN_TIMER_REARM_US;
- return nearest_delta_us;
+ return delta;
}
#ifndef _WIN32
@@ -1422,7 +1538,7 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
!active_timers[QEMU_TIMER_VIRTUAL])
return;
- nearest_delta_us = qemu_next_deadline();
+ nearest_delta_us = qemu_next_deadline_dyntick();
/* check whether a timer is already running */
if (timer_gettime(host_timer, &timeout)) {
@@ -1549,7 +1665,7 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t)
!active_timers[QEMU_TIMER_VIRTUAL])
return;
- nearest_delta_us = qemu_next_deadline();
+ nearest_delta_us = qemu_next_deadline_dyntick();
nearest_delta_us /= 1000;
timeKillEvent(data->timerId);
@@ -6296,6 +6412,8 @@ typedef struct SaveStateEntry {
static SaveStateEntry *first_se;
+/* TODO: Individual devices generally have very little idea about the rest
+ of the system, so instance_id should be removed/replaced. */
int register_savevm(const char *idstr,
int instance_id,
int version_id,
@@ -6309,7 +6427,7 @@ int register_savevm(const char *idstr,
if (!se)
return -1;
pstrcpy(se->idstr, sizeof(se->idstr), idstr);
- se->instance_id = instance_id;
+ se->instance_id = (instance_id == -1) ? 0 : instance_id;
se->version_id = version_id;
se->save_state = save_state;
se->load_state = load_state;
@@ -6318,8 +6436,13 @@ int register_savevm(const char *idstr,
/* add at the end of list */
pse = &first_se;
- while (*pse != NULL)
+ while (*pse != NULL) {
+ if (instance_id == -1
+ && strcmp(se->idstr, (*pse)->idstr) == 0
+ && se->instance_id <= (*pse)->instance_id)
+ se->instance_id = (*pse)->instance_id + 1;
pse = &(*pse)->next;
+ }
*pse = se;
return 0;
}
@@ -7595,10 +7718,33 @@ static int main_loop(void)
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
+ if (use_icount) {
+ int64_t count;
+ int decr;
+ qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+ env->icount_decr.u16.low = 0;
+ env->icount_extra = 0;
+ count = qemu_next_deadline();
+ count = (count + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += count;
+ decr = (count > 0xffff) ? 0xffff : count;
+ count -= decr;
+ env->icount_decr.u16.low = decr;
+ env->icount_extra = count;
+ }
ret = cpu_exec(env);
#ifdef CONFIG_PROFILER
qemu_time += profile_getclock() - ti;
#endif
+ if (use_icount) {
+ /* Fold pending instructions back into the
+ instruction counter, and clear the interrupt flag. */
+ qemu_icount -= (env->icount_decr.u16.low
+ + env->icount_extra);
+ env->icount_decr.u32 = 0;
+ env->icount_extra = 0;
+ }
next_cpu = env->next_cpu ?: first_cpu;
if (event_pending && likely(ret != EXCP_DEBUG)) {
ret = EXCP_INTERRUPT;
@@ -7644,10 +7790,46 @@ static int main_loop(void)
}
/* If all cpus are halted then wait until the next IRQ */
/* XXX: use timeout computed from timers */
- if (ret == EXCP_HALTED)
- timeout = 10;
- else
+ if (ret == EXCP_HALTED) {
+ if (use_icount) {
+ int64_t add;
+ int64_t delta;
+ /* Advance virtual time to the next event. */
+ if (use_icount == 1) {
+ /* When not using an adaptive execution frequency
+ we tend to get badly out of sync with real time,
+ so just delay for a reasonable amount of time. */
+ delta = 0;
+ } else {
+ delta = cpu_get_icount() - cpu_get_clock();
+ }
+ if (delta > 0) {
+ /* If virtual time is ahead of real time then just
+ wait for IO. */
+ timeout = (delta / 1000000) + 1;
+ } else {
+ /* Wait for either IO to occur or the next
+ timer event. */
+ add = qemu_next_deadline();
+ /* We advance the timer before checking for IO.
+ Limit the amount we advance so that early IO
+ activity won't get the guest too far ahead. */
+ if (add > 10000000)
+ add = 10000000;
+ delta += add;
+ add = (add + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += add;
+ timeout = delta / 1000000;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ } else {
+ timeout = 10;
+ }
+ } else {
timeout = 0;
+ }
} else {
timeout = 10;
}
@@ -7812,6 +7994,8 @@ static void help(int exitcode)
"-clock force the use of the given methods for timer alarm.\n"
" To see what timers are available use -clock ?\n"
"-startdate select initial date of the clock\n"
+ "-icount [N|auto]\n"
+ " Enable virtual instruction counter with 2^N clock ticks per instruction\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -7922,6 +8106,7 @@ enum {
QEMU_OPTION_clock,
QEMU_OPTION_startdate,
QEMU_OPTION_tb_size,
+ QEMU_OPTION_icount,
QEMU_OPTION_translation,
QEMU_OPTION_incoming,
QEMU_OPTION_tdf,
@@ -8053,6 +8238,7 @@ const QEMUOption qemu_options[] = {
{ "clock", HAS_ARG, QEMU_OPTION_clock },
{ "startdate", HAS_ARG, QEMU_OPTION_startdate },
{ "tb-size", HAS_ARG, QEMU_OPTION_tb_size },
+ { "icount", HAS_ARG, QEMU_OPTION_icount },
{ "mem-path", HAS_ARG, QEMU_OPTION_mempath },
{ NULL },
};
@@ -8423,7 +8609,7 @@ int main(int argc, char **argv)
kernel_cmdline = "";
cyls = heads = secs = 0;
translation = BIOS_ATA_TRANSLATION_AUTO;
- monitor_device = "vc:800x600";
+ monitor_device = "vc";
for(i = 0; i < MAX_VMCHANNEL_DEVICES; i++)
vmchannel_devices[i][0] = '\0';
@@ -9034,6 +9220,14 @@ int main(int argc, char **argv)
if (tb_size < 0)
tb_size = 0;
break;
+ case QEMU_OPTION_icount:
+ use_icount = 1;
+ if (strcmp(optarg, "auto") == 0) {
+ icount_time_shift = -1;
+ } else {
+ icount_time_shift = strtol(optarg, NULL, 0);
+ }
+ break;
}
}
}
@@ -9118,6 +9312,16 @@ int main(int argc, char **argv)
nb_drives_opt == 0)
help(1);
+ if (!linux_boot && *kernel_cmdline != '\0') {
+ fprintf(stderr, "-append only allowed with -kernel option\n");
+ exit(1);
+ }
+
+ if (!linux_boot && initrd_filename != NULL) {
+ fprintf(stderr, "-initrd only allowed with -kernel option\n");
+ exit(1);
+ }
+
/* boot to floppy or the default cd if no hard disk defined yet */
if (!boot_devices[0]) {
boot_devices = "cad";
@@ -9127,6 +9331,13 @@ int main(int argc, char **argv)
init_timers();
init_timer_alarm();
qemu_aio_init();
+ if (use_icount && icount_time_shift < 0) {
+ use_icount = 2;
+ /* 125MIPS seems a reasonable initial guess at the guest speed.
+ It will be corrected fairly quickly anyway. */
+ icount_time_shift = 3;
+ init_icount_adjust();
+ }
#ifdef _WIN32
socket_init();
diff --git a/vnc_keysym.h b/vnc_keysym.h
index 5c4710444..b6a172de9 100644
--- a/vnc_keysym.h
+++ b/vnc_keysym.h
@@ -289,11 +289,14 @@ static name2keysym_t name2keysym[]={
/* localized keys */
{"BackApostrophe", 0xff21},
{"Muhenkan", 0xff22},
-{"Katakana", 0xff25},
-{"Zenkaku_Hankaku", 0xff29},
+{"Katakana", 0xff27},
+{"Hankaku", 0xff29},
+{"Zenkaku_Hankaku", 0xff2a},
{"Henkan_Mode_Real", 0xff23},
{"Henkan_Mode_Ultra", 0xff3e},
{"backslash_ja", 0xffa5},
+{"Katakana_Real", 0xff25},
+{"Eisu_toggle", 0xff30},
{0,0},
};