summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS13
-rw-r--r--Makefile2
-rw-r--r--Makefile.objs3
-rw-r--r--Makefile.target7
-rw-r--r--arch_init.c2
-rw-r--r--arch_init.h1
-rw-r--r--balloon.c10
-rw-r--r--balloon.h1
-rw-r--r--block.c104
-rw-r--r--block.h63
-rw-r--r--block/nbd.c1
-rw-r--r--block/qcow2-cluster.c27
-rw-r--r--block/qcow2.c14
-rw-r--r--block/qcow2.h1
-rw-r--r--block/raw-posix.c8
-rw-r--r--block/raw.c6
-rw-r--r--block/rbd.c97
-rw-r--r--block_int.h40
-rw-r--r--blockdev.c10
-rwxr-xr-xconfigure15
-rw-r--r--console.c2
-rw-r--r--console.h5
-rw-r--r--cpu-exec.c13
-rw-r--r--default-configs/mips-softmmu.mak1
-rw-r--r--default-configs/mips64-softmmu.mak1
-rw-r--r--default-configs/mips64el-softmmu.mak1
-rw-r--r--default-configs/mipsel-softmmu.mak1
-rw-r--r--default-configs/xtensa-softmmu.mak1
-rw-r--r--default-configs/xtensaeb-softmmu.mak1
-rw-r--r--docs/qdev-device-use.txt2
-rw-r--r--elf.h2
-rw-r--r--gdbstub.c112
-rw-r--r--hw/9pfs/virtio-9p-coth.c4
-rw-r--r--hw/9pfs/virtio-9p-debug.c2
-rw-r--r--hw/fdc.c4
-rw-r--r--hw/g364fb.c16
-rw-r--r--hw/hid.c2
-rw-r--r--hw/ide/ahci.c2
-rw-r--r--hw/ide/ahci.h1
-rw-r--r--hw/ide/atapi.c58
-rw-r--r--hw/ide/cmd646.c1
-rw-r--r--hw/ide/core.c160
-rw-r--r--hw/ide/ich.c1
-rw-r--r--hw/ide/internal.h3
-rw-r--r--hw/ide/isa.c1
-rw-r--r--hw/ide/macio.c1
-rw-r--r--hw/ide/microdrive.c1
-rw-r--r--hw/ide/mmio.c1
-rw-r--r--hw/ide/pci.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/lsi53c895a.c6
-rw-r--r--hw/mips.h3
-rw-r--r--hw/mips_mipssim.c18
-rw-r--r--hw/mipsnet.c106
-rw-r--r--hw/pci.c14
-rw-r--r--hw/pci.h2
-rw-r--r--hw/scsi-bus.c14
-rw-r--r--hw/scsi-disk.c69
-rw-r--r--hw/scsi-generic.c1
-rw-r--r--hw/scsi.h5
-rw-r--r--hw/sd.c2
-rw-r--r--hw/virtio-balloon.c2
-rw-r--r--hw/virtio-blk.c5
-rw-r--r--hw/virtio.h2
-rw-r--r--hw/xen_backend.c40
-rw-r--r--hw/xen_backend.h3
-rw-r--r--hw/xen_console.c4
-rw-r--r--hw/xen_disk.c2
-rw-r--r--hw/xen_nic.c2
-rw-r--r--hw/xenfb.c29
-rw-r--r--hw/xtensa_dc232b.c116
-rw-r--r--hw/xtensa_pic.c134
-rw-r--r--hw/xtensa_sample.c107
-rw-r--r--linux-user/syscall.c3
-rw-r--r--monitor.c2
-rw-r--r--nbd.c1
-rw-r--r--nbd.h4
-rw-r--r--oslib-posix.c14
-rw-r--r--qemu-io.c1
-rw-r--r--qemu-nbd.c2
-rw-r--r--qemu-options.hx14
-rw-r--r--qmp-commands.hx2
-rw-r--r--slirp/libslirp.h2
-rw-r--r--target-i386/kvm.c2
-rw-r--r--target-sparc/cpu.h7
-rw-r--r--target-sparc/helper.c84
-rw-r--r--target-sparc/op_helper.c6
-rw-r--r--target-unicore32/translate.c16
-rw-r--r--target-xtensa/cpu.h425
-rw-r--r--target-xtensa/gdb-config-dc232b.c261
-rw-r--r--target-xtensa/gdb-config-sample-xtensa-core.c375
-rw-r--r--target-xtensa/helper.c763
-rw-r--r--target-xtensa/helpers.h32
-rw-r--r--target-xtensa/machine.c38
-rw-r--r--target-xtensa/op_helper.c675
-rw-r--r--target-xtensa/translate.c2414
-rw-r--r--tcg/ppc64/tcg-target.c2
-rw-r--r--tests/xtensa/Makefile74
-rw-r--r--tests/xtensa/crt.S24
-rw-r--r--tests/xtensa/linker.ld112
-rw-r--r--tests/xtensa/macros.inc68
-rw-r--r--tests/xtensa/test_b.S221
-rw-r--r--tests/xtensa/test_bi.S103
-rw-r--r--tests/xtensa/test_boolean.S23
-rw-r--r--tests/xtensa/test_bz.S57
-rw-r--r--tests/xtensa/test_clamps.S42
-rw-r--r--tests/xtensa/test_fail.S9
-rw-r--r--tests/xtensa/test_interrupt.S194
-rw-r--r--tests/xtensa/test_loop.S77
-rw-r--r--tests/xtensa/test_max.S81
-rw-r--r--tests/xtensa/test_min.S81
-rw-r--r--tests/xtensa/test_mmu.S318
-rw-r--r--tests/xtensa/test_mul16.S83
-rw-r--r--tests/xtensa/test_mul32.S20
-rw-r--r--tests/xtensa/test_nsa.S59
-rw-r--r--tests/xtensa/test_pipeline.S157
-rw-r--r--tests/xtensa/test_quo.S147
-rw-r--r--tests/xtensa/test_rem.S147
-rw-r--r--tests/xtensa/test_rst0.S148
-rw-r--r--tests/xtensa/test_sar.S111
-rw-r--r--tests/xtensa/test_sext.S69
-rw-r--r--tests/xtensa/test_shift.S206
-rw-r--r--tests/xtensa/test_timer.S115
-rw-r--r--tests/xtensa/test_windowed.S302
-rw-r--r--tests/xtensa/vectors.S39
-rw-r--r--trace-events9
-rw-r--r--ui/vnc-tls.c68
-rw-r--r--vl.c3
-rw-r--r--xen-all.c2
-rw-r--r--xen-mapcache.c29
-rw-r--r--xtensa-semi.c224
131 files changed, 9647 insertions, 433 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 508ea1ee24..72b2099d3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -115,6 +115,12 @@ M: qemu-devel@nongnu.org
 S: Odd Fixes
 F: target-i386/
 
+Xtensa
+M: Max Filippov <jcmvbkbc@gmail.com>
+W: http://kkv.spb.su/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
+S: Maintained
+F: target-xtensa/
+
 Guest CPU Cores (KVM):
 ----------------------
 
@@ -335,6 +341,13 @@ M: Anthony Liguori <aliguori@us.ibm.com>
 S: Supported
 F: hw/pc.[ch] hw/pc_piix.c
 
+Xtensa Machines
+---------------
+DC232B
+M: Max Filippov <jcmvbkbc@gmail.com>
+S: Maintained
+F: hw/xtensa_dc232b.c
+
 Devices
 -------
 IDE
diff --git a/Makefile b/Makefile
index e0cf51a8bf..7e9382f101 100644
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,7 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
-version.o: $(SRC_PATH)/version.rc config-host.mak
+version.o: $(SRC_PATH)/version.rc config-host.h
 	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
 version-obj-$(CONFIG_WIN32) += version.o
diff --git a/Makefile.objs b/Makefile.objs
index 26b885bfeb..62020d739c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -240,6 +240,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 
 # MIPS devices
 hw-obj-$(CONFIG_PIIX4) += piix4.o
+hw-obj-$(CONFIG_G364FB) += g364fb.o
 
 # PCI watchdog devices
 hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -390,6 +391,8 @@ trace-nested-y += control.o
 
 trace-obj-y += $(addprefix trace/, $(trace-nested-y))
 
+$(trace-obj-y): $(GENERATED_HEADERS)
+
 ######################################################################
 # smartcard
 
diff --git a/Makefile.target b/Makefile.target
index 8822442a8a..f7084532e6 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -284,7 +284,7 @@ obj-lm32-y += framebuffer.o
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
 obj-mips-y += vga.o i8259.o
-obj-mips-y += g364fb.o jazz_led.o
+obj-mips-y += jazz_led.o
 obj-mips-y += gt64xxx.o mc146818rtc.o
 obj-mips-y += cirrus_vga.o
 obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
@@ -368,6 +368,11 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 obj-alpha-y = i8259.o mc146818rtc.o
 obj-alpha-y += vga.o cirrus_vga.o
 
+obj-xtensa-y += xtensa_pic.o
+obj-xtensa-y += xtensa_sample.o
+obj-xtensa-y += xtensa_dc232b.o
+obj-xtensa-y += xtensa-semi.o
+
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 monitor.o: hmp-commands.h qmp-commands.h
diff --git a/arch_init.c b/arch_init.c
index 567ab3281c..9a5a0e31b3 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -78,6 +78,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XTENSA)
+#define QEMU_ARCH QEMU_ARCH_XTENSA
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 2de9f0852d..a74187a57d 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -17,6 +17,7 @@ enum {
     QEMU_ARCH_S390X = 512,
     QEMU_ARCH_SH4 = 1024,
     QEMU_ARCH_SPARC = 2048,
+    QEMU_ARCH_XTENSA = 4096,
 };
 
 extern const uint32_t arch_type;
diff --git a/balloon.c b/balloon.c
index f56fdc1c4b..a2133dba75 100644
--- a/balloon.c
+++ b/balloon.c
@@ -52,6 +52,16 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
     return 0;
 }
 
+void qemu_remove_balloon_handler(void *opaque)
+{
+    if (balloon_opaque != opaque) {
+        return;
+    }
+    balloon_event_fn = NULL;
+    balloon_stat_fn = NULL;
+    balloon_opaque = NULL;
+}
+
 static int qemu_balloon(ram_addr_t target)
 {
     if (!balloon_event_fn) {
diff --git a/balloon.h b/balloon.h
index 3df14e645a..f59e2881f6 100644
--- a/balloon.h
+++ b/balloon.h
@@ -22,6 +22,7 @@ typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
 
 int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 			     QEMUBalloonStatus *stat_func, void *opaque);
+void qemu_remove_balloon_handler(void *opaque);
 
 void monitor_print_balloon(Monitor *mon, const QObject *data);
 int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
diff --git a/block.c b/block.c
index a8c789a079..e3fe97f275 100644
--- a/block.c
+++ b/block.c
@@ -44,7 +44,7 @@
 #include <windows.h>
 #endif
 
-static void bdrv_dev_change_media_cb(BlockDriverState *bs);
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -480,7 +480,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     bs->encrypted = 0;
     bs->valid_key = 0;
     bs->open_flags = flags;
-    /* buffer_alignment defaulted to 512, drivers can change this value */
     bs->buffer_alignment = 512;
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
@@ -689,7 +688,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
     }
 
     if (!bdrv_key_required(bs)) {
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, true);
     }
 
     return 0;
@@ -725,7 +724,7 @@ void bdrv_close(BlockDriverState *bs)
             bdrv_close(bs->file);
         }
 
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, false);
     }
 }
 
@@ -789,6 +788,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev)
     bs->dev = NULL;
     bs->dev_ops = NULL;
     bs->dev_opaque = NULL;
+    bs->buffer_alignment = 512;
 }
 
 /* TODO change to return DeviceState * when all users are qdevified */
@@ -802,13 +802,29 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
 {
     bs->dev_ops = ops;
     bs->dev_opaque = opaque;
+    if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) {
+        bs_snapshots = NULL;
+    }
 }
 
-static void bdrv_dev_change_media_cb(BlockDriverState *bs)
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
 {
     if (bs->dev_ops && bs->dev_ops->change_media_cb) {
-        bs->dev_ops->change_media_cb(bs->dev_opaque);
+        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
+    }
+}
+
+bool bdrv_dev_has_removable_media(BlockDriverState *bs)
+{
+    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
+}
+
+bool bdrv_dev_is_tray_open(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
+        return bs->dev_ops->is_tray_open(bs->dev_opaque);
     }
+    return false;
 }
 
 static void bdrv_dev_resize_cb(BlockDriverState *bs)
@@ -818,6 +834,14 @@ static void bdrv_dev_resize_cb(BlockDriverState *bs)
     }
 }
 
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
+        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
+    }
+    return false;
+}
+
 /*
  * Run consistency checks on an image
  *
@@ -1321,7 +1345,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
     if (!drv)
         return -ENOMEDIUM;
 
-    if (bs->growable || bs->removable) {
+    if (bs->growable || bdrv_dev_has_removable_media(bs)) {
         if (drv->bdrv_getlength) {
             return drv->bdrv_getlength(bs);
         }
@@ -1598,19 +1622,6 @@ BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
     return is_read ? bs->on_read_error : bs->on_write_error;
 }
 
-void bdrv_set_removable(BlockDriverState *bs, int removable)
-{
-    bs->removable = removable;
-    if (removable && bs == bs_snapshots) {
-        bs_snapshots = NULL;
-    }
-}
-
-int bdrv_is_removable(BlockDriverState *bs)
-{
-    return bs->removable;
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
     return bs->read_only;
@@ -1663,7 +1674,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
     } else if (!bs->valid_key) {
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, true);
     }
     return ret;
 }
@@ -1850,8 +1861,9 @@ static void bdrv_print_dict(QObject *obj, void *opaque)
 
     if (qdict_get_bool(bs_dict, "removable")) {
         monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
+        monitor_printf(mon, " tray-open=%d",
+                       qdict_get_bool(bs_dict, "tray-open"));
     }
-
     if (qdict_haskey(bs_dict, "inserted")) {
         QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
 
@@ -1886,15 +1898,21 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
 
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
         QObject *bs_obj;
+        QDict *bs_dict;
 
         bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
                                     "'removable': %i, 'locked': %i }",
-                                    bs->device_name, bs->removable,
-                                    bs->locked);
-
+                                    bs->device_name,
+                                    bdrv_dev_has_removable_media(bs),
+                                    bdrv_dev_is_medium_locked(bs));
+        bs_dict = qobject_to_qdict(bs_obj);
+
+        if (bdrv_dev_has_removable_media(bs)) {
+            qdict_put(bs_dict, "tray-open",
+                      qbool_from_int(bdrv_dev_is_tray_open(bs)));
+        }
         if (bs->drv) {
             QObject *obj;
-            QDict *bs_dict = qobject_to_qdict(bs_obj);
 
             obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
                                      "'encrypted': %i }",
@@ -3026,13 +3044,12 @@ static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
 int bdrv_is_inserted(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
+
     if (!drv)
         return 0;
     if (!drv->bdrv_is_inserted)
-        return !bs->tray_open;
-    ret = drv->bdrv_is_inserted(bs);
-    return ret;
+        return 1;
+    return drv->bdrv_is_inserted(bs);
 }
 
 /**
@@ -3052,39 +3069,27 @@ int bdrv_media_changed(BlockDriverState *bs)
 /**
  * If eject_flag is TRUE, eject the media. Otherwise, close the tray
  */
-int bdrv_eject(BlockDriverState *bs, int eject_flag)
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
 
-    if (eject_flag && bs->locked) {
-        return -EBUSY;
-    }
-
     if (drv && drv->bdrv_eject) {
         drv->bdrv_eject(bs, eject_flag);
     }
-    bs->tray_open = eject_flag;
-    return 0;
-}
-
-int bdrv_is_locked(BlockDriverState *bs)
-{
-    return bs->locked;
 }
 
 /**
  * Lock or unlock the media (if it is locked, the user won't be able
  * to eject it manually).
  */
-void bdrv_set_locked(BlockDriverState *bs, int locked)
+void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 {
     BlockDriver *drv = bs->drv;
 
-    trace_bdrv_set_locked(bs, locked);
+    trace_bdrv_lock_medium(bs, locked);
 
-    bs->locked = locked;
-    if (drv && drv->bdrv_set_locked) {
-        drv->bdrv_set_locked(bs, locked);
+    if (drv && drv->bdrv_lock_medium) {
+        drv->bdrv_lock_medium(bs, locked);
     }
 }
 
@@ -3110,7 +3115,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
     return NULL;
 }
 
-
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align)
+{
+    bs->buffer_alignment = align;
+}
 
 void *qemu_blockalign(BlockDriverState *bs, size_t size)
 {
diff --git a/block.h b/block.h
index 8ec409fd18..16bfa0a3d6 100644
--- a/block.h
+++ b/block.h
@@ -32,10 +32,22 @@ typedef struct QEMUSnapshotInfo {
 typedef struct BlockDevOps {
     /*
      * Runs when virtual media changed (monitor commands eject, change)
+     * Argument load is true on load and false on eject.
      * Beware: doesn't run when a host device's physical media
      * changes.  Sure would be useful if it did.
+     * Device models with removable media must implement this callback.
      */
-    void (*change_media_cb)(void *opaque);
+    void (*change_media_cb)(void *opaque, bool load);
+    /*
+     * Is the virtual tray open?
+     * Device models implement this only when the device has a tray.
+     */
+    bool (*is_tray_open)(void *opaque);
+    /*
+     * Is the virtual medium locked into the device?
+     * Device models implement this only when device has such a lock.
+     */
+    bool (*is_medium_locked)(void *opaque);
     /*
      * Runs when the size changed (e.g. monitor command block_resize)
      */
@@ -94,6 +106,9 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 void *bdrv_get_attached_dev(BlockDriverState *bs);
 void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                       void *opaque);
+bool bdrv_dev_has_removable_media(BlockDriverState *bs);
+bool bdrv_dev_is_tray_open(BlockDriverState *bs);
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
@@ -199,16 +214,13 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
 void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
                        BlockErrorAction on_write_error);
 BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
-void bdrv_set_removable(BlockDriverState *bs, int removable);
-int bdrv_is_removable(BlockDriverState *bs);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
-int bdrv_is_locked(BlockDriverState *bs);
-void bdrv_set_locked(BlockDriverState *bs, int locked);
-int bdrv_eject(BlockDriverState *bs, int eject_flag);
+void bdrv_lock_medium(BlockDriverState *bs, bool locked);
+void bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
 BlockDriverState *bdrv_next(BlockDriverState *bs);
@@ -258,6 +270,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
                     const char *base_filename, const char *base_fmt,
                     char *options, uint64_t img_size, int flags);
 
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
 void *qemu_blockalign(BlockDriverState *bs, size_t size);
 
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
@@ -339,5 +352,43 @@ typedef enum {
 #define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 
+
+/* Convenience for block device models */
+
+typedef struct BlockConf {
+    BlockDriverState *bs;
+    uint16_t physical_block_size;
+    uint16_t logical_block_size;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+    int32_t bootindex;
+    uint32_t discard_granularity;
+} BlockConf;
+
+static inline unsigned int get_physical_block_exp(BlockConf *conf)
+{
+    unsigned int exp = 0, size;
+
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
+        exp++;
+    }
+
+    return exp;
+}
+
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
+    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
+    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
+                       _conf.logical_block_size, 512),                  \
+    DEFINE_PROP_UINT16("physical_block_size", _state,                   \
+                       _conf.physical_block_size, 512),                 \
+    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
+    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, 0)
+
 #endif
 
diff --git a/block/nbd.c b/block/nbd.c
index 55cb2fd8ba..70edd81bd6 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -28,6 +28,7 @@
 
 #include "qemu-common.h"
 #include "nbd.h"
+#include "block_int.h"
 #include "module.h"
 #include "qemu_socket.h"
 
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index e06be64876..2f76311354 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -694,7 +694,7 @@ err:
  * If the offset is not found, allocate a new cluster.
  *
  * If the cluster was already allocated, m->nb_clusters is set to 0,
- * m->depends_on is set to NULL and the other fields in m are meaningless.
+ * other fields in m are meaningless.
  *
  * If the cluster is newly allocated, m->nb_clusters is set to the number of
  * contiguous clusters that have been allocated. In this case, the other
@@ -736,7 +736,6 @@ again:
 
         cluster_offset &= ~QCOW_OFLAG_COPIED;
         m->nb_clusters = 0;
-        m->depends_on = NULL;
 
         goto out;
     }
@@ -777,17 +776,17 @@ again:
      */
     QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
 
-        uint64_t end_offset = offset + nb_clusters * s->cluster_size;
-        uint64_t old_offset = old_alloc->offset;
-        uint64_t old_end_offset = old_alloc->offset +
-            old_alloc->nb_clusters * s->cluster_size;
+        uint64_t start = offset >> s->cluster_bits;
+        uint64_t end = start + nb_clusters;
+        uint64_t old_start = old_alloc->offset >> s->cluster_bits;
+        uint64_t old_end = old_start + old_alloc->nb_clusters;
 
-        if (end_offset < old_offset || offset > old_end_offset) {
+        if (end < old_start || start > old_end) {
             /* No intersection */
         } else {
-            if (offset < old_offset) {
+            if (start < old_start) {
                 /* Stop at the start of a running allocation */
-                nb_clusters = (old_offset - offset) >> s->cluster_bits;
+                nb_clusters = old_start - start;
             } else {
                 nb_clusters = 0;
             }
@@ -807,6 +806,11 @@ again:
         abort();
     }
 
+    /* save info needed for meta data update */
+    m->offset = offset;
+    m->n_start = n_start;
+    m->nb_clusters = nb_clusters;
+
     QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
 
     /* allocate a new cluster */
@@ -817,11 +821,6 @@ again:
         goto fail;
     }
 
-    /* save info needed for meta data update */
-    m->offset = offset;
-    m->n_start = n_start;
-    m->nb_clusters = nb_clusters;
-
 out:
     ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
     if (ret < 0) {
diff --git a/block/qcow2.c b/block/qcow2.c
index 8aed31004d..510ff6897f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -237,7 +237,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
 
     s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
-    s->cluster_data = g_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+    s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
                                   + 512);
     s->cluster_cache_offset = -1;
 
@@ -296,7 +296,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         qcow2_cache_destroy(bs, s->l2_table_cache);
     }
     g_free(s->cluster_cache);
-    g_free(s->cluster_data);
+    qemu_vfree(s->cluster_data);
     return ret;
 }
 
@@ -456,7 +456,7 @@ static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
                  */
                 if (!cluster_data) {
                     cluster_data =
-                        g_malloc0(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+                        qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
                 }
 
                 assert(cur_nr_sectors <=
@@ -496,7 +496,7 @@ fail:
     qemu_co_mutex_unlock(&s->lock);
 
     qemu_iovec_destroy(&hd_qiov);
-    g_free(cluster_data);
+    qemu_vfree(cluster_data);
 
     return ret;
 }
@@ -566,7 +566,7 @@ static int qcow2_co_writev(BlockDriverState *bs,
 
         if (s->crypt_method) {
             if (!cluster_data) {
-                cluster_data = g_malloc0(QCOW_MAX_CRYPT_CLUSTERS *
+                cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *
                                                  s->cluster_size);
             }
 
@@ -611,7 +611,7 @@ fail:
     qemu_co_mutex_unlock(&s->lock);
 
     qemu_iovec_destroy(&hd_qiov);
-    g_free(cluster_data);
+    qemu_vfree(cluster_data);
 
     return ret;
 }
@@ -628,7 +628,7 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
     g_free(s->cluster_cache);
-    g_free(s->cluster_data);
+    qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
 }
 
diff --git a/block/qcow2.h b/block/qcow2.h
index c8ca3bc574..531af3948b 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -148,7 +148,6 @@ typedef struct QCowL2Meta
     int n_start;
     int nb_available;
     int nb_clusters;
-    struct QCowL2Meta *depends_on;
     CoQueue dependent_requests;
 
     QLIST_ENTRY(QCowL2Meta) next_in_flight;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index bcf50b2cf7..a624f56f86 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1362,7 +1362,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag)
     }
 }
 
-static void cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1400,7 +1400,7 @@ static BlockDriver bdrv_host_cdrom = {
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 
     /* generic scsi device */
     .bdrv_ioctl         = hdev_ioctl,
@@ -1481,7 +1481,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag)
     cdrom_reopen(bs);
 }
 
-static void cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1521,7 +1521,7 @@ static BlockDriver bdrv_host_cdrom = {
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 };
 #endif /* __FreeBSD__ */
 
diff --git a/block/raw.c b/block/raw.c
index f197479645..63cf2d3bf3 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -85,9 +85,9 @@ static void raw_eject(BlockDriverState *bs, int eject_flag)
     bdrv_eject(bs->file, eject_flag);
 }
 
-static void raw_set_locked(BlockDriverState *bs, int locked)
+static void raw_lock_medium(BlockDriverState *bs, bool locked)
 {
-    bdrv_set_locked(bs->file, locked);
+    bdrv_lock_medium(bs->file, locked);
 }
 
 static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
@@ -144,7 +144,7 @@ static BlockDriver bdrv_raw = {
     .bdrv_is_inserted   = raw_is_inserted,
     .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
-    .bdrv_set_locked    = raw_set_locked,
+    .bdrv_lock_medium   = raw_lock_medium,
 
     .bdrv_ioctl         = raw_ioctl,
     .bdrv_aio_ioctl     = raw_aio_ioctl,
diff --git a/block/rbd.c b/block/rbd.c
index ce0f6ef6ee..1b78d51398 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -169,6 +169,34 @@ done:
     return ret;
 }
 
+static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
+{
+    const char *p = conf;
+
+    while (*p) {
+        int len;
+        const char *end = strchr(p, ':');
+
+        if (end) {
+            len = end - p;
+        } else {
+            len = strlen(p);
+        }
+
+        if (strncmp(p, "id=", 3) == 0) {
+            len -= 3;
+            strncpy(clientname, p + 3, len);
+            clientname[len] = '\0';
+            return clientname;
+        }
+        if (end == NULL) {
+            break;
+        }
+        p = end + 1;
+    }
+    return NULL;
+}
+
 static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 {
     char *p, *buf;
@@ -198,17 +226,19 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
             break;
         }
 
-        if (strcmp(name, "conf")) {
-            ret = rados_conf_set(cluster, name, value);
+        if (strcmp(name, "conf") == 0) {
+            ret = rados_conf_read_file(cluster, value);
             if (ret < 0) {
-                error_report("invalid conf option %s", name);
-                ret = -EINVAL;
+                error_report("error reading conf file %s", value);
                 break;
             }
+        } else if (strcmp(name, "id") == 0) {
+            /* ignore, this is parsed by qemu_rbd_parse_clientname() */
         } else {
-            ret = rados_conf_read_file(cluster, value);
+            ret = rados_conf_set(cluster, name, value);
             if (ret < 0) {
-                error_report("error reading conf file %s", value);
+                error_report("invalid conf option %s", name);
+                ret = -EINVAL;
                 break;
             }
         }
@@ -227,6 +257,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
     char name[RBD_MAX_IMAGE_NAME_SIZE];
     char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
     char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
     rados_t cluster;
     rados_ioctx_t io_ctx;
     int ret;
@@ -259,7 +291,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    if (rados_create(&cluster, NULL) < 0) {
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    if (rados_create(&cluster, clientname) < 0) {
         error_report("error initializing");
         return -EIO;
     }
@@ -358,15 +391,14 @@ static void qemu_rbd_aio_event_reader(void *opaque)
         char *p = (char *)&s->event_rcb;
 
         /* now read the rcb pointer that was sent from a non qemu thread */
-        if ((ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
-                        sizeof(s->event_rcb) - s->event_reader_pos)) > 0) {
-            if (ret > 0) {
-                s->event_reader_pos += ret;
-                if (s->event_reader_pos == sizeof(s->event_rcb)) {
-                    s->event_reader_pos = 0;
-                    qemu_rbd_complete_aio(s->event_rcb);
-                    s->qemu_aio_count--;
-                }
+        ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
+                   sizeof(s->event_rcb) - s->event_reader_pos);
+        if (ret > 0) {
+            s->event_reader_pos += ret;
+            if (s->event_reader_pos == sizeof(s->event_rcb)) {
+                s->event_reader_pos = 0;
+                qemu_rbd_complete_aio(s->event_rcb);
+                s->qemu_aio_count--;
             }
         }
     } while (ret < 0 && errno == EINTR);
@@ -385,6 +417,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
     char pool[RBD_MAX_POOL_NAME_SIZE];
     char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
     char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
     int r;
 
     if (qemu_rbd_parsename(filename, pool, sizeof(pool),
@@ -393,23 +427,24 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
                            conf, sizeof(conf)) < 0) {
         return -EINVAL;
     }
-    s->snap = NULL;
-    if (snap_buf[0] != '\0') {
-        s->snap = g_strdup(snap_buf);
-    }
 
-    r = rados_create(&s->cluster, NULL);
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    r = rados_create(&s->cluster, clientname);
     if (r < 0) {
         error_report("error initializing");
         return r;
     }
 
+    s->snap = NULL;
+    if (snap_buf[0] != '\0') {
+        s->snap = g_strdup(snap_buf);
+    }
+
     if (strstr(conf, "conf=") == NULL) {
         r = rados_conf_read_file(s->cluster, NULL);
         if (r < 0) {
             error_report("error reading config file");
-            rados_shutdown(s->cluster);
-            return r;
+            goto failed_shutdown;
         }
     }
 
@@ -417,31 +452,26 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
         r = qemu_rbd_set_conf(s->cluster, conf);
         if (r < 0) {
             error_report("error setting config options");
-            rados_shutdown(s->cluster);
-            return r;
+            goto failed_shutdown;
         }
     }
 
     r = rados_connect(s->cluster);
     if (r < 0) {
         error_report("error connecting");
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_shutdown;
     }
 
     r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
     if (r < 0) {
         error_report("error opening pool %s", pool);
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_shutdown;
     }
 
     r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
     if (r < 0) {
         error_report("error reading header from %s", s->name);
-        rados_ioctx_destroy(s->io_ctx);
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_open;
     }
 
     bs->read_only = (s->snap != NULL);
@@ -462,8 +492,11 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
 
 failed:
     rbd_close(s->image);
+failed_open:
     rados_ioctx_destroy(s->io_ctx);
+failed_shutdown:
     rados_shutdown(s->cluster);
+    g_free(s->snap);
     return r;
 }
 
diff --git a/block_int.h b/block_int.h
index 5dc0074bfc..8c3b86373c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -120,7 +120,7 @@ struct BlockDriver {
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
     void (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
-    void (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+    void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
 
     /* to control generic scsi devices */
     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
@@ -155,9 +155,6 @@ struct BlockDriverState {
     int read_only; /* if true, the media is read only */
     int keep_read_only; /* if true, the media was requested to stay read only */
     int open_flags; /* flags used to open the file, re-used for re-open */
-    int removable; /* if true, the media can be removed */
-    int locked;    /* if true, the media cannot temporarily be ejected */
-    int tray_open; /* if true, the virtual tray is open */
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
@@ -228,39 +225,4 @@ void qemu_aio_release(void *p);
 int is_windows_drive(const char *filename);
 #endif
 
-typedef struct BlockConf {
-    BlockDriverState *bs;
-    uint16_t physical_block_size;
-    uint16_t logical_block_size;
-    uint16_t min_io_size;
-    uint32_t opt_io_size;
-    int32_t bootindex;
-    uint32_t discard_granularity;
-} BlockConf;
-
-static inline unsigned int get_physical_block_exp(BlockConf *conf)
-{
-    unsigned int exp = 0, size;
-
-    for (size = conf->physical_block_size;
-        size > conf->logical_block_size;
-        size >>= 1) {
-        exp++;
-    }
-
-    return exp;
-}
-
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
-    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
-    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
-                       _conf.logical_block_size, 512),                  \
-    DEFINE_PROP_UINT16("physical_block_size", _state,                   \
-                       _conf.physical_block_size, 512),                 \
-    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
-    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
-    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
-    DEFINE_PROP_UINT32("discard_granularity", _state, \
-                       _conf.discard_granularity, 0)
-
 #endif /* BLOCK_INT_H */
diff --git a/blockdev.c b/blockdev.c
index 049dda5549..0827bf7743 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -473,17 +473,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
             }
 	    break;
 	case MEDIA_CDROM:
-            bdrv_set_removable(dinfo->bdrv, 1);
             dinfo->media_cd = 1;
 	    break;
 	}
         break;
     case IF_SD:
-        /* FIXME: This isn't really a floppy, but it's a reasonable
-           approximation.  */
     case IF_FLOPPY:
-        bdrv_set_removable(dinfo->bdrv, 1);
-        break;
     case IF_PFLASH:
     case IF_MTD:
         break;
@@ -636,11 +631,12 @@ out:
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
-    if (!bdrv_is_removable(bs)) {
+    if (!bdrv_dev_has_removable_media(bs)) {
         qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return -1;
     }
-    if (!force && bdrv_is_locked(bs)) {
+    if (!force && !bdrv_dev_is_tray_open(bs)
+        && bdrv_dev_is_medium_locked(bs)) {
         qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
         return -1;
     }
diff --git a/configure b/configure
index fe3147b289..0875f95979 100755
--- a/configure
+++ b/configure
@@ -873,6 +873,8 @@ sh4eb-softmmu \
 sparc-softmmu \
 sparc64-softmmu \
 s390x-softmmu \
+xtensa-softmmu \
+xtensaeb-softmmu \
 "
 fi
 # the following are Linux specific
@@ -1025,7 +1027,6 @@ echo "  --disable-linux-aio      disable Linux AIO support"
 echo "  --enable-linux-aio       enable Linux AIO support"
 echo "  --disable-attr           disables attr and xattr support"
 echo "  --enable-attr            enable attr and xattr support"
-echo "  --enable-io-thread       enable IO thread"
 echo "  --disable-blobs          disable installing provided firmware blobs"
 echo "  --enable-docs            enable documentation build"
 echo "  --disable-docs           disable documentation build"
@@ -1071,7 +1072,7 @@ cat > $TMPC << EOF
 int main(void) { return 0; }
 EOF
 for flag in $gcc_flags; do
-    if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
+    if compile_prog "$flag -Werror" "" ; then
 	QEMU_CFLAGS="$QEMU_CFLAGS $flag"
     fi
 done
@@ -3151,7 +3152,7 @@ target_arch2=`echo $target | cut -d '-' -f 1`
 target_bigendian="no"
 
 case "$target_arch2" in
-  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
+  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
   target_bigendian=yes
   ;;
 esac
@@ -3346,6 +3347,10 @@ case "$target_arch2" in
   unicore32)
     target_phys_bits=32
   ;;
+  xtensa|xtensaeb)
+    TARGET_ARCH=xtensa
+    target_phys_bits=32
+  ;;
   *)
     echo "Unsupported target CPU"
     exit 1
@@ -3520,6 +3525,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_SPARC_DIS=y"  >> $config_target_mak
     echo "CONFIG_SPARC_DIS=y"  >> $libdis_config_mak
   ;;
+  xtensa*)
+    echo "CONFIG_XTENSA_DIS=y"  >> $config_target_mak
+    echo "CONFIG_XTENSA_DIS=y"  >> $libdis_config_mak
+  ;;
   esac
 done
 
diff --git a/console.c b/console.c
index 500b3fbc77..5c7a93b655 100644
--- a/console.c
+++ b/console.c
@@ -343,6 +343,7 @@ static const uint32_t dmask4[4] = {
 
 static uint32_t color_table[2][8];
 
+#ifndef CONFIG_CURSES
 enum color_names {
     COLOR_BLACK   = 0,
     COLOR_RED     = 1,
@@ -353,6 +354,7 @@ enum color_names {
     COLOR_CYAN    = 6,
     COLOR_WHITE   = 7
 };
+#endif
 
 static const uint32_t color_table_rgb[2][8] = {
     {   /* dark */
diff --git a/console.h b/console.h
index 67d137384e..9c1487e041 100644
--- a/console.h
+++ b/console.h
@@ -328,7 +328,12 @@ static inline int ds_get_bytes_per_pixel(DisplayState *ds)
     return ds->surface->pf.bytes_per_pixel;
 }
 
+#ifdef CONFIG_CURSES
+#include <curses.h>
+typedef chtype console_ch_t;
+#else
 typedef unsigned long console_ch_t;
+#endif
 static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
 {
     if (!(ch & 0xff))
diff --git a/cpu-exec.c b/cpu-exec.c
index de0d716da0..aef66f290c 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -86,7 +86,7 @@ static TranslationBlock *tb_find_slow(CPUState *env,
 {
     TranslationBlock *tb, **ptb1;
     unsigned int h;
-    tb_page_addr_t phys_pc, phys_page1, phys_page2;
+    tb_page_addr_t phys_pc, phys_page1;
     target_ulong virt_page2;
 
     tb_invalidated_flag = 0;
@@ -94,7 +94,6 @@ static TranslationBlock *tb_find_slow(CPUState *env,
     /* find translated block using physical mappings */
     phys_pc = get_page_addr_code(env, pc);
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
-    phys_page2 = -1;
     h = tb_phys_hash_func(phys_pc);
     ptb1 = &tb_phys_hash[h];
     for(;;) {
@@ -107,6 +106,8 @@ static TranslationBlock *tb_find_slow(CPUState *env,
             tb->flags == flags) {
             /* check next page if needed */
             if (tb->page_addr[1] != -1) {
+                tb_page_addr_t phys_page2;
+
                 virt_page2 = (pc & TARGET_PAGE_MASK) +
                     TARGET_PAGE_SIZE;
                 phys_page2 = get_page_addr_code(env, virt_page2);
@@ -222,6 +223,7 @@ int cpu_exec(CPUState *env)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -487,6 +489,12 @@ int cpu_exec(CPUState *env)
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_XTENSA)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        env->exception_index = EXC_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #endif
                    /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
@@ -616,6 +624,7 @@ int cpu_exec(CPUState *env)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index f524971598..45bdefb9b2 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index aeab6b2c28..d43e33ca60 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 8e6511cbeb..f307e8d8b0 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -28,3 +28,4 @@ CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_FULONG=y
+CONFIG_G364FB=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index a05ac25393..1a66bc31bb 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/default-configs/xtensa-softmmu.mak b/default-configs/xtensa-softmmu.mak
new file mode 100644
index 0000000000..e5faa09012
--- /dev/null
+++ b/default-configs/xtensa-softmmu.mak
@@ -0,0 +1 @@
+# Default configuration for Xtensa
diff --git a/default-configs/xtensaeb-softmmu.mak b/default-configs/xtensaeb-softmmu.mak
new file mode 100644
index 0000000000..e5faa09012
--- /dev/null
+++ b/default-configs/xtensaeb-softmmu.mak
@@ -0,0 +1 @@
+# Default configuration for Xtensa
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 057c322090..136d271120 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -208,7 +208,7 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
 
 * con: becomes -chardev console
 
-* COM<NUM> becomes -chardev serial,path=<NUM>
+* COM<NUM> becomes -chardev serial,path=COM<NUM>
 
 * file:FNAME becomes -chardev file,path=FNAME
 
diff --git a/elf.h b/elf.h
index ffcac7e0b0..2e05d34620 100644
--- a/elf.h
+++ b/elf.h
@@ -125,6 +125,8 @@ typedef int64_t  Elf64_Sxword;
 #define EM_MICROBLAZE      189
 #define EM_MICROBLAZE_OLD  0xBAAB
 
+#define EM_XTENSA   94      /* Tensilica Xtensa */
+
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
 #define DT_NEEDED	1
diff --git a/gdbstub.c b/gdbstub.c
index 3b87c27349..90683a46c3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -41,6 +41,15 @@
 #include "qemu_socket.h"
 #include "kvm.h"
 
+#ifndef TARGET_CPU_MEMORY_RW_DEBUG
+static inline int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                                         uint8_t *buf, int len, int is_write)
+{
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+#else
+/* target_memory_rw_debug() defined in cpu.h */
+#endif
 
 enum {
     GDB_SIGNAL_0 = 0,
@@ -1541,6 +1550,94 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
     }
     return 4;
 }
+#elif defined(TARGET_XTENSA)
+
+/* Use num_core_regs to see only non-privileged registers in an unmodified gdb.
+ * Use num_regs to see all registers. gdb modification is required for that:
+ * reset bit 0 in the 'flags' field of the registers definitions in the
+ * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
+ */
+#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
+#define num_g_regs NUM_CORE_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        GET_REG32(env->pc);
+        break;
+
+    case 1: /*ar*/
+        xtensa_sync_phys_from_window(env);
+        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
+        break;
+
+    case 2: /*SR*/
+        GET_REG32(env->sregs[reg->targno & 0xff]);
+        break;
+
+    case 3: /*UR*/
+        GET_REG32(env->uregs[reg->targno & 0xff]);
+        break;
+
+    case 8: /*a*/
+        GET_REG32(env->regs[reg->targno & 0x0f]);
+        break;
+
+    default:
+        qemu_log("%s from reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        env->pc = tmp;
+        break;
+
+    case 1: /*ar*/
+        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+        xtensa_sync_window_from_phys(env);
+        break;
+
+    case 2: /*SR*/
+        env->sregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 3: /*UR*/
+        env->uregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 8: /*a*/
+        env->regs[reg->targno & 0x0f] = tmp;
+        break;
+
+    default:
+        qemu_log("%s to reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+
+    return 4;
+}
 #else
 
 #define NUM_CORE_REGS 0
@@ -1557,7 +1654,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 
 #endif
 
+#if !defined(TARGET_XTENSA)
 static int num_g_regs = NUM_CORE_REGS;
+#endif
 
 #ifdef GDB_CORE_XML
 /* Encode data using the encoding for 'x' packets.  */
@@ -1654,6 +1753,7 @@ static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
     return 0;
 }
 
+#if !defined(TARGET_XTENSA)
 /* Register a supplemental set of CPU registers.  If g_pos is nonzero it
    specifies the first register number and these registers are included in
    a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
@@ -1693,6 +1793,7 @@ void gdb_register_coprocessor(CPUState * env,
         }
     }
 }
+#endif
 
 #ifndef CONFIG_USER_ONLY
 static const int xlat_gdb_type[] = {
@@ -1818,6 +1919,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
     s->c_cpu->psw.addr = pc;
 #elif defined (TARGET_LM32)
     s->c_cpu->pc = pc;
+#elif defined(TARGET_XTENSA)
+    s->c_cpu->pc = pc;
 #endif
 }
 
@@ -1988,6 +2091,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'g':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         len = 0;
         for (addr = 0; addr < num_g_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1998,6 +2102,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'G':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
@@ -2013,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ',')
             p++;
         len = strtoull(p, NULL, 16);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
             put_packet (s, "E14");
         } else {
             memtohex(buf, mem_buf, len);
@@ -2028,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
             put_packet(s, "E14");
-        else
+        } else {
             put_packet(s, "OK");
+        }
         break;
     case 'p':
         /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c
index ae05658632..25556cc6a7 100644
--- a/hw/9pfs/virtio-9p-coth.c
+++ b/hw/9pfs/virtio-9p-coth.c
@@ -67,10 +67,6 @@ int v9fs_init_worker_threads(void)
     /* Leave signal handling to the iothread.  */
     pthread_sigmask(SIG_SETMASK, &set, &oldset);
 
-    /* init thread system if not already initialized */
-    if (!g_thread_get_initialized()) {
-        g_thread_init(NULL);
-    }
     if (qemu_pipe(notifier_fds) == -1) {
         ret = -1;
         goto err_out;
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
index 4636ad51f0..96925f04a4 100644
--- a/hw/9pfs/virtio-9p-debug.c
+++ b/hw/9pfs/virtio-9p-debug.c
@@ -295,7 +295,7 @@ static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
 
     if (rx) {
         count = pdu->elem.in_num;
-    } else
+    } else {
         count = pdu->elem.out_num;
     }
 
diff --git a/hw/fdc.c b/hw/fdc.c
index 1d44bbd1e3..433af73ad7 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,7 +36,6 @@
 #include "qdev-addr.h"
 #include "blockdev.h"
 #include "sysemu.h"
-#include "block_int.h"
 
 /********************************************************/
 /* debug Floppy devices */
@@ -1778,7 +1777,7 @@ static void fdctrl_result_timer(void *opaque)
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
 
-static void fdctrl_change_cb(void *opaque)
+static void fdctrl_change_cb(void *opaque, bool load)
 {
     FDrive *drive = opaque;
 
@@ -1813,7 +1812,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
         fd_revalidate(drive);
         if (drive->bs) {
             drive->media_changed = 1;
-            bdrv_set_removable(drive->bs, 1);
             bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
         }
     }
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 5e7bcfa278..b43341f8d7 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -58,6 +58,8 @@ typedef struct G364State {
 #define CTLA_FORCE_BLANK 0x00000400
 #define CTLA_NO_CURSOR   0x00800000
 
+#define G364_PAGE_SIZE 4096
+
 static inline int check_dirty(G364State *s, ram_addr_t page)
 {
     return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
@@ -68,7 +70,7 @@ static inline void reset_dirty(G364State *s,
 {
     memory_region_reset_dirty(&s->mem_vram,
                               page_min,
-                              page_max + TARGET_PAGE_SIZE - page_min - 1,
+                              page_max + G364_PAGE_SIZE - page_min - 1,
                               DIRTY_MEMORY_VGA);
 }
 
@@ -136,7 +138,7 @@ static void g364fb_draw_graphic8(G364State *s)
             page_max = page;
             if (x < xmin)
                 xmin = x;
-            for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+            for (i = 0; i < G364_PAGE_SIZE; i++) {
                 uint8_t index;
                 unsigned int color;
                 if (unlikely((y >= ycursor && y < ycursor + 64) &&
@@ -200,15 +202,15 @@ static void g364fb_draw_graphic8(G364State *s)
                 ymin = s->height;
                 ymax = 0;
             }
-            x += TARGET_PAGE_SIZE;
+            x += G364_PAGE_SIZE;
             dy = x / s->width;
             x = x % s->width;
             y += dy;
-            vram += TARGET_PAGE_SIZE;
+            vram += G364_PAGE_SIZE;
             data_display += dy * ds_get_linesize(s->ds);
             dd = data_display + x * w;
         }
-        page += TARGET_PAGE_SIZE;
+        page += G364_PAGE_SIZE;
     }
 
 done:
@@ -267,7 +269,7 @@ static inline void g364fb_invalidate_display(void *opaque)
     int i;
 
     s->blanked = 0;
-    for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
+    for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
         memory_region_set_dirty(&s->mem_vram, i);
     }
 }
@@ -387,7 +389,7 @@ static void g364_invalidate_cursor_position(G364State *s)
     start = ymin * ds_get_linesize(s->ds);
     end = (ymax + 1) * ds_get_linesize(s->ds);
 
-    for (i = start; i < end; i += TARGET_PAGE_SIZE) {
+    for (i = start; i < end; i += G364_PAGE_SIZE) {
         memory_region_set_dirty(&s->mem_vram, i);
     }
 }
diff --git a/hw/hid.c b/hw/hid.c
index ec066cf2d3..03761ab8b8 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -96,7 +96,7 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
         /* Windows drivers do not like the 0/0 position and ignore such
          * events. */
         if (!(x1 | y1)) {
-            x1 = 1;
+            e->xdx = 1;
         }
     }
     e->dz += z1;
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index f4fa1545bd..a8659cf8b9 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -754,7 +754,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
         case READ_FPDMA_QUEUED:
             DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
-            ncq_tfs->is_read = 1;
 
             DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
 
@@ -768,7 +767,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
         case WRITE_FPDMA_QUEUED:
             DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
-            ncq_tfs->is_read = 0;
 
             DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
 
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 3c29d93b47..5de986c90f 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -259,7 +259,6 @@ typedef struct NCQTransferState {
     BlockDriverAIOCB *aiocb;
     QEMUSGList sglist;
     BlockAcctCookie acct;
-    int is_read;
     uint16_t sector_count;
     uint64_t lba;
     uint8_t tag;
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f38d2896ae..3f909c3a99 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -73,7 +73,7 @@ static void lba_to_msf(uint8_t *buf, int lba)
 
 static inline int media_present(IDEState *s)
 {
-    return (s->nb_sectors > 0);
+    return !s->tray_open && s->nb_sectors > 0;
 }
 
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
@@ -521,7 +521,7 @@ static unsigned int event_status_media(IDEState *s,
     uint8_t event_code, media_status;
 
     media_status = 0;
-    if (s->bs->tray_open) {
+    if (s->tray_open) {
         media_status = MS_TRAY_OPEN;
     } else if (bdrv_is_inserted(s->bs)) {
         media_status = MS_MEDIA_PRESENT;
@@ -788,8 +788,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[12] = 0x71;
             buf[13] = 3 << 5;
             buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
-            if (bdrv_is_locked(s->bs))
+            if (s->tray_locked) {
                 buf[6] |= 1 << 1;
+            }
             buf[15] = 0x00;
             cpu_to_ube16(&buf[16], 706);
             buf[18] = 0;
@@ -831,7 +832,8 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
 
 static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
 {
-    bdrv_set_locked(s->bs, buf[4] & 1);
+    s->tray_locked = buf[4] & 1;
+    bdrv_lock_medium(s->bs, buf[4] & 1);
     ide_atapi_cmd_ok(s);
 }
 
@@ -903,29 +905,22 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
 
 static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
 {
-    int start, eject, sense, err = 0;
-    start = buf[4] & 1;
-    eject = (buf[4] >> 1) & 1;
-
-    if (eject) {
-        err = bdrv_eject(s->bs, !start);
-    }
-
-    switch (err) {
-    case 0:
-        ide_atapi_cmd_ok(s);
-        break;
-    case -EBUSY:
-        sense = SENSE_NOT_READY;
-        if (bdrv_is_inserted(s->bs)) {
-            sense = SENSE_ILLEGAL_REQUEST;
+    int sense;
+    bool start = buf[4] & 1;
+    bool loej = buf[4] & 2;     /* load on start, eject on !start */
+
+    if (loej) {
+        if (!start && !s->tray_open && s->tray_locked) {
+            sense = bdrv_is_inserted(s->bs)
+                ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
+            ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+            return;
         }
-        ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
-        break;
-    default:
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
-        break;
+        bdrv_eject(s->bs, !start);
+        s->tray_open = !start;
     }
+
+    ide_atapi_cmd_ok(s);
 }
 
 static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
@@ -1073,20 +1068,21 @@ static const struct {
     [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
     [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
     [ 0x1a ] = { cmd_mode_sense, /* (6) */          0 },
-    [ 0x1b ] = { cmd_start_stop_unit,               0 },
+    [ 0x1b ] = { cmd_start_stop_unit,               0 }, /* [1] */
     [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
     [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
-    [ 0x28 ] = { cmd_read, /* (10) */               0 },
+    [ 0x28 ] = { cmd_read, /* (10) */               CHECK_READY },
     [ 0x2b ] = { cmd_seek,                          CHECK_READY },
     [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
     [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
     [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
     [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
-    [ 0xa8 ] = { cmd_read, /* (12) */               0 },
-    [ 0xad ] = { cmd_read_dvd_structure,            0 },
+    [ 0xa8 ] = { cmd_read, /* (12) */               CHECK_READY },
+    [ 0xad ] = { cmd_read_dvd_structure,            CHECK_READY },
     [ 0xbb ] = { cmd_set_speed,                     0 },
     [ 0xbd ] = { cmd_mechanism_status,              0 },
-    [ 0xbe ] = { cmd_read_cd,                       0 },
+    [ 0xbe ] = { cmd_read_cd,                       CHECK_READY },
+    /* [1] handler detects and reports not ready condition itself */
 };
 
 void ide_atapi_cmd(IDEState *s)
@@ -1122,7 +1118,7 @@ void ide_atapi_cmd(IDEState *s)
      * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
      * states rely on this behavior.
      */
-    if (bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+    if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
         ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 
         s->cdrom_changed = 0;
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 4d91e2c642..5fe98b1bb3 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 1806e008bc..9297b9e657 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -30,6 +30,7 @@
 #include "sysemu.h"
 #include "dma.h"
 #include "blockdev.h"
+#include "block_int.h"
 
 #include <hw/ide/internal.h>
 
@@ -783,11 +784,12 @@ static void ide_cfata_metadata_write(IDEState *s)
 }
 
 /* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque)
+static void ide_cd_change_cb(void *opaque, bool load)
 {
     IDEState *s = opaque;
     uint64_t nb_sectors;
 
+    s->tray_open = !load;
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
 
@@ -901,6 +903,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
+#define HD_OK (1u << IDE_HD)
+#define CD_OK (1u << IDE_CD)
+#define CFA_OK (1u << IDE_CFATA)
+#define HD_CFA_OK (HD_OK | CFA_OK)
+#define ALL_OK (HD_OK | CD_OK | CFA_OK)
+
+/* See ACS-2 T13/2015-D Table B.2 Command codes */
+static const uint8_t ide_cmd_table[0x100] = {
+    /* NOP not implemented, mandatory for CD */
+    [CFA_REQ_EXT_ERROR_CODE]            = CFA_OK,
+    [WIN_DSM]                           = ALL_OK,
+    [WIN_DEVICE_RESET]                  = CD_OK,
+    [WIN_RECAL]                         = HD_CFA_OK,
+    [WIN_READ]                          = ALL_OK,
+    [WIN_READ_ONCE]                     = ALL_OK,
+    [WIN_READ_EXT]                      = HD_CFA_OK,
+    [WIN_READDMA_EXT]                   = HD_CFA_OK,
+    [WIN_READ_NATIVE_MAX_EXT]           = HD_CFA_OK,
+    [WIN_MULTREAD_EXT]                  = HD_CFA_OK,
+    [WIN_WRITE]                         = HD_CFA_OK,
+    [WIN_WRITE_ONCE]                    = HD_CFA_OK,
+    [WIN_WRITE_EXT]                     = HD_CFA_OK,
+    [WIN_WRITEDMA_EXT]                  = HD_CFA_OK,
+    [CFA_WRITE_SECT_WO_ERASE]           = CFA_OK,
+    [WIN_MULTWRITE_EXT]                 = HD_CFA_OK,
+    [WIN_WRITE_VERIFY]                  = HD_CFA_OK,
+    [WIN_VERIFY]                        = HD_CFA_OK,
+    [WIN_VERIFY_ONCE]                   = HD_CFA_OK,
+    [WIN_VERIFY_EXT]                    = HD_CFA_OK,
+    [WIN_SEEK]                          = HD_CFA_OK,
+    [CFA_TRANSLATE_SECTOR]              = CFA_OK,
+    [WIN_DIAGNOSE]                      = ALL_OK,
+    [WIN_SPECIFY]                       = HD_CFA_OK,
+    [WIN_STANDBYNOW2]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE2]                = ALL_OK,
+    [WIN_STANDBY2]                      = ALL_OK,
+    [WIN_SETIDLE2]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE2]               = ALL_OK,
+    [WIN_SLEEPNOW2]                     = ALL_OK,
+    [WIN_PACKETCMD]                     = CD_OK,
+    [WIN_PIDENTIFY]                     = CD_OK,
+    [WIN_SMART]                         = HD_CFA_OK,
+    [CFA_ACCESS_METADATA_STORAGE]       = CFA_OK,
+    [CFA_ERASE_SECTORS]                 = CFA_OK,
+    [WIN_MULTREAD]                      = HD_CFA_OK,
+    [WIN_MULTWRITE]                     = HD_CFA_OK,
+    [WIN_SETMULT]                       = HD_CFA_OK,
+    [WIN_READDMA]                       = HD_CFA_OK,
+    [WIN_READDMA_ONCE]                  = HD_CFA_OK,
+    [WIN_WRITEDMA]                      = HD_CFA_OK,
+    [WIN_WRITEDMA_ONCE]                 = HD_CFA_OK,
+    [CFA_WRITE_MULTI_WO_ERASE]          = CFA_OK,
+    [WIN_STANDBYNOW1]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE]                 = ALL_OK,
+    [WIN_STANDBY]                       = ALL_OK,
+    [WIN_SETIDLE1]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE1]               = ALL_OK,
+    [WIN_SLEEPNOW1]                     = ALL_OK,
+    [WIN_FLUSH_CACHE]                   = ALL_OK,
+    [WIN_FLUSH_CACHE_EXT]               = HD_CFA_OK,
+    [WIN_IDENTIFY]                      = ALL_OK,
+    [WIN_SETFEATURES]                   = ALL_OK,
+    [IBM_SENSE_CONDITION]               = CFA_OK,
+    [CFA_WEAR_LEVEL]                    = CFA_OK,
+    [WIN_READ_NATIVE_MAX]               = ALL_OK,
+};
+
+static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
+{
+    return cmd < ARRAY_SIZE(ide_cmd_table)
+        && (ide_cmd_table[cmd] & (1u << s->drive_kind));
+}
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val)
 {
@@ -920,6 +994,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
         return;
 
+    if (!ide_cmd_permitted(s, val)) {
+        goto abort_cmd;
+    }
+
     switch(val) {
     case WIN_DSM:
         switch (s->feature) {
@@ -983,8 +1061,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 	lba48 = 1;
     case WIN_READ:
     case WIN_READ_ONCE:
-        if (!s->bs)
+        if (s->drive_kind == IDE_CD) {
+            ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
             goto abort_cmd;
+        }
 	ide_cmd_lba48_transform(s, lba48);
         s->req_nb_sectors = 1;
         ide_sector_read(s);
@@ -1138,21 +1218,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case WIN_SEEK:
-        if(s->drive_kind == IDE_CD)
-            goto abort_cmd;
         /* XXX: Check that seek is within bounds */
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
         /* ATAPI commands */
     case WIN_PIDENTIFY:
-        if (s->drive_kind == IDE_CD) {
-            ide_atapi_identify(s);
-            s->status = READY_STAT | SEEK_STAT;
-            ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
-        } else {
-            ide_abort_command(s);
-        }
+        ide_atapi_identify(s);
+        s->status = READY_STAT | SEEK_STAT;
+        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
         ide_set_irq(s->bus);
         break;
     case WIN_DIAGNOSE:
@@ -1169,15 +1243,11 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case WIN_DEVICE_RESET:
-        if (s->drive_kind != IDE_CD)
-            goto abort_cmd;
         ide_set_signature(s);
         s->status = 0x00; /* NOTE: READY is _not_ set */
         s->error = 0x01;
         break;
     case WIN_PACKETCMD:
-        if (s->drive_kind != IDE_CD)
-            goto abort_cmd;
         /* overlapping commands not supported */
         if (s->feature & 0x02)
             goto abort_cmd;
@@ -1189,16 +1259,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         break;
     /* CF-ATA commands */
     case CFA_REQ_EXT_ERROR_CODE:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         s->error = 0x09;    /* miscellaneous error */
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
     case CFA_ERASE_SECTORS:
     case CFA_WEAR_LEVEL:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         if (val == CFA_WEAR_LEVEL)
             s->nsector = 0;
         if (val == CFA_ERASE_SECTORS)
@@ -1208,8 +1274,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case CFA_TRANSLATE_SECTOR:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         s->error = 0x00;
         s->status = READY_STAT | SEEK_STAT;
         memset(s->io_buffer, 0, 0x200);
@@ -1228,8 +1292,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case CFA_ACCESS_METADATA_STORAGE:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         switch (s->feature) {
         case 0x02:	/* Inquiry Metadata Storage */
             ide_cfata_metadata_inquiry(s);
@@ -1248,8 +1310,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case IBM_SENSE_CONDITION:
-        if (s->drive_kind != IDE_CFATA)
-            goto abort_cmd;
         switch (s->feature) {
         case 0x01:  /* sense temperature in device */
             s->nsector = 0x50;      /* +20 C */
@@ -1262,8 +1322,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         break;
 
     case WIN_SMART:
-	if (s->drive_kind == IDE_CD)
-		goto abort_cmd;
 	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
 		goto abort_cmd;
 	if (!s->smart_enabled && s->feature != SMART_ENABLE)
@@ -1418,6 +1476,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 	}
 	break;
     default:
+        /* should not be reachable */
     abort_cmd:
         ide_abort_command(s);
         ide_set_irq(s->bus);
@@ -1738,8 +1797,20 @@ void ide_bus_reset(IDEBus *bus)
     bus->dma->ops->reset(bus->dma);
 }
 
+static bool ide_cd_is_tray_open(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_open;
+}
+
+static bool ide_cd_is_medium_locked(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_locked;
+}
+
 static const BlockDevOps ide_cd_block_ops = {
     .change_media_cb = ide_cd_change_cb,
+    .is_tray_open = ide_cd_is_tray_open,
+    .is_medium_locked = ide_cd_is_medium_locked,
 };
 
 int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
@@ -1777,7 +1848,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     s->smart_selftest_count = 0;
     if (kind == IDE_CD) {
         bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
-        bs->buffer_alignment = 2048;
+        bdrv_set_buffer_alignment(bs, 2048);
     } else {
         if (!bdrv_is_inserted(s->bs)) {
             error_report("Device needs media, but drive is empty");
@@ -1801,7 +1872,6 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     }
 
     ide_reset(s);
-    bdrv_set_removable(bs, s->drive_kind == IDE_CD);
     return 0;
 }
 
@@ -1995,6 +2065,22 @@ static bool ide_drive_pio_state_needed(void *opaque)
         || (s->bus->error_status & BM_STATUS_PIO_RETRY);
 }
 
+static int ide_tray_state_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    bdrv_eject(s->bs, s->tray_open);
+    bdrv_lock_medium(s->bs, s->tray_locked);
+    return 0;
+}
+
+static bool ide_tray_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->tray_open || s->tray_locked;
+}
+
 static bool ide_atapi_gesn_needed(void *opaque)
 {
     IDEState *s = opaque;
@@ -2022,6 +2108,19 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
     }
 };
 
+static const VMStateDescription vmstate_ide_tray_state = {
+    .name = "ide_drive/tray_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ide_tray_state_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(tray_open, IDEState),
+        VMSTATE_BOOL(tray_locked, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_ide_drive_pio_state = {
     .name = "ide_drive/pio_state",
     .version_id = 1,
@@ -2076,6 +2175,9 @@ const VMStateDescription vmstate_ide_drive = {
             .vmsd = &vmstate_ide_drive_pio_state,
             .needed = ide_drive_pio_state_needed,
         }, {
+            .vmsd = &vmstate_ide_tray_state,
+            .needed = ide_tray_state_needed,
+        }, {
             .vmsd = &vmstate_ide_atapi_gesn_state,
             .needed = ide_atapi_gesn_needed,
         }, {
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 5278bc4d6c..0327d0ee72 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -66,7 +66,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 111785294d..233915ce0d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -7,7 +7,6 @@
  * non-internal declarations are in hw/ide.h
  */
 #include <hw/ide.h>
-#include "block_int.h"
 #include "iorange.h"
 #include "dma.h"
 
@@ -442,6 +441,8 @@ struct IDEState {
     struct unreported_events events;
     uint8_t sense_key;
     uint8_t asc;
+    bool tray_open;
+    bool tray_locked;
     uint8_t cdrom_changed;
     int packet_transfer_size;
     int elementary_transfer_size;
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 4ac745324c..28b69d2cc3 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -26,7 +26,6 @@
 #include <hw/pc.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index fdf5d75082..c1844cb738 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -26,7 +26,6 @@
 #include <hw/ppc_mac.h>
 #include <hw/mac_dbdma.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
index 91c0e3c89d..9eee5b50ba 100644
--- a/hw/ide/microdrive.c
+++ b/hw/ide/microdrive.c
@@ -26,7 +26,6 @@
 #include <hw/pc.h>
 #include <hw/pcmcia.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 132b7517ba..2ec21b0163 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -24,7 +24,6 @@
  */
 #include <hw/hw.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index d1a14d7cc1..9fded02954 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
diff --git a/hw/ide/via.c b/hw/ide/via.c
index c0b9d43827..dab8a39f57 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -28,7 +28,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 1643a63ee8..dbb3bdf2ce 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -15,7 +15,6 @@
 #include "hw.h"
 #include "pci.h"
 #include "scsi.h"
-#include "block_int.h"
 
 //#define DEBUG_LSI
 //#define DEBUG_LSI_REG
@@ -883,7 +882,6 @@ static void lsi_do_msgout(LSIState *s)
     int len;
     uint32_t current_tag;
     lsi_request *current_req, *p, *p_next;
-    int id;
 
     if (s->current) {
         current_tag = s->current->tag;
@@ -892,7 +890,6 @@ static void lsi_do_msgout(LSIState *s)
         current_tag = s->select_tag;
         current_req = lsi_find_by_tag(s, current_tag);
     }
-    id = (current_tag >> 8) & 0xf;
 
     DPRINTF("MSG out len=%d\n", s->dbc);
     while (s->dbc) {
@@ -977,9 +974,8 @@ static void lsi_do_msgout(LSIState *s)
                device, but this is currently not implemented (and seems not
                to be really necessary). So let's simply clear all queued
                commands for the current device: */
-            id = current_tag & 0x0000ff00;
             QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
-                if ((p->tag & 0x0000ff00) == id) {
+                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
                     scsi_req_cancel(p->req);
                 }
             }
diff --git a/hw/mips.h b/hw/mips.h
index 8ce41fc4be..6fa9a3ae75 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,9 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
 /* bonito.c */
 PCIBus *bonito_init(qemu_irq *pic);
 
-/* mipsnet.c */
-void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
-
 /* jazz_led.c */
 void jazz_led_init(target_phys_addr_t base);
 
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 0d46cc4c5a..ac65555b74 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -35,6 +35,8 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "elf.h"
+#include "sysbus.h"
+#include "exec-memory.h"
 
 static struct _loaderparams {
     int ram_size;
@@ -112,6 +114,22 @@ static void main_cpu_reset(void *opaque)
     }
 }
 
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "mipsnet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(get_system_io(),
+                                base,
+                                sysbus_mmio_get_region(s, 0));
+}
+
 static void
 mips_mipssim_init (ram_addr_t ram_size,
                    const char *boot_device,
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b889ee0062..605367bc5f 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -1,12 +1,7 @@
 #include "hw.h"
-#include "mips.h"
 #include "net.h"
-#include "isa.h"
-
-//#define DEBUG_MIPSNET_SEND
-//#define DEBUG_MIPSNET_RECEIVE
-//#define DEBUG_MIPSNET_DATA
-//#define DEBUG_MIPSNET_IRQ
+#include "trace.h"
+#include "sysbus.h"
 
 /* MIPSnet register offsets */
 
@@ -25,6 +20,8 @@
 #define MAX_ETH_FRAME_SIZE	1514
 
 typedef struct MIPSnetState {
+    SysBusDevice busdev;
+
     uint32_t busy;
     uint32_t rx_count;
     uint32_t rx_read;
@@ -33,7 +30,7 @@ typedef struct MIPSnetState {
     uint32_t intctl;
     uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
     uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
-    int io_base;
+    MemoryRegion io;
     qemu_irq irq;
     NICState *nic;
     NICConf conf;
@@ -54,9 +51,7 @@ static void mipsnet_reset(MIPSnetState *s)
 static void mipsnet_update_irq(MIPSnetState *s)
 {
     int isr = !!s->intctl;
-#ifdef DEBUG_MIPSNET_IRQ
-    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
-#endif
+    trace_mipsnet_irq(isr, s->intctl);
     qemu_set_irq(s->irq, isr);
 }
 
@@ -80,9 +75,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-#ifdef DEBUG_MIPSNET_RECEIVE
-    printf("mipsnet: receiving len=%zu\n", size);
-#endif
+    trace_mipsnet_receive(size);
     if (!mipsnet_can_receive(nc))
         return -1;
 
@@ -103,7 +96,8 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
     return size;
 }
 
-static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
+static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned int size)
 {
     MIPSnetState *s = opaque;
     int ret = 0;
@@ -144,20 +138,17 @@ static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
     default:
         break;
     }
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+    trace_mipsnet_read(addr, ret);
     return ret;
 }
 
-static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t val, unsigned int size)
 {
     MIPSnetState *s = opaque;
 
     addr &= 0x3f;
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+    trace_mipsnet_write(addr, val);
     switch (addr) {
     case MIPSNET_TX_DATA_COUNT:
 	s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
@@ -181,9 +172,7 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         s->tx_buffer[s->tx_written++] = val;
         if (s->tx_written == s->tx_count) {
             /* Send buffer. */
-#ifdef DEBUG_MIPSNET_SEND
-            printf("mipsnet: sending len=%d\n", s->tx_count);
-#endif
+            trace_mipsnet_send(s->tx_count);
             qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
             s->tx_count = s->tx_written = 0;
             s->intctl |= MIPSNET_INTCTL_TXDONE;
@@ -224,11 +213,7 @@ static void mipsnet_cleanup(VLANClientState *nc)
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    vmstate_unregister(NULL, &vmstate_mipsnet, s);
-
-    isa_unassign_ioport(s->io_base, 36);
-
-    g_free(s);
+    s->nic = NULL;
 }
 
 static NetClientInfo net_mipsnet_info = {
@@ -239,35 +224,50 @@ static NetClientInfo net_mipsnet_info = {
     .cleanup = mipsnet_cleanup,
 };
 
-void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
-{
-    MIPSnetState *s;
-
-    qemu_check_nic_model(nd, "mipsnet");
+static MemoryRegionOps mipsnet_ioport_ops = {
+    .read = mipsnet_ioport_read,
+    .write = mipsnet_ioport_write,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 4,
+};
 
-    s = g_malloc0(sizeof(MIPSnetState));
+static int mipsnet_sysbus_init(SysBusDevice *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
 
-    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
+    sysbus_init_mmio_region(dev, &s->io);
+    sysbus_init_irq(dev, &s->irq);
 
-    s->io_base = base;
-    s->irq = irq;
+    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
-    if (nd) {
-        s->conf.macaddr = nd->macaddr;
-        s->conf.vlan = nd->vlan;
-        s->conf.peer = nd->netdev;
+    return 0;
+}
 
-        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
-                              nd->model, nd->name, s);
+static void mipsnet_sysbus_reset(DeviceState *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
+    mipsnet_reset(s);
+}
 
-        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+static SysBusDeviceInfo mipsnet_info = {
+    .init = mipsnet_sysbus_init,
+    .qdev.name = "mipsnet",
+    .qdev.desc = "MIPS Simulator network device",
+    .qdev.size = sizeof(MIPSnetState),
+    .qdev.vmsd = &vmstate_mipsnet,
+    .qdev.reset = mipsnet_sysbus_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+        DEFINE_PROP_END_OF_LIST(),
     }
+};
 
-    mipsnet_reset(s);
-    vmstate_register(NULL, 0, &vmstate_mipsnet, s);
+static void mipsnet_register_devices(void)
+{
+    sysbus_register_withprop(&mipsnet_info);
 }
+
+device_init(mipsnet_register_devices)
diff --git a/hw/pci.c b/hw/pci.c
index 57ff7b1098..af7400374b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -312,11 +312,6 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
     bus->hotplug_qdev = qdev;
 }
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
-{
-    bus->mem_base = base;
-}
-
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          void *irq_opaque,
@@ -833,12 +828,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
     return pci_dev;
 }
 
-static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
-                                          target_phys_addr_t addr)
-{
-    return addr + bus->mem_base;
-}
-
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {
     PCIIORegion *r;
@@ -1066,8 +1055,7 @@ static void pci_update_mappings(PCIDevice *d)
                                                     1);
             } else {
                 memory_region_add_subregion_overlap(r->address_space,
-                                                    pci_to_cpu_addr(d->bus,
-                                                                    r->addr),
+                                                    r->addr,
                                                     r->memory,
                                                     1);
             }
diff --git a/hw/pci.h b/hw/pci.h
index 391217e431..c04b1693c3 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -255,8 +255,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
 void pci_device_reset(PCIDevice *dev);
 void pci_bus_reset(PCIBus *bus);
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base);
-
 PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
                         const char *default_devaddr);
 PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 160eaee693..02482947ca 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -772,6 +772,11 @@ const struct SCSISense sense_code_NO_MEDIUM = {
     .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
 };
 
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x00
+};
+
 /* Hardware error, internal target failure */
 const struct SCSISense sense_code_TARGET_FAILURE = {
     .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
@@ -807,6 +812,11 @@ const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = {
     .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
 };
 
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
+};
+
 /* Command aborted, I/O process terminated */
 const struct SCSISense sense_code_IO_ERROR = {
     .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
@@ -977,13 +987,11 @@ static const char *scsi_command_name(uint8_t cmd)
         [ SYNCHRONIZE_CACHE_16     ] = "SYNCHRONIZE_CACHE_16",
         [ LOCATE_16                ] = "LOCATE_16",
         [ WRITE_SAME_16            ] = "WRITE_SAME_16",
-        [ ERASE_16                 ] = "ERASE_16",
+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
         [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
         [ WRITE_LONG_16            ] = "WRITE_LONG_16",
         [ REPORT_LUNS              ] = "REPORT_LUNS",
         [ BLANK                    ] = "BLANK",
-        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
-        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9724d0fe9a..4a60820b18 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi-defs.h"
 #include "sysemu.h"
 #include "blockdev.h"
+#include "block_int.h"
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
@@ -72,6 +73,8 @@ struct SCSIDiskState
     QEMUBH *bh;
     char *version;
     char *serial;
+    bool tray_open;
+    bool tray_locked;
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -182,6 +185,9 @@ static void scsi_read_data(SCSIRequest *req)
     if (n > SCSI_DMA_BUF_SIZE / 512)
         n = SCSI_DMA_BUF_SIZE / 512;
 
+    if (s->tray_open) {
+        scsi_read_complete(r, -ENOMEDIUM);
+    }
     r->iov.iov_len = n * 512;
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 
@@ -280,6 +286,9 @@ static void scsi_write_data(SCSIRequest *req)
 
     n = r->iov.iov_len / 512;
     if (n) {
+        if (s->tray_open) {
+            scsi_write_complete(r, -ENOMEDIUM);
+        }
         qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 
         bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
@@ -664,7 +673,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         p[5] = 0xff; /* CD DA, DA accurate, RW supported,
                         RW corrected, C2 errors, ISRC,
                         UPC, Bar code */
-        p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0);
+        p[6] = 0x2d | (s->tray_locked ? 2 : 0);
         /* Locking supported, jumper present, eject, tray */
         p[7] = 0; /* no volume & mute control, no
                      changer */
@@ -814,6 +823,27 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     return toclen;
 }
 
+static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    bool start = req->cmd.buf[4] & 1;
+    bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+
+    if (s->qdev.type == TYPE_ROM && loej) {
+        if (!start && !s->tray_open && s->tray_locked) {
+            scsi_check_condition(r,
+                                 bdrv_is_inserted(s->bs)
+                                 ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
+                                 : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
+            return -1;
+        }
+        bdrv_eject(s->bs, !start);
+        s->tray_open = !start;
+    }
+    return 0;
+}
+
 static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
 {
     SCSIRequest *req = &r->req;
@@ -823,7 +853,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
 
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
-        if (!bdrv_is_inserted(s->bs))
+        if (s->tray_open || !bdrv_is_inserted(s->bs))
             goto not_ready;
         break;
     case INQUIRY:
@@ -859,13 +889,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             goto illegal_request;
         break;
     case START_STOP:
-        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
-            /* load/eject medium */
-            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
+        if (scsi_disk_emulate_start_stop(r) < 0) {
+            return -1;
         }
         break;
     case ALLOW_MEDIUM_REMOVAL:
-        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
+        s->tray_locked = req->cmd.buf[4] & 1;
+        bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
         break;
     case READ_CAPACITY_10:
         /* The normal LEN field for this command is zero.  */
@@ -946,7 +976,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
     return buflen;
 
 not_ready:
-    if (!bdrv_is_inserted(s->bs)) {
+    if (s->tray_open || !bdrv_is_inserted(s->bs)) {
         scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
     } else {
         scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
@@ -1143,6 +1173,27 @@ static void scsi_destroy(SCSIDevice *dev)
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
+static void scsi_cd_change_media_cb(void *opaque, bool load)
+{
+    ((SCSIDiskState *)opaque)->tray_open = !load;
+}
+
+static bool scsi_cd_is_tray_open(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_open;
+}
+
+static bool scsi_cd_is_medium_locked(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps scsi_cd_block_ops = {
+    .change_media_cb = scsi_cd_change_media_cb,
+    .is_tray_open = scsi_cd_is_tray_open,
+    .is_medium_locked = scsi_cd_is_medium_locked,
+};
+
 static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
@@ -1177,6 +1228,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
     }
 
     if (scsi_type == TYPE_ROM) {
+        bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
         s->qdev.blocksize = 2048;
     } else if (scsi_type == TYPE_DISK) {
         s->qdev.blocksize = s->qdev.conf.logical_block_size;
@@ -1185,11 +1237,10 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         return -1;
     }
     s->cluster_size = s->qdev.blocksize / 512;
-    s->bs->buffer_alignment = s->qdev.blocksize;
+    bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
 
     s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
-    bdrv_set_removable(s->bs, scsi_type == TYPE_ROM);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
 }
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index cb5d4f125d..5ce01afdce 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -450,7 +450,6 @@ static int scsi_generic_initfn(SCSIDevice *dev)
         }
     }
     DPRINTF("block size %d\n", s->qdev.blocksize);
-    bdrv_set_removable(s->bs, 0);
     return 0;
 }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index 98fd689859..e8dcabfa28 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,7 +3,6 @@
 
 #include "qdev.h"
 #include "block.h"
-#include "block_int.h"
 
 #define MAX_SCSI_DEVS	255
 
@@ -136,6 +135,8 @@ extern const struct SCSISense sense_code_NO_SENSE;
 extern const struct SCSISense sense_code_LUN_NOT_READY;
 /* LUN not ready, Medium not present */
 extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
 /* Hardware error, internal target failure */
 extern const struct SCSISense sense_code_TARGET_FAILURE;
 /* Illegal request, invalid command operation code */
@@ -150,6 +151,8 @@ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
 extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
 /* Illegal request, Incompatible format */
 extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
 /* Command aborted, I/O process terminated */
 extern const struct SCSISense sense_code_IO_ERROR;
 /* Command aborted, I_T Nexus loss occurred */
diff --git a/hw/sd.c b/hw/sd.c
index 1af62b23c6..10e26ade58 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -419,7 +419,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     sd->pwd_len = 0;
 }
 
-static void sd_cardchange(void *opaque)
+static void sd_cardchange(void *opaque, bool load)
 {
     SDState *sd = opaque;
 
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 072a88a382..5f8f4bdb9f 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -303,6 +303,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
 void virtio_balloon_exit(VirtIODevice *vdev)
 {
     VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+
+    qemu_remove_balloon_handler(s);
     unregister_savevm(s->qdev, "virtio-balloon", s);
     virtio_cleanup(vdev);
 }
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 4df23f4228..c2ee0001eb 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "qemu-error.h"
 #include "trace.h"
 #include "blockdev.h"
@@ -599,9 +599,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
     s->qdev = dev;
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
-    bdrv_set_removable(s->bs, 0);
     bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
-    s->bs->buffer_alignment = conf->logical_block_size;
+    bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
 
     add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
 
diff --git a/hw/virtio.h b/hw/virtio.h
index c1292647fe..4d20d9b8f4 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -18,7 +18,7 @@
 #include "net.h"
 #include "qdev.h"
 #include "sysemu.h"
-#include "block_int.h"
+#include "block.h"
 #include "event_notifier.h"
 #ifdef CONFIG_LINUX
 #include "9p.h"
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index aa642675f8..d876cabb12 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -421,13 +421,13 @@ static int xen_be_try_init(struct XenDevice *xendev)
 }
 
 /*
- * Try to connect xendev.  Depends on the frontend being ready
+ * Try to initialise xendev.  Depends on the frontend being ready
  * for it (shared ring and evtchn info in xenstore, state being
  * Initialised or Connected).
  *
  * Goes to Connected on success.
  */
-static int xen_be_try_connect(struct XenDevice *xendev)
+static int xen_be_try_initialise(struct XenDevice *xendev)
 {
     int rc = 0;
 
@@ -441,11 +441,11 @@ static int xen_be_try_connect(struct XenDevice *xendev)
         }
     }
 
-    if (xendev->ops->connect) {
-        rc = xendev->ops->connect(xendev);
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
     }
     if (rc != 0) {
-        xen_be_printf(xendev, 0, "connect() failed\n");
+        xen_be_printf(xendev, 0, "initialise() failed\n");
         return rc;
     }
 
@@ -454,6 +454,29 @@ static int xen_be_try_connect(struct XenDevice *xendev)
 }
 
 /*
+ * Try to let xendev know that it is connected.  Depends on the
+ * frontend being Connected.  Note that this may be called more
+ * than once since the backend state is not modified.
+ */
+static void xen_be_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
+/*
  * Teardown connection.
  *
  * Goes to Closed when done.
@@ -508,7 +531,12 @@ void xen_be_check_state(struct XenDevice *xendev)
             rc = xen_be_try_init(xendev);
             break;
         case XenbusStateInitWait:
-            rc = xen_be_try_connect(xendev);
+            rc = xen_be_try_initialise(xendev);
+            break;
+        case XenbusStateConnected:
+            /* xendev->be_state doesn't change */
+            xen_be_try_connected(xendev);
+            rc = -1;
             break;
         case XenbusStateClosed:
             rc = xen_be_try_reset(xendev);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 6401c85a7e..3305630903 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -21,7 +21,8 @@ struct XenDevOps {
     uint32_t  flags;
     void      (*alloc)(struct XenDevice *xendev);
     int       (*init)(struct XenDevice *xendev);
-    int       (*connect)(struct XenDevice *xendev);
+    int       (*initialise)(struct XenDevice *xendev);
+    void      (*connected)(struct XenDevice *xendev);
     void      (*event)(struct XenDevice *xendev);
     void      (*disconnect)(struct XenDevice *xendev);
     int       (*free)(struct XenDevice *xendev);
diff --git a/hw/xen_console.c b/hw/xen_console.c
index 5789bd09a5..edcb31ce66 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -212,7 +212,7 @@ out:
     return ret;
 }
 
-static int con_connect(struct XenDevice *xendev)
+static int con_initialise(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
     int limit;
@@ -273,7 +273,7 @@ struct XenDevOps xen_console_ops = {
     .size       = sizeof(struct XenConsole),
     .flags      = DEVOPS_FLAG_IGNORE_STATE,
     .init       = con_init,
-    .connect    = con_connect,
+    .initialise = con_initialise,
     .event      = con_event,
     .disconnect = con_disconnect,
 };
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index da531a67dd..8a9fac499b 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -852,7 +852,7 @@ struct XenDevOps xen_blkdev_ops = {
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .alloc      = blk_alloc,
     .init       = blk_init,
-    .connect    = blk_connect,
+    .initialise    = blk_connect,
     .disconnect = blk_disconnect,
     .event      = blk_event,
     .free       = blk_free,
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index b28b15670b..aeca8da96b 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -433,7 +433,7 @@ struct XenDevOps xen_netdev_ops = {
     .size       = sizeof(struct XenNetDev),
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .init       = net_init,
-    .connect    = net_connect,
+    .initialise    = net_connect,
     .event      = net_event,
     .disconnect = net_disconnect,
     .free       = net_free,
diff --git a/hw/xenfb.c b/hw/xenfb.c
index d532d3e898..1bcf171b01 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -351,15 +351,11 @@ static int input_init(struct XenDevice *xendev)
     return 0;
 }
 
-static int input_connect(struct XenDevice *xendev)
+static int input_initialise(struct XenDevice *xendev)
 {
     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
     int rc;
 
-    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
-                             &in->abs_pointer_wanted) == -1)
-	in->abs_pointer_wanted = 0;
-
     if (!in->c.ds) {
         char *vfb = xenstore_read_str(NULL, "device/vfb");
         if (vfb == NULL) {
@@ -377,10 +373,24 @@ static int input_connect(struct XenDevice *xendev)
 	return rc;
 
     qemu_add_kbd_event_handler(xenfb_key_event, in);
+    return 0;
+}
+
+static void input_connected(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+                             &in->abs_pointer_wanted) == -1) {
+        in->abs_pointer_wanted = 0;
+    }
+
+    if (in->qmouse) {
+        qemu_remove_mouse_event_handler(in->qmouse);
+    }
     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
 					      in->abs_pointer_wanted,
 					      "Xen PVFB Mouse");
-    return 0;
 }
 
 static void input_disconnect(struct XenDevice *xendev)
@@ -865,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
     return 0;
 }
 
-static int fb_connect(struct XenDevice *xendev)
+static int fb_initialise(struct XenDevice *xendev)
 {
     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
     struct xenfb_page *fb_page;
@@ -959,7 +969,8 @@ static void fb_event(struct XenDevice *xendev)
 struct XenDevOps xen_kbdmouse_ops = {
     .size       = sizeof(struct XenInput),
     .init       = input_init,
-    .connect    = input_connect,
+    .initialise = input_initialise,
+    .connected  = input_connected,
     .disconnect = input_disconnect,
     .event      = input_event,
 };
@@ -967,7 +978,7 @@ struct XenDevOps xen_kbdmouse_ops = {
 struct XenDevOps xen_framebuffer_ops = {
     .size       = sizeof(struct XenFB),
     .init       = fb_init,
-    .connect    = fb_connect,
+    .initialise = fb_initialise,
     .disconnect = fb_disconnect,
     .event      = fb_event,
     .frontend_changed = fb_frontend_changed,
diff --git a/hw/xtensa_dc232b.c b/hw/xtensa_dc232b.c
new file mode 100644
index 0000000000..015d6aaa6b
--- /dev/null
+++ b/hw/xtensa_dc232b.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void dc232b_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void dc232b_init(ram_addr_t ram_size,
+        const char *boot_device,
+        const char *kernel_filename, const char *kernel_cmdline,
+        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    MemoryRegion *ram, *rom;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env->sregs[PRID] = n;
+        qemu_register_reset(dc232b_reset, env);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        dc232b_reset(env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    rom = g_malloc(sizeof(*rom));
+    memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
+    memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_dc232b_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "dc232b";
+    }
+    dc232b_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_dc232b_machine = {
+    .name = "dc232b",
+    .desc = "Diamond 232L Standard Core Rev.B (LE) (dc232b)",
+    .init = xtensa_dc232b_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_dc232b_machine_init(void)
+{
+    qemu_register_machine(&xtensa_dc232b_machine);
+}
+
+machine_init(xtensa_dc232b_machine_init);
diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
new file mode 100644
index 0000000000..3033ae214a
--- /dev/null
+++ b/hw/xtensa_pic.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "qemu-log.h"
+#include "qemu-timer.h"
+
+/* Stub functions for hardware that doesn't exist.  */
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
+
+void xtensa_advance_ccount(CPUState *env, uint32_t d)
+{
+    uint32_t old_ccount = env->sregs[CCOUNT];
+
+    env->sregs[CCOUNT] += d;
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
+                xtensa_timer_irq(env, i, 1);
+            }
+        }
+    }
+}
+
+void check_interrupts(CPUState *env)
+{
+    int minlevel = xtensa_get_cintlevel(env);
+    uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
+    int level;
+
+    /* If the CPU is halted advance CCOUNT according to the vm_clock time
+     * elapsed since the moment when it was advanced last time.
+     */
+    if (env->halted) {
+        int64_t now = qemu_get_clock_ns(vm_clock);
+
+        xtensa_advance_ccount(env,
+                muldiv64(now - env->halt_clock,
+                    env->config->clock_freq_khz, 1000000));
+        env->halt_clock = now;
+    }
+    for (level = env->config->nlevel; level > minlevel; --level) {
+        if (env->config->level_mask[level] & int_set_enabled) {
+            env->pending_irq_level = level;
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            qemu_log_mask(CPU_LOG_INT,
+                    "%s level = %d, cintlevel = %d, "
+                    "pc = %08x, a0 = %08x, ps = %08x, "
+                    "intset = %08x, intenable = %08x, "
+                    "ccount = %08x\n",
+                    __func__, level, xtensa_get_cintlevel(env),
+                    env->pc, env->regs[0], env->sregs[PS],
+                    env->sregs[INTSET], env->sregs[INTENABLE],
+                    env->sregs[CCOUNT]);
+            return;
+        }
+    }
+    env->pending_irq_level = 0;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void xtensa_set_irq(void *opaque, int irq, int active)
+{
+    CPUState *env = opaque;
+
+    if (irq >= env->config->ninterrupt) {
+        qemu_log("%s: bad IRQ %d\n", __func__, irq);
+    } else {
+        uint32_t irq_bit = 1 << irq;
+
+        if (active) {
+            env->sregs[INTSET] |= irq_bit;
+        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+            env->sregs[INTSET] &= ~irq_bit;
+        }
+
+        check_interrupts(env);
+    }
+}
+
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active)
+{
+    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+}
+
+static void xtensa_ccompare_cb(void *opaque)
+{
+    CPUState *env = opaque;
+    xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
+}
+
+void xtensa_irq_init(CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(
+            xtensa_set_irq, env, env->config->ninterrupt);
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+            env->config->nccompare > 0) {
+        env->ccompare_timer =
+            qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env);
+    }
+}
diff --git a/hw/xtensa_sample.c b/hw/xtensa_sample.c
new file mode 100644
index 0000000000..31a6f70825
--- /dev/null
+++ b/hw/xtensa_sample.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static void xtensa_sample_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void xtensa_init(ram_addr_t ram_size,
+        const char *boot_device,
+        const char *kernel_filename, const char *kernel_cmdline,
+        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    MemoryRegion *ram;
+    const size_t dram_size = 0x10000;
+    const size_t iram_size = 0x20000;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        qemu_register_reset(xtensa_sample_reset, env);
+        env->sregs[PRID] = n;
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.ram",
+            dram_size + iram_size + ram_size);
+    memory_region_add_subregion(get_system_memory(),
+            0x60000000 - dram_size - iram_size, ram);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_sample_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "sample-xtensa-core";
+    }
+    xtensa_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_sample_machine = {
+    .name = "sample-xtensa-machine",
+    .desc = "Sample Xtensa machine (sample Xtensa core)",
+    .init = xtensa_sample_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_sample_machine_init(void)
+{
+    qemu_register_machine(&xtensa_sample_machine);
+}
+
+machine_init(xtensa_sample_machine_init);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6bdf4e6ab4..e87e17432e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -60,7 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 #include <linux/wireless.h>
-#include <qemu-common.h>
+#include "qemu-common.h"
 #ifdef TARGET_GPROF
 #include <sys/gmon.h>
 #endif
@@ -96,7 +96,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include "cpu-uname.h"
 
 #include "qemu.h"
-#include "qemu-common.h"
 
 #if defined(CONFIG_USE_NPTL)
 #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
diff --git a/monitor.c b/monitor.c
index df0f622067..03ae997ffe 100644
--- a/monitor.c
+++ b/monitor.c
@@ -886,7 +886,7 @@ static void print_cpu_iter(QObject *obj, void *opaque)
     monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "nip"));
 #elif defined(TARGET_SPARC)
-    monitor_printf(mon, "pc=0x " TARGET_FMT_lx,
+    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "pc"));
     monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "npc"));
diff --git a/nbd.c b/nbd.c
index e7a585dcb0..6d81cfbcd0 100644
--- a/nbd.c
+++ b/nbd.c
@@ -17,6 +17,7 @@
  */
 
 #include "nbd.h"
+#include "block.h"
 
 #include <errno.h>
 #include <string.h>
diff --git a/nbd.h b/nbd.h
index 96f77fe2d1..df7b7af7c0 100644
--- a/nbd.h
+++ b/nbd.h
@@ -21,9 +21,7 @@
 
 #include <sys/types.h>
 
-#include <qemu-common.h>
-
-#include "block_int.h"
+#include "qemu-common.h"
 
 struct nbd_request {
     uint32_t magic;
diff --git a/oslib-posix.c b/oslib-posix.c
index 196099cc77..a304fb0f53 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -35,6 +35,13 @@
 extern int daemon(int, int);
 #endif
 
+#if defined(__linux__) && defined(__x86_64__)
+   /* Use 2MB alignment so transparent hugepages can be used by KVM */
+#  define QEMU_VMALLOC_ALIGN (512 * 4096)
+#else
+#  define QEMU_VMALLOC_ALIGN getpagesize()
+#endif
+
 #include "config-host.h"
 #include "sysemu.h"
 #include "trace.h"
@@ -80,7 +87,12 @@ void *qemu_memalign(size_t alignment, size_t size)
 void *qemu_vmalloc(size_t size)
 {
     void *ptr;
-    ptr = qemu_memalign(getpagesize(), size);
+    size_t align = QEMU_VMALLOC_ALIGN;
+
+    if (size < align) {
+        align = getpagesize();
+    }
+    ptr = qemu_memalign(align, size);
     trace_qemu_vmalloc(size, ptr);
     return ptr;
 }
diff --git a/qemu-io.c b/qemu-io.c
index 7e40c48951..5e46213af1 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -992,7 +992,6 @@ static int multiwrite_f(int argc, char **argv)
 
         optind = j + 1;
 
-        offset += reqs[i].qiov->size;
         pattern++;
     }
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 0b25a4dd48..3a39145174 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -16,7 +16,7 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "block_int.h"
 #include "nbd.h"
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 659ecb2db7..dfbabd0088 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1412,7 +1412,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
 Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
 listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
 and MODE @var{octalmode} to change default ownership and permissions for
-communication port. This option is available only if QEMU has been compiled
+communication port. This option is only available if QEMU has been compiled
 with vde support enabled.
 
 Example:
@@ -2396,11 +2396,11 @@ STEXI
 Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
 ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
-    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K)
+    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA)
 STEXI
 @item -semihosting
 @findex -semihosting
-Semihosting mode (ARM, M68K only).
+Semihosting mode (ARM, M68K, Xtensa only).
 ETEXI
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n", QEMU_ARCH_ARM)
@@ -2453,13 +2453,13 @@ Specify tracing options.
 Immediately enable events listed in @var{file}.
 The file must contain one event name (as listed in the @var{trace-events} file)
 per line.
-
-This option is only available when using the @var{simple} and @var{stderr}
-tracing backends.
+This option is only available if QEMU has been compiled with
+either @var{simple} or @var{stderr} tracing backend.
 @item file=@var{file}
 Log output traces to @var{file}.
 
-This option is only available when using the @var{simple} tracing backend.
+This option is only available if QEMU has been compiled with
+the @var{simple} tracing backend.
 @end table
 ETEXI
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 27cc66ebc9..d1c2c5905d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1131,6 +1131,8 @@ Each json-object contain the following:
          - Possible values: "unknown"
 - "removable": true if the device is removable, false otherwise (json-bool)
 - "locked": true if the device is locked, false otherwise (json-bool)
+- "tray-open": only present if removable, true if the device has a tray,
+               and it is open (json-bool)
 - "inserted": only present if the device is inserted, it is a json-object
    containing the following:
          - "file": device file name (json-string)
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 67c70e32e3..a7551235e2 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -1,7 +1,7 @@
 #ifndef _LIBSLIRP_H
 #define _LIBSLIRP_H
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 
 #ifdef CONFIG_SLIRP
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 70ef74b80a..22b1dd0665 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -769,7 +769,7 @@ static int kvm_put_xsave(CPUState *env)
 
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     memset(xsave, 0, sizeof(struct kvm_xsave));
-    cwd = swd = twd = 0;
+    twd = 0;
     swd = env->fpus & ~(7 << 11);
     swd |= (env->fpstt & 7) << 11;
     cwd = env->fpuc;
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 8654f26a4e..19de5ba334 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -495,6 +495,13 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
 
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write);
+#define TARGET_CPU_MEMORY_RW_DEBUG
+#endif
+
+
 /* translate.c */
 void gen_intermediate_code_init(CPUSPARCState *env);
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 1fe1f074ef..c80531a16c 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -358,6 +358,90 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
     }
 }
 
+#if !defined(CONFIG_USER_ONLY)
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int i;
+    int len1;
+    int cwp = env->cwp;
+
+    if (!is_write) {
+        for (i = 0; i < env->nwindows; i++) {
+            int off;
+            target_ulong fp = env->regbase[cwp * 16 + 22];
+
+            /* Assume fp == 0 means end of frame.  */
+            if (fp == 0) {
+                break;
+            }
+
+            cwp = cpu_cwp_inc(env, cwp + 1);
+
+            /* Invalid window ? */
+            if (env->wim & (1 << cwp)) {
+                break;
+            }
+
+            /* According to the ABI, the stack is growing downward.  */
+            if (addr + len < fp) {
+                break;
+            }
+
+            /* Not in this frame.  */
+            if (addr > fp + 64) {
+                continue;
+            }
+
+            /* Handle access before this window.  */
+            if (addr < fp) {
+                len1 = fp - addr;
+                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+                    return -1;
+                }
+                addr += len1;
+                len -= len1;
+                buf += len1;
+            }
+
+            /* Access byte per byte to registers. Not very efficient but speed
+             * is not critical.
+             */
+            off = addr - fp;
+            len1 = 64 - off;
+
+            if (len1 > len) {
+                len1 = len;
+            }
+
+            for (; len1; len1--) {
+                int reg = cwp * 16 + 8 + (off >> 2);
+                union {
+                    uint32_t v;
+                    uint8_t c[4];
+                } u;
+                u.v = cpu_to_be32(env->regbase[reg]);
+                *buf++ = u.c[off & 3];
+                addr++;
+                len--;
+                off++;
+            }
+
+            if (len == 0) {
+                return 0;
+            }
+        }
+    }
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#endif  /* !defined(CONFIG_USER_ONLY) */
+
 #else /* !TARGET_SPARC64 */
 
 // 41 bit physical address space
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index d1a8dd9939..48e1db8227 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3901,10 +3901,8 @@ target_ulong cpu_get_ccr(CPUState *env1)
 
 static void put_ccr(target_ulong val)
 {
-    target_ulong tmp = val;
-
-    env->xcc = (tmp >> 4) << 20;
-    env->psr = (tmp & 0xf) << 20;
+    env->xcc = (val >> 4) << 20;
+    env->psr = (val & 0xf) << 20;
     CC_OP = CC_OP_FLAGS;
 }
 
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 4ecb0f1704..4d0aa43da2 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1788,7 +1788,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
      * E    : 5
      */
     switch (insn >> 29) {
-    case 0b000:
+    case 0x0:
         if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
             do_mult(env, s, insn);
             break;
@@ -1798,7 +1798,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
             do_misc(env, s, insn);
             break;
         }
-    case 0b001:
+    case 0x1:
         if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
             do_misc(env, s, insn);
             break;
@@ -1806,7 +1806,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
         do_datap(env, s, insn);
         break;
 
-    case 0b010:
+    case 0x2:
         if (UCOP_SET(8) && UCOP_SET(5)) {
             do_ldst_hwsb(env, s, insn);
             break;
@@ -1814,24 +1814,24 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
         if (UCOP_SET(8) || UCOP_SET(5)) {
             ILLEGAL;
         }
-    case 0b011:
+    case 0x3:
         do_ldst_ir(env, s, insn);
         break;
 
-    case 0b100:
+    case 0x4:
         if (UCOP_SET(8)) {
             ILLEGAL; /* extended instructions */
         }
         do_ldst_m(env, s, insn);
         break;
-    case 0b101:
+    case 0x5:
         do_branch(env, s, insn);
         break;
-    case 0b110:
+    case 0x6:
         /* Coprocessor.  */
         disas_coproc_insn(env, s, insn);
         break;
-    case 0b111:
+    case 0x7:
         if (!UCOP_SET(28)) {
             disas_coproc_insn(env, s, insn);
             break;
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
new file mode 100644
index 0000000000..339075dda1
--- /dev/null
+++ b/target-xtensa/cpu.h
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CPU_XTENSA_H
+#define CPU_XTENSA_H
+
+#define TARGET_LONG_BITS 32
+#define ELF_MACHINE EM_XTENSA
+
+#define CPUState struct CPUXtensaState
+
+#include "config.h"
+#include "qemu-common.h"
+#include "cpu-defs.h"
+
+#define TARGET_HAS_ICE 1
+
+#define NB_MMU_MODES 4
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define TARGET_PAGE_BITS 12
+
+enum {
+    /* Additional instructions */
+    XTENSA_OPTION_CODE_DENSITY,
+    XTENSA_OPTION_LOOP,
+    XTENSA_OPTION_EXTENDED_L32R,
+    XTENSA_OPTION_16_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IDIV,
+    XTENSA_OPTION_MAC16,
+    XTENSA_OPTION_MISC_OP,
+    XTENSA_OPTION_COPROCESSOR,
+    XTENSA_OPTION_BOOLEAN,
+    XTENSA_OPTION_FP_COPROCESSOR,
+    XTENSA_OPTION_MP_SYNCHRO,
+    XTENSA_OPTION_CONDITIONAL_STORE,
+
+    /* Interrupts and exceptions */
+    XTENSA_OPTION_EXCEPTION,
+    XTENSA_OPTION_RELOCATABLE_VECTOR,
+    XTENSA_OPTION_UNALIGNED_EXCEPTION,
+    XTENSA_OPTION_INTERRUPT,
+    XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+    XTENSA_OPTION_TIMER_INTERRUPT,
+
+    /* Local memory */
+    XTENSA_OPTION_ICACHE,
+    XTENSA_OPTION_ICACHE_TEST,
+    XTENSA_OPTION_ICACHE_INDEX_LOCK,
+    XTENSA_OPTION_DCACHE,
+    XTENSA_OPTION_DCACHE_TEST,
+    XTENSA_OPTION_DCACHE_INDEX_LOCK,
+    XTENSA_OPTION_IRAM,
+    XTENSA_OPTION_IROM,
+    XTENSA_OPTION_DRAM,
+    XTENSA_OPTION_DROM,
+    XTENSA_OPTION_XLMI,
+    XTENSA_OPTION_HW_ALIGNMENT,
+    XTENSA_OPTION_MEMORY_ECC_PARITY,
+
+    /* Memory protection and translation */
+    XTENSA_OPTION_REGION_PROTECTION,
+    XTENSA_OPTION_REGION_TRANSLATION,
+    XTENSA_OPTION_MMU,
+
+    /* Other */
+    XTENSA_OPTION_WINDOWED_REGISTER,
+    XTENSA_OPTION_PROCESSOR_INTERFACE,
+    XTENSA_OPTION_MISC_SR,
+    XTENSA_OPTION_THREAD_POINTER,
+    XTENSA_OPTION_PROCESSOR_ID,
+    XTENSA_OPTION_DEBUG,
+    XTENSA_OPTION_TRACE_PORT,
+};
+
+enum {
+    THREADPTR = 231,
+    FCR = 232,
+    FSR = 233,
+};
+
+enum {
+    LBEG = 0,
+    LEND = 1,
+    LCOUNT = 2,
+    SAR = 3,
+    BR = 4,
+    LITBASE = 5,
+    SCOMPARE1 = 12,
+    WINDOW_BASE = 72,
+    WINDOW_START = 73,
+    PTEVADDR = 83,
+    RASID = 90,
+    ITLBCFG = 91,
+    DTLBCFG = 92,
+    EPC1 = 177,
+    DEPC = 192,
+    EPS2 = 194,
+    EXCSAVE1 = 209,
+    CPENABLE = 224,
+    INTSET = 226,
+    INTCLEAR = 227,
+    INTENABLE = 228,
+    PS = 230,
+    VECBASE = 231,
+    EXCCAUSE = 232,
+    CCOUNT = 234,
+    PRID = 235,
+    EXCVADDR = 238,
+    CCOMPARE = 240,
+};
+
+#define PS_INTLEVEL 0xf
+#define PS_INTLEVEL_SHIFT 0
+
+#define PS_EXCM 0x10
+#define PS_UM 0x20
+
+#define PS_RING 0xc0
+#define PS_RING_SHIFT 6
+
+#define PS_OWB 0xf00
+#define PS_OWB_SHIFT 8
+
+#define PS_CALLINC 0x30000
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_LEN 2
+
+#define PS_WOE 0x40000
+
+#define MAX_NAREG 64
+#define MAX_NINTERRUPT 32
+#define MAX_NLEVEL 6
+#define MAX_NNMI 1
+#define MAX_NCCOMPARE 3
+#define MAX_TLB_WAY_SIZE 8
+
+#define REGION_PAGE_MASK 0xe0000000
+
+enum {
+    /* Static vectors */
+    EXC_RESET,
+    EXC_MEMORY_ERROR,
+
+    /* Dynamic vectors */
+    EXC_WINDOW_OVERFLOW4,
+    EXC_WINDOW_UNDERFLOW4,
+    EXC_WINDOW_OVERFLOW8,
+    EXC_WINDOW_UNDERFLOW8,
+    EXC_WINDOW_OVERFLOW12,
+    EXC_WINDOW_UNDERFLOW12,
+    EXC_IRQ,
+    EXC_KERNEL,
+    EXC_USER,
+    EXC_DOUBLE,
+    EXC_MAX
+};
+
+enum {
+    ILLEGAL_INSTRUCTION_CAUSE = 0,
+    SYSCALL_CAUSE,
+    INSTRUCTION_FETCH_ERROR_CAUSE,
+    LOAD_STORE_ERROR_CAUSE,
+    LEVEL1_INTERRUPT_CAUSE,
+    ALLOCA_CAUSE,
+    INTEGER_DIVIDE_BY_ZERO_CAUSE,
+    PRIVILEGED_CAUSE = 8,
+    LOAD_STORE_ALIGNMENT_CAUSE,
+
+    INSTR_PIF_DATA_ERROR_CAUSE = 12,
+    LOAD_STORE_PIF_DATA_ERROR_CAUSE,
+    INSTR_PIF_ADDR_ERROR_CAUSE,
+    LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
+
+    INST_TLB_MISS_CAUSE,
+    INST_TLB_MULTI_HIT_CAUSE,
+    INST_FETCH_PRIVILEGE_CAUSE,
+    INST_FETCH_PROHIBITED_CAUSE = 20,
+    LOAD_STORE_TLB_MISS_CAUSE = 24,
+    LOAD_STORE_TLB_MULTI_HIT_CAUSE,
+    LOAD_STORE_PRIVILEGE_CAUSE,
+    LOAD_PROHIBITED_CAUSE = 28,
+    STORE_PROHIBITED_CAUSE,
+
+    COPROCESSOR0_DISABLED = 32,
+};
+
+typedef enum {
+    INTTYPE_LEVEL,
+    INTTYPE_EDGE,
+    INTTYPE_NMI,
+    INTTYPE_SOFTWARE,
+    INTTYPE_TIMER,
+    INTTYPE_DEBUG,
+    INTTYPE_WRITE_ERR,
+    INTTYPE_MAX
+} interrupt_type;
+
+typedef struct xtensa_tlb_entry {
+    uint32_t vaddr;
+    uint32_t paddr;
+    uint8_t asid;
+    uint8_t attr;
+    bool variable;
+} xtensa_tlb_entry;
+
+typedef struct xtensa_tlb {
+    unsigned nways;
+    const unsigned way_size[10];
+    bool varway56;
+    unsigned nrefillentries;
+} xtensa_tlb;
+
+typedef struct XtensaGdbReg {
+    int targno;
+    int type;
+    int group;
+} XtensaGdbReg;
+
+typedef struct XtensaGdbRegmap {
+    int num_regs;
+    int num_core_regs;
+    /* PC + a + ar + sr + ur */
+    XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
+} XtensaGdbRegmap;
+
+typedef struct XtensaConfig {
+    const char *name;
+    uint64_t options;
+    XtensaGdbRegmap gdb_regmap;
+    unsigned nareg;
+    int excm_level;
+    int ndepc;
+    uint32_t vecbase;
+    uint32_t exception_vector[EXC_MAX];
+    unsigned ninterrupt;
+    unsigned nlevel;
+    uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t inttype_mask[INTTYPE_MAX];
+    struct {
+        uint32_t level;
+        interrupt_type inttype;
+    } interrupt[MAX_NINTERRUPT];
+    unsigned nccompare;
+    uint32_t timerint[MAX_NCCOMPARE];
+    uint32_t clock_freq_khz;
+
+    xtensa_tlb itlb;
+    xtensa_tlb dtlb;
+} XtensaConfig;
+
+typedef struct CPUXtensaState {
+    const XtensaConfig *config;
+    uint32_t regs[16];
+    uint32_t pc;
+    uint32_t sregs[256];
+    uint32_t uregs[256];
+    uint32_t phys_regs[MAX_NAREG];
+
+    xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
+    xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
+    unsigned autorefill_idx;
+
+    int pending_irq_level; /* level of last raised IRQ */
+    void **irq_inputs;
+    QEMUTimer *ccompare_timer;
+    uint32_t wake_ccount;
+    int64_t halt_clock;
+
+    int exception_taken;
+
+    CPU_COMMON
+} CPUXtensaState;
+
+#define cpu_init cpu_xtensa_init
+#define cpu_exec cpu_xtensa_exec
+#define cpu_gen_code cpu_xtensa_gen_code
+#define cpu_signal_handler cpu_xtensa_signal_handler
+#define cpu_list xtensa_cpu_list
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model);
+void xtensa_translate_init(void);
+int cpu_xtensa_exec(CPUXtensaState *s);
+void do_interrupt(CPUXtensaState *s);
+void check_interrupts(CPUXtensaState *s);
+void xtensa_irq_init(CPUState *env);
+void xtensa_advance_ccount(CPUState *env, uint32_t d);
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active);
+int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+void xtensa_sync_window_from_phys(CPUState *env);
+void xtensa_sync_phys_from_window(CPUState *env);
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way);
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei);
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access);
+
+
+#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
+
+static inline bool xtensa_option_bits_enabled(const XtensaConfig *config,
+        uint64_t opt)
+{
+    return (config->options & opt) != 0;
+}
+
+static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
+{
+    return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt));
+}
+
+static inline int xtensa_get_cintlevel(const CPUState *env)
+{
+    int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
+    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
+        level = env->config->excm_level;
+    }
+    return level;
+}
+
+static inline int xtensa_get_ring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+static inline int xtensa_get_cring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
+            (env->sregs[PS] & PS_EXCM) == 0) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUState *env,
+        bool dtlb, unsigned wi, unsigned ei)
+{
+    return dtlb ?
+        env->dtlb[wi] + ei :
+        env->itlb[wi] + ei;
+}
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _ring0
+#define MMU_MODE1_SUFFIX _ring1
+#define MMU_MODE2_SUFFIX _ring2
+#define MMU_MODE3_SUFFIX _ring3
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return xtensa_get_cring(env);
+}
+
+#define XTENSA_TBFLAG_RING_MASK 0x3
+#define XTENSA_TBFLAG_EXCM 0x4
+#define XTENSA_TBFLAG_LITBASE 0x8
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+    *flags |= xtensa_get_ring(env);
+    if (env->sregs[PS] & PS_EXCM) {
+        *flags |= XTENSA_TBFLAG_EXCM;
+    }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+            (env->sregs[LITBASE] & 1)) {
+        *flags |= XTENSA_TBFLAG_LITBASE;
+    }
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return env->pending_irq_level;
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/target-xtensa/gdb-config-dc232b.c b/target-xtensa/gdb-config-dc232b.c
new file mode 100644
index 0000000000..13aba5edec
--- /dev/null
+++ b/target-xtensa/gdb-config-dc232b.c
@@ -0,0 +1,261 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,
+          0, 0, 0, 0, 0, 0)
+  XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(36, 144,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,
+          0, 0, 0, 0, 0, 0)
+  XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(38, 152,  3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(39, 156,  8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart,
+          0, 0, 0, 0, 0, 0)
+  XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,
+          0, 0, 0, 0, 0, 0)
+  XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,
+          0, 0, 0, 0, 0, 0)
+  XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,
+          0, 0, 0, 0, 0, 0)
+  XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo,
+          0, 0, 0, 0, 0, 0)
+  XTREG(46, 184,  8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi,
+          0, 0, 0, 0, 0, 0)
+  XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate,
+          0, 0, 0, 0, 0, 0)
+  XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(55, 220, 18, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(56, 224, 18, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(57, 228,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(58, 232, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(59, 236, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(60, 240, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(61, 244, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(62, 248, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(63, 252, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(64, 256, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(65, 260, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(66, 264, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(67, 268, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(68, 272, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(69, 276, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(70, 280, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(71, 284, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(72, 288, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(73, 292, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(74, 296, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(75, 300, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(76, 304, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(77, 308, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(78, 312, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(79, 316, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(80, 320, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(81, 324, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(82, 328, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(83, 332, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(84, 336, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(85, 340, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(86, 344,  8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(87, 348, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,
+          0, 0, 0, 0, 0, 0)
+  XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,
+          0, 0, 0, 0, 0, 0)
+  XTREG(89, 356, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,
+          0, 0, 0, 0, 0, 0)
+  XTREG(90, 360, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(91, 364, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(92, 368,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(93, 372, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(94, 376, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(95, 380, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(96, 384, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(97, 388,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel,
+          0, 0, 0, 0, 0, 0)
+  XTREG(98, 392, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(99, 396, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(100, 400, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(101, 404, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(102, 408, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(103, 412, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(104, 416, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(105, 420, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(106, 424, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(107, 428, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(108, 432, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(109, 436, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(110, 440, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(111, 444, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(112, 448, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(113, 452, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(114, 456, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(115, 460, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(116, 464, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(117, 468, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(118, 472, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(119, 476, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,
+          0, 0, 0, 0, 0, 0)
diff --git a/target-xtensa/gdb-config-sample-xtensa-core.c b/target-xtensa/gdb-config-sample-xtensa-core.c
new file mode 100644
index 0000000000..bfbd7be30a
--- /dev/null
+++ b/target-xtensa/gdb-config-sample-xtensa-core.c
@@ -0,0 +1,375 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (c) 2003-2010 Tensilica Inc.
+
+   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.  */
+
+  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(33, 132, 32, 4, 4, 0x0120, 0x0006, -2, 1, 0x0002, ar32,
+          0, 0, 0, 0, 0, 0)
+  XTREG(34, 136, 32, 4, 4, 0x0121, 0x0006, -2, 1, 0x0002, ar33,
+          0, 0, 0, 0, 0, 0)
+  XTREG(35, 140, 32, 4, 4, 0x0122, 0x0006, -2, 1, 0x0002, ar34,
+          0, 0, 0, 0, 0, 0)
+  XTREG(36, 144, 32, 4, 4, 0x0123, 0x0006, -2, 1, 0x0002, ar35,
+          0, 0, 0, 0, 0, 0)
+  XTREG(37, 148, 32, 4, 4, 0x0124, 0x0006, -2, 1, 0x0002, ar36,
+          0, 0, 0, 0, 0, 0)
+  XTREG(38, 152, 32, 4, 4, 0x0125, 0x0006, -2, 1, 0x0002, ar37,
+          0, 0, 0, 0, 0, 0)
+  XTREG(39, 156, 32, 4, 4, 0x0126, 0x0006, -2, 1, 0x0002, ar38,
+          0, 0, 0, 0, 0, 0)
+  XTREG(40, 160, 32, 4, 4, 0x0127, 0x0006, -2, 1, 0x0002, ar39,
+          0, 0, 0, 0, 0, 0)
+  XTREG(41, 164, 32, 4, 4, 0x0128, 0x0006, -2, 1, 0x0002, ar40,
+          0, 0, 0, 0, 0, 0)
+  XTREG(42, 168, 32, 4, 4, 0x0129, 0x0006, -2, 1, 0x0002, ar41,
+          0, 0, 0, 0, 0, 0)
+  XTREG(43, 172, 32, 4, 4, 0x012a, 0x0006, -2, 1, 0x0002, ar42,
+          0, 0, 0, 0, 0, 0)
+  XTREG(44, 176, 32, 4, 4, 0x012b, 0x0006, -2, 1, 0x0002, ar43,
+          0, 0, 0, 0, 0, 0)
+  XTREG(45, 180, 32, 4, 4, 0x012c, 0x0006, -2, 1, 0x0002, ar44,
+          0, 0, 0, 0, 0, 0)
+  XTREG(46, 184, 32, 4, 4, 0x012d, 0x0006, -2, 1, 0x0002, ar45,
+          0, 0, 0, 0, 0, 0)
+  XTREG(47, 188, 32, 4, 4, 0x012e, 0x0006, -2, 1, 0x0002, ar46,
+          0, 0, 0, 0, 0, 0)
+  XTREG(48, 192, 32, 4, 4, 0x012f, 0x0006, -2, 1, 0x0002, ar47,
+          0, 0, 0, 0, 0, 0)
+  XTREG(49, 196, 32, 4, 4, 0x0130, 0x0006, -2, 1, 0x0002, ar48,
+          0, 0, 0, 0, 0, 0)
+  XTREG(50, 200, 32, 4, 4, 0x0131, 0x0006, -2, 1, 0x0002, ar49,
+          0, 0, 0, 0, 0, 0)
+  XTREG(51, 204, 32, 4, 4, 0x0132, 0x0006, -2, 1, 0x0002, ar50,
+          0, 0, 0, 0, 0, 0)
+  XTREG(52, 208, 32, 4, 4, 0x0133, 0x0006, -2, 1, 0x0002, ar51,
+          0, 0, 0, 0, 0, 0)
+  XTREG(53, 212, 32, 4, 4, 0x0134, 0x0006, -2, 1, 0x0002, ar52,
+          0, 0, 0, 0, 0, 0)
+  XTREG(54, 216, 32, 4, 4, 0x0135, 0x0006, -2, 1, 0x0002, ar53,
+          0, 0, 0, 0, 0, 0)
+  XTREG(55, 220, 32, 4, 4, 0x0136, 0x0006, -2, 1, 0x0002, ar54,
+          0, 0, 0, 0, 0, 0)
+  XTREG(56, 224, 32, 4, 4, 0x0137, 0x0006, -2, 1, 0x0002, ar55,
+          0, 0, 0, 0, 0, 0)
+  XTREG(57, 228, 32, 4, 4, 0x0138, 0x0006, -2, 1, 0x0002, ar56,
+          0, 0, 0, 0, 0, 0)
+  XTREG(58, 232, 32, 4, 4, 0x0139, 0x0006, -2, 1, 0x0002, ar57,
+          0, 0, 0, 0, 0, 0)
+  XTREG(59, 236, 32, 4, 4, 0x013a, 0x0006, -2, 1, 0x0002, ar58,
+          0, 0, 0, 0, 0, 0)
+  XTREG(60, 240, 32, 4, 4, 0x013b, 0x0006, -2, 1, 0x0002, ar59,
+          0, 0, 0, 0, 0, 0)
+  XTREG(61, 244, 32, 4, 4, 0x013c, 0x0006, -2, 1, 0x0002, ar60,
+          0, 0, 0, 0, 0, 0)
+  XTREG(62, 248, 32, 4, 4, 0x013d, 0x0006, -2, 1, 0x0002, ar61,
+          0, 0, 0, 0, 0, 0)
+  XTREG(63, 252, 32, 4, 4, 0x013e, 0x0006, -2, 1, 0x0002, ar62,
+          0, 0, 0, 0, 0, 0)
+  XTREG(64, 256, 32, 4, 4, 0x013f, 0x0006, -2, 1, 0x0002, ar63,
+          0, 0, 0, 0, 0, 0)
+  XTREG(65, 260, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(66, 264, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,
+          0, 0, 0, 0, 0, 0)
+  XTREG(67, 268, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(68, 272,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,
+          0, 0, 0, 0, 0, 0)
+  XTREG(69, 276, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(70, 280,  4, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(71, 284, 16, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart,
+          0, 0, 0, 0, 0, 0)
+  XTREG(72, 288, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,
+          0, 0, 0, 0, 0, 0)
+  XTREG(73, 292, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,
+          0, 0, 0, 0, 0, 0)
+  XTREG(74, 296, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,
+          0, 0, 0, 0, 0, 0)
+  XTREG(75, 300, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(76, 304, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(77, 308, 32, 4, 4, 0x0327, 0x000e, -1, 3, 0x0210, expstate,
+          0, 0, 0, 0, 0, 0)
+  XTREG(78, 312, 32, 4, 4, 0x0300, 0x0006,  2, 3, 0x0210, stage1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(79, 316, 32, 4, 4, 0x0301, 0x0006,  2, 3, 0x0210, stage2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(80, 320, 32, 4, 4, 0x0302, 0x0006,  2, 3, 0x0210, input_align_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(81, 324,  6, 4, 4, 0x0303, 0x0006,  2, 3, 0x0210, input_align_reg_pos,
+          0, 0, 0, 0, 0, 0)
+  XTREG(82, 328, 32, 4, 4, 0x0304, 0x0006,  2, 3, 0x0210, data_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(83, 332,  7, 4, 4, 0x0305, 0x0006,  2, 3, 0x0210, data_reg_pos,
+          0, 0, 0, 0, 0, 0)
+  XTREG(84, 336, 32, 4, 4, 0x0306, 0x0006,  2, 3, 0x0210, crc_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(85, 340, 32, 4, 4, 0x0307, 0x0006,  2, 3, 0x0210, pol_reg00,
+          0, 0, 0, 0, 0, 0)
+  XTREG(86, 344, 32, 4, 4, 0x0308, 0x0006,  2, 3, 0x0210, pol_reg01,
+          0, 0, 0, 0, 0, 0)
+  XTREG(87, 348, 32, 4, 4, 0x0309, 0x0006,  2, 3, 0x0210, pol_reg02,
+          0, 0, 0, 0, 0, 0)
+  XTREG(88, 352, 32, 4, 4, 0x030a, 0x0006,  2, 3, 0x0210, pol_reg03,
+          0, 0, 0, 0, 0, 0)
+  XTREG(89, 356, 32, 4, 4, 0x030b, 0x0006,  2, 3, 0x0210, pol_reg04,
+          0, 0, 0, 0, 0, 0)
+  XTREG(90, 360, 32, 4, 4, 0x030c, 0x0006,  2, 3, 0x0210, pol_reg05,
+          0, 0, 0, 0, 0, 0)
+  XTREG(91, 364, 32, 4, 4, 0x030d, 0x0006,  2, 3, 0x0210, pol_reg06,
+          0, 0, 0, 0, 0, 0)
+  XTREG(92, 368, 32, 4, 4, 0x030e, 0x0006,  2, 3, 0x0210, pol_reg07,
+          0, 0, 0, 0, 0, 0)
+  XTREG(93, 372, 32, 4, 4, 0x030f, 0x0006,  2, 3, 0x0210, pol_reg08,
+          0, 0, 0, 0, 0, 0)
+  XTREG(94, 376, 32, 4, 4, 0x0310, 0x0006,  2, 3, 0x0210, pol_reg09,
+          0, 0, 0, 0, 0, 0)
+  XTREG(95, 380, 32, 4, 4, 0x0311, 0x0006,  2, 3, 0x0210, pol_reg10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(96, 384, 32, 4, 4, 0x0312, 0x0006,  2, 3, 0x0210, pol_reg11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(97, 388, 32, 4, 4, 0x0313, 0x0006,  2, 3, 0x0210, pol_reg12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(98, 392, 32, 4, 4, 0x0314, 0x0006,  2, 3, 0x0210, pol_reg13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(99, 396, 32, 4, 4, 0x0315, 0x0006,  2, 3, 0x0210, pol_reg14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(100, 400, 32, 4, 4, 0x0316, 0x0006,  2, 3, 0x0210, pol_reg15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(101, 404, 32, 4, 4, 0x0317, 0x0006,  2, 3, 0x0210, pol_reg16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(102, 408, 32, 4, 4, 0x0318, 0x0006,  2, 3, 0x0210, pol_reg17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(103, 412, 32, 4, 4, 0x0319, 0x0006,  2, 3, 0x0210, pol_reg18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(104, 416, 32, 4, 4, 0x031a, 0x0006,  2, 3, 0x0210, pol_reg19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(105, 420, 32, 4, 4, 0x031b, 0x0006,  2, 3, 0x0210, pol_reg20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(106, 424, 32, 4, 4, 0x031c, 0x0006,  2, 3, 0x0210, pol_reg21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(107, 428, 32, 4, 4, 0x031d, 0x0006,  2, 3, 0x0210, pol_reg22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(108, 432, 32, 4, 4, 0x031e, 0x0006,  2, 3, 0x0210, pol_reg23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(109, 436, 32, 4, 4, 0x031f, 0x0006,  2, 3, 0x0210, pol_reg24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(110, 440, 32, 4, 4, 0x0320, 0x0006,  2, 3, 0x0210, pol_reg25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(111, 444, 32, 4, 4, 0x0321, 0x0006,  2, 3, 0x0210, pol_reg26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(112, 448, 32, 4, 4, 0x0322, 0x0006,  2, 3, 0x0210, pol_reg27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(113, 452, 32, 4, 4, 0x0323, 0x0006,  2, 3, 0x0210, pol_reg28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(114, 456, 32, 4, 4, 0x0324, 0x0006,  2, 3, 0x0210, pol_reg29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(115, 460, 32, 4, 4, 0x0325, 0x0006,  2, 3, 0x0210, pol_reg30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(116, 464, 32, 4, 4, 0x0326, 0x0006,  2, 3, 0x0210, pol_reg31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(117, 468, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(118, 472,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(119, 476,  6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl,
+          0, 0, 0, 0, 0, 0)
+  XTREG(120, 480, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(121, 484, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(122, 488, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(123, 492, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(124, 496, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(125, 500, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(126, 504, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(127, 508, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(128, 512, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(129, 516, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(130, 520, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(131, 524, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(132, 528, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(133, 532, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(134, 536, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(135, 540, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(136, 544, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(137, 548, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(138, 552, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(139, 556, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(140, 560, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(141, 564, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(142, 568, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(143, 572, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(144, 576, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(145, 580,  4, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(146, 584, 13, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,
+          0, 0, 0, 0, 0, 0)
+  XTREG(147, 588, 13, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,
+          0, 0, 0, 0, 0, 0)
+  XTREG(148, 592, 13, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,
+          0, 0, 0, 0, 0, 0)
+  XTREG(149, 596, 13, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(150, 600, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(151, 604,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(152, 608, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(153, 612, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(154, 616, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(155, 620, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(156, 624,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel,
+          0, 0, 0, 0, 0, 0)
+  XTREG(157, 628, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(158, 632, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(159, 636, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(160, 640, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(161, 644, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(162, 648, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(163, 652, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(164, 656, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(165, 660, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(166, 664, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(167, 668, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(168, 672, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(169, 676, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(170, 680, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(171, 684, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(172, 688, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(173, 692, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(174, 696, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(175, 700, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,
+          0, 0, 0, 0, 0, 0)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
new file mode 100644
index 0000000000..c8ba74e145
--- /dev/null
+++ b/target-xtensa/helper.c
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
+
+#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \
+        a1, a2, a3, a4, a5, a6) \
+    { .targno = (no), .type = (typ), .group = (grp) },
+
+static void reset_mmu(CPUState *env);
+
+void cpu_reset(CPUXtensaState *env)
+{
+    env->exception_taken = 0;
+    env->pc = env->config->exception_vector[EXC_RESET];
+    env->sregs[LITBASE] &= ~1;
+    env->sregs[PS] = xtensa_option_enabled(env->config,
+            XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+    env->sregs[VECBASE] = env->config->vecbase;
+
+    env->pending_irq_level = 0;
+    reset_mmu(env);
+}
+
+static const XtensaConfig core_config[] = {
+    {
+        .name = "sample-xtensa-core",
+        .options = -1 ^
+            (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_MMU)),
+        .gdb_regmap = {
+            .num_regs = 176,
+            .num_core_regs = 117,
+            .reg = {
+#include "gdb-config-sample-xtensa-core.c"
+            }
+        },
+        .nareg = 64,
+        .ndepc = 1,
+        .excm_level = 16,
+        .vecbase = 0x5fff8400,
+        .exception_vector = {
+            [EXC_RESET] = 0x5fff8000,
+            [EXC_WINDOW_OVERFLOW4] = 0x5fff8400,
+            [EXC_WINDOW_UNDERFLOW4] = 0x5fff8440,
+            [EXC_WINDOW_OVERFLOW8] = 0x5fff8480,
+            [EXC_WINDOW_UNDERFLOW8] = 0x5fff84c0,
+            [EXC_WINDOW_OVERFLOW12] = 0x5fff8500,
+            [EXC_WINDOW_UNDERFLOW12] = 0x5fff8540,
+            [EXC_KERNEL] = 0x5fff861c,
+            [EXC_USER] = 0x5fff863c,
+            [EXC_DOUBLE] = 0x5fff865c,
+        },
+        .ninterrupt = 13,
+        .nlevel = 6,
+        .interrupt_vector = {
+            0,
+            0,
+            0x5fff857c,
+            0x5fff859c,
+            0x5fff85bc,
+            0x5fff85dc,
+            0x5fff85fc,
+        },
+        .level_mask = {
+            [4] = 1,
+        },
+        .interrupt = {
+            [0] = {
+                .level = 4,
+                .inttype = INTTYPE_TIMER,
+            },
+        },
+        .nccompare = 1,
+        .timerint = {
+            [0] = 0,
+        },
+        .clock_freq_khz = 912000,
+    }, {
+        .name = "dc232b",
+        .options = -1 ^
+            (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)),
+        .gdb_regmap = {
+            .num_regs = 120,
+            .num_core_regs = 52,
+            .reg = {
+#include "gdb-config-dc232b.c"
+            }
+        },
+        .nareg = 32,
+        .ndepc = 1,
+        .excm_level = 3,
+        .vecbase = 0xd0000000,
+        .exception_vector = {
+            [EXC_RESET] = 0xfe000000,
+            [EXC_WINDOW_OVERFLOW4] = 0xd0000000,
+            [EXC_WINDOW_UNDERFLOW4] = 0xd0000040,
+            [EXC_WINDOW_OVERFLOW8] = 0xd0000080,
+            [EXC_WINDOW_UNDERFLOW8] = 0xd00000c0,
+            [EXC_WINDOW_OVERFLOW12] = 0xd0000100,
+            [EXC_WINDOW_UNDERFLOW12] = 0xd0000140,
+            [EXC_KERNEL] = 0xd0000300,
+            [EXC_USER] = 0xd0000340,
+            [EXC_DOUBLE] = 0xd00003c0,
+        },
+        .ninterrupt = 22,
+        .nlevel = 6,
+        .interrupt_vector = {
+            0,
+            0,
+            0xd0000180,
+            0xd00001c0,
+            0xd0000200,
+            0xd0000240,
+            0xd0000280,
+            0xd00002c0,
+        },
+        .level_mask = {
+            [1] = 0x1f80ff,
+            [2] = 0x000100,
+            [3] = 0x200e00,
+            [4] = 0x001000,
+            [5] = 0x002000,
+            [6] = 0x000000,
+            [7] = 0x004000,
+        },
+        .inttype_mask = {
+            [INTTYPE_EDGE] = 0x3f8000,
+            [INTTYPE_NMI] = 0x4000,
+            [INTTYPE_SOFTWARE] = 0x880,
+        },
+        .interrupt = {
+            [0] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [1] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [2] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [3] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [4] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [5] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [6] = {
+                .level = 1,
+                .inttype = INTTYPE_TIMER,
+            },
+            [7] = {
+                .level = 1,
+                .inttype = INTTYPE_SOFTWARE,
+            },
+            [8] = {
+                .level = 2,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [9] = {
+                .level = 3,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [10] = {
+                .level = 3,
+                .inttype = INTTYPE_TIMER,
+            },
+            [11] = {
+                .level = 3,
+                .inttype = INTTYPE_SOFTWARE,
+            },
+            [12] = {
+                .level = 4,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [13] = {
+                .level = 5,
+                .inttype = INTTYPE_TIMER,
+            },
+            [14] = {
+                .level = 7,
+                .inttype = INTTYPE_NMI,
+            },
+            [15] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [16] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [17] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [18] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [19] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [20] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [21] = {
+                .level = 3,
+                .inttype = INTTYPE_EDGE,
+            },
+        },
+        .nccompare = 3,
+        .timerint = {
+            [0] = 6,
+            [1] = 10,
+            [2] = 13,
+        },
+        .clock_freq_khz = 912000,
+        .itlb = {
+            .nways = 7,
+            .way_size = {
+                4, 4, 4, 4, 4, 2, 2,
+            },
+            .varway56 = false,
+            .nrefillentries = 16,
+        },
+        .dtlb = {
+            .nways = 10,
+            .way_size = {
+                4, 4, 4, 4, 4, 2, 2, 1, 1, 1,
+            },
+            .varway56 = false,
+            .nrefillentries = 16,
+        },
+    },
+};
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
+{
+    static int tcg_inited;
+    CPUXtensaState *env;
+    const XtensaConfig *config = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i)
+        if (strcmp(core_config[i].name, cpu_model) == 0) {
+            config = core_config + i;
+            break;
+        }
+
+    if (config == NULL) {
+        return NULL;
+    }
+
+    env = g_malloc0(sizeof(*env));
+    env->config = config;
+    cpu_exec_init(env);
+
+    if (!tcg_inited) {
+        tcg_inited = 1;
+        xtensa_translate_init();
+    }
+
+    xtensa_irq_init(env);
+    qemu_init_vcpu(env);
+    return env;
+}
+
+
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i) {
+        cpu_fprintf(f, "  %s\n", core_config[i].name);
+    }
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+
+    if (xtensa_get_physical_addr(env, addr, 0, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    if (xtensa_get_physical_addr(env, addr, 2, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    return ~0;
+}
+
+static uint32_t relocated_vector(CPUState *env, uint32_t vector)
+{
+    if (xtensa_option_enabled(env->config,
+                XTENSA_OPTION_RELOCATABLE_VECTOR)) {
+        return vector - env->config->vecbase + env->sregs[VECBASE];
+    } else {
+        return vector;
+    }
+}
+
+/*!
+ * Handle penging IRQ.
+ * For the high priority interrupt jump to the corresponding interrupt vector.
+ * For the level-1 interrupt convert it to either user, kernel or double
+ * exception with the 'level-1 interrupt' exception cause.
+ */
+static void handle_interrupt(CPUState *env)
+{
+    int level = env->pending_irq_level;
+
+    if (level > xtensa_get_cintlevel(env) &&
+            level <= env->config->nlevel &&
+            (env->config->level_mask[level] &
+             env->sregs[INTSET] &
+             env->sregs[INTENABLE])) {
+        if (level > 1) {
+            env->sregs[EPC1 + level - 1] = env->pc;
+            env->sregs[EPS2 + level - 2] = env->sregs[PS];
+            env->sregs[PS] =
+                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
+            env->pc = relocated_vector(env,
+                    env->config->interrupt_vector[level]);
+        } else {
+            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
+
+            if (env->sregs[PS] & PS_EXCM) {
+                if (env->config->ndepc) {
+                    env->sregs[DEPC] = env->pc;
+                } else {
+                    env->sregs[EPC1] = env->pc;
+                }
+                env->exception_index = EXC_DOUBLE;
+            } else {
+                env->sregs[EPC1] = env->pc;
+                env->exception_index =
+                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+            }
+            env->sregs[PS] |= PS_EXCM;
+        }
+        env->exception_taken = 1;
+    }
+}
+
+void do_interrupt(CPUState *env)
+{
+    if (env->exception_index == EXC_IRQ) {
+        qemu_log_mask(CPU_LOG_INT,
+                "%s(EXC_IRQ) level = %d, cintlevel = %d, "
+                "pc = %08x, a0 = %08x, ps = %08x, "
+                "intset = %08x, intenable = %08x, "
+                "ccount = %08x\n",
+                __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
+                env->pc, env->regs[0], env->sregs[PS],
+                env->sregs[INTSET], env->sregs[INTENABLE],
+                env->sregs[CCOUNT]);
+        handle_interrupt(env);
+    }
+
+    switch (env->exception_index) {
+    case EXC_WINDOW_OVERFLOW4:
+    case EXC_WINDOW_UNDERFLOW4:
+    case EXC_WINDOW_OVERFLOW8:
+    case EXC_WINDOW_UNDERFLOW8:
+    case EXC_WINDOW_OVERFLOW12:
+    case EXC_WINDOW_UNDERFLOW12:
+    case EXC_KERNEL:
+    case EXC_USER:
+    case EXC_DOUBLE:
+        qemu_log_mask(CPU_LOG_INT, "%s(%d) "
+                "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
+                __func__, env->exception_index,
+                env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
+        if (env->config->exception_vector[env->exception_index]) {
+            env->pc = relocated_vector(env,
+                    env->config->exception_vector[env->exception_index]);
+            env->exception_taken = 1;
+        } else {
+            qemu_log("%s(pc = %08x) bad exception_index: %d\n",
+                    __func__, env->pc, env->exception_index);
+        }
+        break;
+
+    case EXC_IRQ:
+        break;
+
+    default:
+        qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
+                __func__, env->pc, env->exception_index);
+        break;
+    }
+    check_interrupts(env);
+}
+
+static void reset_tlb_mmu_all_ways(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned wi, ei;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
+            entry[wi][ei].asid = 0;
+            entry[wi][ei].variable = true;
+        }
+    }
+}
+
+static void reset_tlb_mmu_ways56(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    if (!tlb->varway56) {
+        static const xtensa_tlb_entry way5[] = {
+            {
+                .vaddr = 0xd0000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xd8000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        static const xtensa_tlb_entry way6[] = {
+            {
+                .vaddr = 0xe0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xf0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        memcpy(entry[5], way5, sizeof(way5));
+        memcpy(entry[6], way6, sizeof(way6));
+    } else {
+        uint32_t ei;
+        for (ei = 0; ei < 8; ++ei) {
+            entry[6][ei].vaddr = ei << 29;
+            entry[6][ei].paddr = ei << 29;
+            entry[6][ei].asid = 1;
+            entry[6][ei].attr = 2;
+        }
+    }
+}
+
+static void reset_tlb_region_way0(CPUState *env,
+        xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned ei;
+
+    for (ei = 0; ei < 8; ++ei) {
+        entry[0][ei].vaddr = ei << 29;
+        entry[0][ei].paddr = ei << 29;
+        entry[0][ei].asid = 1;
+        entry[0][ei].attr = 2;
+        entry[0][ei].variable = true;
+    }
+}
+
+static void reset_mmu(CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        env->sregs[RASID] = 0x04030201;
+        env->sregs[ITLBCFG] = 0;
+        env->sregs[DTLBCFG] = 0;
+        env->autorefill_idx = 0;
+        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
+        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
+    } else {
+        reset_tlb_region_way0(env, env->itlb);
+        reset_tlb_region_way0(env, env->dtlb);
+    }
+}
+
+static unsigned get_ring(const CPUState *env, uint8_t asid)
+{
+    unsigned i;
+    for (i = 0; i < 4; ++i) {
+        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
+            return i;
+        }
+    }
+    return 0xff;
+}
+
+/*!
+ * Lookup xtensa TLB for the given virtual address.
+ * See ISA, 4.6.2.2
+ *
+ * \param pwi: [out] way index
+ * \param pei: [out] entry index
+ * \param pring: [out] access ring
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring)
+{
+    const xtensa_tlb *tlb = dtlb ?
+        &env->config->dtlb : &env->config->itlb;
+    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
+        env->dtlb : env->itlb;
+
+    int nhits = 0;
+    unsigned wi;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        uint32_t vpn;
+        uint32_t ei;
+        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
+        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
+            unsigned ring = get_ring(env, entry[wi][ei].asid);
+            if (ring < 4) {
+                if (++nhits > 1) {
+                    return dtlb ?
+                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
+                        INST_TLB_MULTI_HIT_CAUSE;
+                }
+                *pwi = wi;
+                *pei = ei;
+                *pring = ring;
+            }
+        }
+    }
+    return nhits ? 0 :
+        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
+}
+
+/*!
+ * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.5.10
+ */
+static unsigned mmu_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if (attr < 12) {
+        access |= PAGE_READ;
+        if (attr & 0x1) {
+            access |= PAGE_EXEC;
+        }
+        if (attr & 0x2) {
+            access |= PAGE_WRITE;
+        }
+    } else if (attr == 13) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    return access;
+}
+
+/*!
+ * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.3.3
+ */
+static unsigned region_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if ((attr < 6 && attr != 3) || attr == 14) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    if (attr > 0 && attr < 6) {
+        access |= PAGE_EXEC;
+    }
+    return access;
+}
+
+static bool is_access_granted(unsigned access, int is_write)
+{
+    switch (is_write) {
+    case 0:
+        return access & PAGE_READ;
+
+    case 1:
+        return access & PAGE_WRITE;
+
+    case 2:
+        return access & PAGE_EXEC;
+
+    default:
+        return 0;
+    }
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring);
+
+static int get_physical_addr_mmu(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi;
+    uint32_t ei;
+    uint8_t ring;
+    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
+
+    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
+            (mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
+            autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) {
+        ret = 0;
+    }
+    if (ret != 0) {
+        return ret;
+    }
+
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (ring < mmu_idx) {
+        return dtlb ?
+            LOAD_STORE_PRIVILEGE_CAUSE :
+            INST_FETCH_PRIVILEGE_CAUSE;
+    }
+
+    *access = mmu_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
+    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
+
+    return 0;
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring)
+{
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+    uint32_t pt_vaddr =
+        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
+    int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0,
+            &paddr, &page_size, &access);
+
+    qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
+            vaddr, ret ? ~0 : paddr);
+
+    if (ret == 0) {
+        uint32_t vpn;
+        uint32_t pte = ldl_phys(paddr);
+
+        *ring = (pte >> 4) & 0x3;
+        *wi = (++env->autorefill_idx) & 0x3;
+        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei);
+        xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte);
+        qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
+                __func__, vaddr, vpn, pte);
+    }
+    return ret;
+}
+
+static int get_physical_addr_region(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi = 0;
+    uint32_t ei = (vaddr >> 29) & 0x7;
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    *access = region_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
+    *page_size = ~REGION_PAGE_MASK + 1;
+
+    return 0;
+}
+
+/*!
+ * Convert virtual address to physical addr.
+ * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
+ *
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else if (xtensa_option_bits_enabled(env->config,
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
+        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else {
+        *paddr = vaddr;
+        *page_size = TARGET_PAGE_SIZE;
+        *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+}
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
new file mode 100644
index 0000000000..09ab3325c9
--- /dev/null
+++ b/target-xtensa/helpers.h
@@ -0,0 +1,32 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
+DEF_HELPER_1(nsa, i32, i32)
+DEF_HELPER_1(nsau, i32, i32)
+DEF_HELPER_1(wsr_windowbase, void, i32)
+DEF_HELPER_3(entry, void, i32, i32, i32)
+DEF_HELPER_1(retw, i32, i32)
+DEF_HELPER_1(rotw, void, i32)
+DEF_HELPER_2(window_check, void, i32, i32)
+DEF_HELPER_0(restore_owb, void)
+DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
+DEF_HELPER_1(simcall, void, env)
+DEF_HELPER_0(dump_state, void)
+
+DEF_HELPER_2(waiti, void, i32, i32)
+DEF_HELPER_2(timer_irq, void, i32, i32)
+DEF_HELPER_1(advance_ccount, void, i32)
+DEF_HELPER_1(check_interrupts, void, env)
+
+DEF_HELPER_1(wsr_rasid, void, i32)
+DEF_HELPER_2(rtlb0, i32, i32, i32)
+DEF_HELPER_2(rtlb1, i32, i32, i32)
+DEF_HELPER_2(itlb, void, i32, i32)
+DEF_HELPER_2(ptlb, i32, i32, i32)
+DEF_HELPER_3(wtlb, void, i32, i32, i32)
+
+#include "def-helper.h"
diff --git a/target-xtensa/machine.c b/target-xtensa/machine.c
new file mode 100644
index 0000000000..ddeffb2da4
--- /dev/null
+++ b/target-xtensa/machine.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
new file mode 100644
index 0000000000..d02706db62
--- /dev/null
+++ b/target-xtensa/op_helper.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helpers.h"
+#include "host-utils.h"
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr);
+
+#define ALIGNED_ONLY
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+static void do_restore_state(void *pc_ptr)
+{
+    TranslationBlock *tb;
+    uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
+
+    tb = tb_find_pc(pc);
+    if (tb) {
+        cpu_restore_state(tb, env, pc);
+    }
+}
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
+            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
+        do_restore_state(retaddr);
+        HELPER(exception_cause_vaddr)(
+                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+    }
+}
+
+void tlb_fill(target_ulong vaddr, int is_write, int mmu_idx, void *retaddr)
+{
+    CPUState *saved_env = env;
+
+    env = cpu_single_env;
+    {
+        uint32_t paddr;
+        uint32_t page_size;
+        unsigned access;
+        int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
+                &paddr, &page_size, &access);
+
+        qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
+                vaddr, is_write, mmu_idx, paddr, ret);
+
+        if (ret == 0) {
+            tlb_set_page(env,
+                    vaddr & TARGET_PAGE_MASK,
+                    paddr & TARGET_PAGE_MASK,
+                    access, mmu_idx, page_size);
+        } else {
+            do_restore_state(retaddr);
+            HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
+        }
+    }
+    env = saved_env;
+}
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
+{
+    uint32_t vector;
+
+    env->pc = pc;
+    if (env->sregs[PS] & PS_EXCM) {
+        if (env->config->ndepc) {
+            env->sregs[DEPC] = pc;
+        } else {
+            env->sregs[EPC1] = pc;
+        }
+        vector = EXC_DOUBLE;
+    } else {
+        env->sregs[EPC1] = pc;
+        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+    }
+
+    env->sregs[EXCCAUSE] = cause;
+    env->sregs[PS] |= PS_EXCM;
+
+    HELPER(exception)(vector);
+}
+
+void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
+{
+    env->sregs[EXCVADDR] = vaddr;
+    HELPER(exception_cause)(pc, cause);
+}
+
+uint32_t HELPER(nsa)(uint32_t v)
+{
+    if (v & 0x80000000) {
+        v = ~v;
+    }
+    return v ? clz32(v) - 1 : 31;
+}
+
+uint32_t HELPER(nsau)(uint32_t v)
+{
+    return v ? clz32(v) : 32;
+}
+
+static void copy_window_from_phys(CPUState *env,
+        uint32_t window, uint32_t phys, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n1 * sizeof(uint32_t));
+        memcpy(env->regs + window + n1, env->phys_regs,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+static void copy_phys_from_window(CPUState *env,
+        uint32_t phys, uint32_t window, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n1 * sizeof(uint32_t));
+        memcpy(env->phys_regs, env->regs + window + n1,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+
+static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
+{
+    return a & (env->config->nareg / 4 - 1);
+}
+
+static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
+{
+    return 1 << windowbase_bound(a, env);
+}
+
+void xtensa_sync_window_from_phys(CPUState *env)
+{
+    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
+}
+
+void xtensa_sync_phys_from_window(CPUState *env)
+{
+    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
+}
+
+static void rotate_window_abs(uint32_t position)
+{
+    xtensa_sync_phys_from_window(env);
+    env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
+    xtensa_sync_window_from_phys(env);
+}
+
+static void rotate_window(uint32_t delta)
+{
+    rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
+}
+
+void HELPER(wsr_windowbase)(uint32_t v)
+{
+    rotate_window_abs(v);
+}
+
+void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
+{
+    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
+    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
+                pc, env->sregs[PS]);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
+        rotate_window(callinc);
+        env->sregs[WINDOW_START] |=
+            windowstart_bit(env->sregs[WINDOW_BASE], env);
+    }
+}
+
+void HELPER(window_check)(uint32_t pc, uint32_t w)
+{
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t m, n;
+
+    if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
+        return;
+    }
+
+    for (n = 1; ; ++n) {
+        if (n > w) {
+            return;
+        }
+        if (windowstart & windowstart_bit(windowbase + n, env)) {
+            break;
+        }
+    }
+
+    m = windowbase_bound(windowbase + n, env);
+    rotate_window(n);
+    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+    env->sregs[EPC1] = env->pc = pc;
+
+    if (windowstart & windowstart_bit(m + 1, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW4);
+    } else if (windowstart & windowstart_bit(m + 2, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW8);
+    } else {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW12);
+    }
+}
+
+uint32_t HELPER(retw)(uint32_t pc)
+{
+    int n = (env->regs[0] >> 30) & 0x3;
+    int m = 0;
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t ret_pc = 0;
+
+    if (windowstart & windowstart_bit(windowbase - 1, env)) {
+        m = 1;
+    } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
+        m = 2;
+    } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
+        m = 3;
+    }
+
+    if (n == 0 || (m != 0 && m != n) ||
+            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal retw instruction(pc = %08x), "
+                "PS = %08x, m = %d, n = %d\n",
+                pc, env->sregs[PS], m, n);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        int owb = windowbase;
+
+        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
+
+        rotate_window(-n);
+        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
+            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
+        } else {
+            /* window underflow */
+            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+                (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+            env->sregs[EPC1] = env->pc = pc;
+
+            if (n == 1) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
+            } else if (n == 2) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
+            } else if (n == 3) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
+            }
+        }
+    }
+    return ret_pc;
+}
+
+void HELPER(rotw)(uint32_t imm4)
+{
+    rotate_window(imm4);
+}
+
+void HELPER(restore_owb)(void)
+{
+    rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
+}
+
+void HELPER(movsp)(uint32_t pc)
+{
+    if ((env->sregs[WINDOW_START] &
+            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
+        HELPER(exception_cause)(pc, ALLOCA_CAUSE);
+    }
+}
+
+void HELPER(wsr_lbeg)(uint32_t v)
+{
+    if (env->sregs[LBEG] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LBEG] = v;
+    }
+}
+
+void HELPER(wsr_lend)(uint32_t v)
+{
+    if (env->sregs[LEND] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LEND] = v;
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+    }
+}
+
+void HELPER(dump_state)(void)
+{
+    cpu_dump_state(env, stderr, fprintf, 0);
+}
+
+void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
+{
+    env->pc = pc;
+    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
+        (intlevel << PS_INTLEVEL_SHIFT);
+    check_interrupts(env);
+    if (env->pending_irq_level) {
+        cpu_loop_exit(env);
+        return;
+    }
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
+
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
+                    wake_ccount - env->sregs[CCOUNT]) {
+                wake_ccount = env->sregs[CCOMPARE + i];
+            }
+        }
+        env->wake_ccount = wake_ccount;
+        qemu_mod_timer(env->ccompare_timer, qemu_get_clock_ns(vm_clock) +
+                muldiv64(wake_ccount - env->sregs[CCOUNT],
+                    1000000, env->config->clock_freq_khz));
+    }
+    env->halt_clock = qemu_get_clock_ns(vm_clock);
+    env->halted = 1;
+    HELPER(exception)(EXCP_HLT);
+}
+
+void HELPER(timer_irq)(uint32_t id, uint32_t active)
+{
+    xtensa_timer_irq(env, id, active);
+}
+
+void HELPER(advance_ccount)(uint32_t d)
+{
+    xtensa_advance_ccount(env, d);
+}
+
+void HELPER(check_interrupts)(CPUState *env)
+{
+    check_interrupts(env);
+}
+
+void HELPER(wsr_rasid)(uint32_t v)
+{
+    v = (v & 0xffffff00) | 0x1;
+    if (v != env->sregs[RASID]) {
+        env->sregs[RASID] = v;
+        tlb_flush(env, 1);
+    }
+}
+
+static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
+{
+    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
+
+    switch (way) {
+    case 4:
+        return (tlbcfg >> 16) & 0x3;
+
+    case 5:
+        return (tlbcfg >> 20) & 0x1;
+
+    case 6:
+        return (tlbcfg >> 24) & 0x1;
+
+    default:
+        return 0;
+    }
+}
+
+/*!
+ * Get bit mask for the virtual address bits translated by the TLB way
+ */
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        switch (way) {
+        case 4:
+            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
+
+        case 5:
+            if (varway56) {
+                return 0xf8000000 << get_page_size(env, dtlb, way);
+            } else {
+                return 0xf8000000;
+            }
+
+        case 6:
+            if (varway56) {
+                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
+            } else {
+                return 0xf0000000;
+            }
+
+        default:
+            return 0xfffff000;
+        }
+    } else {
+        return REGION_PAGE_MASK;
+    }
+}
+
+/*!
+ * Get bit mask for the 'VPN without index' field.
+ * See ISA, 4.6.5.6, data format for RxTLB0
+ */
+static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (way < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        return is32 ? 0xffff8000 : 0xffffc000;
+    } else if (way == 4) {
+        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
+    } else if (way <= 6) {
+        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        if (varway56) {
+            return mask << (way == 5 ? 2 : 3);
+        } else {
+            return mask << 1;
+        }
+    } else {
+        return 0xfffff000;
+    }
+}
+
+/*!
+ * Split virtual address into VPN (with index) and entry index
+ * for the given TLB way
+ */
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei)
+{
+    bool varway56 = dtlb ?
+        env->config->dtlb.varway56 :
+        env->config->itlb.varway56;
+
+    if (!dtlb) {
+        wi &= 7;
+    }
+
+    if (wi < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
+    } else {
+        switch (wi) {
+        case 4:
+            {
+                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
+                *ei = (v >> eibase) & 0x3;
+            }
+            break;
+
+        case 5:
+            if (varway56) {
+                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x3;
+            } else {
+                *ei = (v >> 27) & 0x1;
+            }
+            break;
+
+        case 6:
+            if (varway56) {
+                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x7;
+            } else {
+                *ei = (v >> 28) & 0x1;
+            }
+            break;
+
+        default:
+            *ei = 0;
+            break;
+        }
+    }
+    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+}
+
+/*!
+ * Split TLB address into TLB way, entry index and VPN (with index).
+ * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
+ */
+static void split_tlb_entry_spec(uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        *wi = v & (dtlb ? 0xf : 0x7);
+        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
+    } else {
+        *vpn = v & REGION_PAGE_MASK;
+        *wi = 0;
+        *ei = (v >> 29) & 0x7;
+    }
+}
+
+static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    if (pwi) {
+        *pwi = wi;
+    }
+    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
+}
+
+uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
+    } else {
+        return v & REGION_PAGE_MASK;
+    }
+}
+
+uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
+{
+    const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
+    return entry->paddr | entry->attr;
+}
+
+void HELPER(itlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        if (entry->variable && entry->asid) {
+            tlb_flush_page(env, entry->vaddr);
+            entry->asid = 0;
+        }
+    }
+}
+
+uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        uint32_t ei;
+        uint8_t ring;
+        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
+
+        switch (res) {
+        case 0:
+            if (ring >= xtensa_get_ring(env)) {
+                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
+            }
+            break;
+
+        case INST_TLB_MULTI_HIT_CAUSE:
+        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
+            HELPER(exception_cause_vaddr)(env->pc, res, v);
+            break;
+        }
+        return 0;
+    } else {
+        return (v & REGION_PAGE_MASK) | 0x1;
+    }
+}
+
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
+{
+    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        if (entry->variable) {
+            if (entry->asid) {
+                tlb_flush_page(env, entry->vaddr);
+            }
+            entry->vaddr = vpn;
+            entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+            entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
+            entry->attr = pte & 0xf;
+        } else {
+            qemu_log("%s %d, %d, %d trying to set immutable entry\n",
+                    __func__, dtlb, wi, ei);
+        }
+    } else {
+        tlb_flush_page(env, entry->vaddr);
+        if (xtensa_option_enabled(env->config,
+                    XTENSA_OPTION_REGION_TRANSLATION)) {
+            entry->paddr = pte & REGION_PAGE_MASK;
+        }
+        entry->attr = pte & 0xf;
+    }
+}
+
+void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
new file mode 100644
index 0000000000..93a807e8c0
--- /dev/null
+++ b/target-xtensa/translate.c
@@ -0,0 +1,2414 @@
+/*
+ * Xtensa ISA:
+ * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+#include "sysemu.h"
+
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext {
+    const XtensaConfig *config;
+    TranslationBlock *tb;
+    uint32_t pc;
+    uint32_t next_pc;
+    int cring;
+    int ring;
+    uint32_t lbeg;
+    uint32_t lend;
+    TCGv_i32 litbase;
+    int is_jmp;
+    int singlestep_enabled;
+
+    bool sar_5bit;
+    bool sar_m32_5bit;
+    bool sar_m32_allocated;
+    TCGv_i32 sar_m32;
+
+    uint32_t ccount_delta;
+    unsigned used_window;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_pc;
+static TCGv_i32 cpu_R[16];
+static TCGv_i32 cpu_SR[256];
+static TCGv_i32 cpu_UR[256];
+
+#include "gen-icount.h"
+
+static const char * const sregnames[256] = {
+    [LBEG] = "LBEG",
+    [LEND] = "LEND",
+    [LCOUNT] = "LCOUNT",
+    [SAR] = "SAR",
+    [BR] = "BR",
+    [LITBASE] = "LITBASE",
+    [SCOMPARE1] = "SCOMPARE1",
+    [WINDOW_BASE] = "WINDOW_BASE",
+    [WINDOW_START] = "WINDOW_START",
+    [PTEVADDR] = "PTEVADDR",
+    [RASID] = "RASID",
+    [ITLBCFG] = "ITLBCFG",
+    [DTLBCFG] = "DTLBCFG",
+    [EPC1] = "EPC1",
+    [EPC1 + 1] = "EPC2",
+    [EPC1 + 2] = "EPC3",
+    [EPC1 + 3] = "EPC4",
+    [EPC1 + 4] = "EPC5",
+    [EPC1 + 5] = "EPC6",
+    [EPC1 + 6] = "EPC7",
+    [DEPC] = "DEPC",
+    [EPS2] = "EPS2",
+    [EPS2 + 1] = "EPS3",
+    [EPS2 + 2] = "EPS4",
+    [EPS2 + 3] = "EPS5",
+    [EPS2 + 4] = "EPS6",
+    [EPS2 + 5] = "EPS7",
+    [EXCSAVE1] = "EXCSAVE1",
+    [EXCSAVE1 + 1] = "EXCSAVE2",
+    [EXCSAVE1 + 2] = "EXCSAVE3",
+    [EXCSAVE1 + 3] = "EXCSAVE4",
+    [EXCSAVE1 + 4] = "EXCSAVE5",
+    [EXCSAVE1 + 5] = "EXCSAVE6",
+    [EXCSAVE1 + 6] = "EXCSAVE7",
+    [CPENABLE] = "CPENABLE",
+    [INTSET] = "INTSET",
+    [INTCLEAR] = "INTCLEAR",
+    [INTENABLE] = "INTENABLE",
+    [PS] = "PS",
+    [VECBASE] = "VECBASE",
+    [EXCCAUSE] = "EXCCAUSE",
+    [CCOUNT] = "CCOUNT",
+    [PRID] = "PRID",
+    [EXCVADDR] = "EXCVADDR",
+    [CCOMPARE] = "CCOMPARE0",
+    [CCOMPARE + 1] = "CCOMPARE1",
+    [CCOMPARE + 2] = "CCOMPARE2",
+};
+
+static const char * const uregnames[256] = {
+    [THREADPTR] = "THREADPTR",
+    [FCR] = "FCR",
+    [FSR] = "FSR",
+};
+
+void xtensa_translate_init(void)
+{
+    static const char * const regnames[] = {
+        "ar0", "ar1", "ar2", "ar3",
+        "ar4", "ar5", "ar6", "ar7",
+        "ar8", "ar9", "ar10", "ar11",
+        "ar12", "ar13", "ar14", "ar15",
+    };
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
+            offsetof(CPUState, pc), "pc");
+
+    for (i = 0; i < 16; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                offsetof(CPUState, regs[i]),
+                regnames[i]);
+    }
+
+    for (i = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, sregs[i]),
+                    sregnames[i]);
+        }
+    }
+
+    for (i = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, uregs[i]),
+                    uregnames[i]);
+        }
+    }
+#define GEN_HELPER 2
+#include "helpers.h"
+}
+
+static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
+{
+    return xtensa_option_bits_enabled(dc->config, opt);
+}
+
+static inline bool option_enabled(DisasContext *dc, int opt)
+{
+    return xtensa_option_enabled(dc->config, opt);
+}
+
+static void init_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        dc->litbase = tcg_temp_local_new_i32();
+        tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000);
+    }
+}
+
+static void reset_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        tcg_temp_free(dc->litbase);
+    }
+}
+
+static void init_sar_tracker(DisasContext *dc)
+{
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+    dc->sar_m32_allocated = false;
+}
+
+static void reset_sar_tracker(DisasContext *dc)
+{
+    if (dc->sar_m32_allocated) {
+        tcg_temp_free(dc->sar_m32);
+    }
+}
+
+static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    tcg_gen_andi_i32(cpu_SR[SAR], sa, 0x1f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = true;
+    dc->sar_m32_5bit = false;
+}
+
+static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    TCGv_i32 tmp = tcg_const_i32(32);
+    if (!dc->sar_m32_allocated) {
+        dc->sar_m32 = tcg_temp_local_new_i32();
+        dc->sar_m32_allocated = true;
+    }
+    tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f);
+    tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32);
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = true;
+    tcg_temp_free(tmp);
+}
+
+static void gen_advance_ccount(DisasContext *dc)
+{
+    if (dc->ccount_delta > 0) {
+        TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
+        dc->ccount_delta = 0;
+        gen_helper_advance_ccount(tmp);
+        tcg_temp_free(tmp);
+    }
+}
+
+static void reset_used_window(DisasContext *dc)
+{
+    dc->used_window = 0;
+}
+
+static void gen_exception(DisasContext *dc, int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_advance_ccount(dc);
+    gen_helper_exception(tmp);
+    tcg_temp_free(tmp);
+}
+
+static void gen_exception_cause(DisasContext *dc, uint32_t cause)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
+    gen_helper_exception_cause(tpc, tcause);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+}
+
+static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
+        TCGv_i32 vaddr)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
+    gen_helper_exception_cause_vaddr(tpc, tcause, vaddr);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+}
+
+static void gen_check_privilege(DisasContext *dc)
+{
+    if (dc->cring) {
+        gen_exception_cause(dc, PRIVILEGED_CAUSE);
+    }
+}
+
+static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
+{
+    tcg_gen_mov_i32(cpu_pc, dest);
+    if (dc->singlestep_enabled) {
+        gen_exception(dc, EXCP_DEBUG);
+    } else {
+        gen_advance_ccount(dc);
+        if (slot >= 0) {
+            tcg_gen_goto_tb(slot);
+            tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+    }
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_jump(DisasContext *dc, TCGv dest)
+{
+    gen_jump_slot(dc, dest, -1);
+}
+
+static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_jump_slot(dc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
+static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest,
+        int slot)
+{
+    TCGv_i32 tcallinc = tcg_const_i32(callinc);
+
+    tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS],
+            tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN);
+    tcg_temp_free(tcallinc);
+    tcg_gen_movi_i32(cpu_R[callinc << 2],
+            (callinc << 30) | (dc->next_pc & 0x3fffffff));
+    gen_jump_slot(dc, dest, slot);
+}
+
+static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest)
+{
+    gen_callw_slot(dc, callinc, dest, -1);
+}
+
+static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_callw_slot(dc, callinc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
+static bool gen_check_loop_end(DisasContext *dc, int slot)
+{
+    if (option_enabled(dc, XTENSA_OPTION_LOOP) &&
+            !(dc->tb->flags & XTENSA_TBFLAG_EXCM) &&
+            dc->next_pc == dc->lend) {
+        int label = gen_new_label();
+
+        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
+        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
+        gen_jumpi(dc, dc->lbeg, slot);
+        gen_set_label(label);
+        gen_jumpi(dc, dc->next_pc, -1);
+        return true;
+    }
+    return false;
+}
+
+static void gen_jumpi_check_loop_end(DisasContext *dc, int slot)
+{
+    if (!gen_check_loop_end(dc, slot)) {
+        gen_jumpi(dc, dc->next_pc, slot);
+    }
+}
+
+static void gen_brcond(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
+{
+    int label = gen_new_label();
+
+    tcg_gen_brcond_i32(cond, t0, t1, label);
+    gen_jumpi_check_loop_end(dc, 0);
+    gen_set_label(label);
+    gen_jumpi(dc, dc->pc + offset, 1);
+}
+
+static void gen_brcondi(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, uint32_t t1, uint32_t offset)
+{
+    TCGv_i32 tmp = tcg_const_i32(t1);
+    gen_brcond(dc, cond, t0, tmp, offset);
+    tcg_temp_free(tmp);
+}
+
+static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    gen_advance_ccount(dc);
+    tcg_gen_mov_i32(d, cpu_SR[sr]);
+}
+
+static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10);
+    tcg_gen_or_i32(d, d, cpu_SR[sr]);
+    tcg_gen_andi_i32(d, d, 0xfffffffc);
+}
+
+static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    static void (* const rsr_handler[256])(DisasContext *dc,
+            TCGv_i32 d, uint32_t sr) = {
+        [CCOUNT] = gen_rsr_ccount,
+        [PTEVADDR] = gen_rsr_ptevaddr,
+    };
+
+    if (sregnames[sr]) {
+        if (rsr_handler[sr]) {
+            rsr_handler[sr](dc, d, sr);
+        } else {
+            tcg_gen_mov_i32(d, cpu_SR[sr]);
+        }
+    } else {
+        qemu_log("RSR %d not implemented, ", sr);
+    }
+}
+
+static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lbeg(s);
+}
+
+static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lend(s);
+}
+
+static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+}
+
+static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff);
+}
+
+static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_windowbase(v);
+    reset_used_window(dc);
+}
+
+static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_mov_i32(cpu_SR[sr], v);
+    reset_used_window(dc);
+}
+
+static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000);
+}
+
+static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_rasid(v);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
+}
+
+static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v,
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_andi_i32(tmp, v,
+            dc->config->inttype_mask[INTTYPE_EDGE] |
+            dc->config->inttype_mask[INTTYPE_NMI] |
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp);
+    tcg_temp_free(tmp);
+    gen_helper_check_interrupts(cpu_env);
+}
+
+static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_mov_i32(cpu_SR[sr], v);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
+        PS_UM | PS_EXCM | PS_INTLEVEL;
+
+    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+        mask |= PS_RING;
+    }
+    tcg_gen_andi_i32(cpu_SR[sr], v, mask);
+    reset_used_window(dc);
+    gen_helper_check_interrupts(cpu_env);
+    /* This can change mmu index and tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+}
+
+static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t id = sr - CCOMPARE;
+    if (id < dc->config->nccompare) {
+        uint32_t int_bit = 1 << dc->config->timerint[id];
+        gen_advance_ccount(dc);
+        tcg_gen_mov_i32(cpu_SR[sr], v);
+        tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit);
+        gen_helper_check_interrupts(cpu_env);
+    }
+}
+
+static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    static void (* const wsr_handler[256])(DisasContext *dc,
+            uint32_t sr, TCGv_i32 v) = {
+        [LBEG] = gen_wsr_lbeg,
+        [LEND] = gen_wsr_lend,
+        [SAR] = gen_wsr_sar,
+        [BR] = gen_wsr_br,
+        [LITBASE] = gen_wsr_litbase,
+        [WINDOW_BASE] = gen_wsr_windowbase,
+        [WINDOW_START] = gen_wsr_windowstart,
+        [PTEVADDR] = gen_wsr_ptevaddr,
+        [RASID] = gen_wsr_rasid,
+        [ITLBCFG] = gen_wsr_tlbcfg,
+        [DTLBCFG] = gen_wsr_tlbcfg,
+        [INTSET] = gen_wsr_intset,
+        [INTCLEAR] = gen_wsr_intclear,
+        [INTENABLE] = gen_wsr_intenable,
+        [PS] = gen_wsr_ps,
+        [PRID] = gen_wsr_prid,
+        [CCOMPARE] = gen_wsr_ccompare,
+        [CCOMPARE + 1] = gen_wsr_ccompare,
+        [CCOMPARE + 2] = gen_wsr_ccompare,
+    };
+
+    if (sregnames[sr]) {
+        if (wsr_handler[sr]) {
+            wsr_handler[sr](dc, sr, s);
+        } else {
+            tcg_gen_mov_i32(cpu_SR[sr], s);
+        }
+    } else {
+        qemu_log("WSR %d not implemented, ", sr);
+    }
+}
+
+static void gen_load_store_alignment(DisasContext *dc, int shift,
+        TCGv_i32 addr, bool no_hw_alignment)
+{
+    if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) {
+        tcg_gen_andi_i32(addr, addr, ~0 << shift);
+    } else if (option_enabled(dc, XTENSA_OPTION_HW_ALIGNMENT) &&
+            no_hw_alignment) {
+        int label = gen_new_label();
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_andi_i32(tmp, addr, ~(~0 << shift));
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        gen_exception_cause_vaddr(dc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+        gen_set_label(label);
+        tcg_temp_free(tmp);
+    }
+}
+
+static void gen_waiti(DisasContext *dc, uint32_t imm4)
+{
+    TCGv_i32 pc = tcg_const_i32(dc->next_pc);
+    TCGv_i32 intlevel = tcg_const_i32(imm4);
+    gen_advance_ccount(dc);
+    gen_helper_waiti(pc, intlevel);
+    tcg_temp_free(pc);
+    tcg_temp_free(intlevel);
+}
+
+static void gen_window_check1(DisasContext *dc, unsigned r1)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
+        return;
+    }
+    if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) &&
+            r1 / 4 > dc->used_window) {
+        TCGv_i32 pc = tcg_const_i32(dc->pc);
+        TCGv_i32 w = tcg_const_i32(r1 / 4);
+
+        dc->used_window = r1 / 4;
+        gen_advance_ccount(dc);
+        gen_helper_window_check(pc, w);
+
+        tcg_temp_free(w);
+        tcg_temp_free(pc);
+    }
+}
+
+static void gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2)
+{
+    gen_window_check1(dc, r1 > r2 ? r1 : r2);
+}
+
+static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2,
+        unsigned r3)
+{
+    gen_window_check2(dc, r1, r2 > r3 ? r2 : r3);
+}
+
+static void disas_xtensa_insn(DisasContext *dc)
+{
+#define HAS_OPTION_BITS(opt) do { \
+        if (!option_bits_enabled(dc, opt)) { \
+            qemu_log("Option is not enabled %s:%d\n", \
+                    __FILE__, __LINE__); \
+            goto invalid_opcode; \
+        } \
+    } while (0)
+
+#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt))
+
+#define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__)
+#define RESERVED() do { \
+        qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \
+                dc->pc, b0, b1, b2, __FILE__, __LINE__); \
+        goto invalid_opcode; \
+    } while (0)
+
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define OP0 (((b0) & 0xf0) >> 4)
+#define OP1 (((b2) & 0xf0) >> 4)
+#define OP2 ((b2) & 0xf)
+#define RRR_R ((b1) & 0xf)
+#define RRR_S (((b1) & 0xf0) >> 4)
+#define RRR_T ((b0) & 0xf)
+#else
+#define OP0 (((b0) & 0xf))
+#define OP1 (((b2) & 0xf))
+#define OP2 (((b2) & 0xf0) >> 4)
+#define RRR_R (((b1) & 0xf0) >> 4)
+#define RRR_S (((b1) & 0xf))
+#define RRR_T (((b0) & 0xf0) >> 4)
+#endif
+
+#define RRRN_R RRR_R
+#define RRRN_S RRR_S
+#define RRRN_T RRR_T
+
+#define RRI8_R RRR_R
+#define RRI8_S RRR_S
+#define RRI8_T RRR_T
+#define RRI8_IMM8 (b2)
+#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8)
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define RI16_IMM16 (((b1) << 8) | (b2))
+#else
+#define RI16_IMM16 (((b2) << 8) | (b1))
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALL_N (((b0) & 0xc) >> 2)
+#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
+#else
+#define CALL_N (((b0) & 0x30) >> 4)
+#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
+#endif
+#define CALL_OFFSET_SE \
+    (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET)
+
+#define CALLX_N CALL_N
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALLX_M ((b0) & 0x3)
+#else
+#define CALLX_M (((b0) & 0xc0) >> 6)
+#endif
+#define CALLX_S RRR_S
+
+#define BRI12_M CALLX_M
+#define BRI12_S RRR_S
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2))
+#else
+#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
+#endif
+#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12)
+
+#define BRI8_M BRI12_M
+#define BRI8_R RRI8_R
+#define BRI8_S RRI8_S
+#define BRI8_IMM8 RRI8_IMM8
+#define BRI8_IMM8_SE RRI8_IMM8_SE
+
+#define RSR_SR (b1)
+
+    uint8_t b0 = ldub_code(dc->pc);
+    uint8_t b1 = ldub_code(dc->pc + 1);
+    uint8_t b2 = ldub_code(dc->pc + 2);
+
+    static const uint32_t B4CONST[] = {
+        0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
+    static const uint32_t B4CONSTU[] = {
+        32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
+    if (OP0 >= 8) {
+        dc->next_pc = dc->pc + 2;
+        HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
+    } else {
+        dc->next_pc = dc->pc + 3;
+    }
+
+    switch (OP0) {
+    case 0: /*QRST*/
+        switch (OP1) {
+        case 0: /*RST0*/
+            switch (OP2) {
+            case 0: /*ST0*/
+                if ((RRR_R & 0xc) == 0x8) {
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                }
+
+                switch (RRR_R) {
+                case 0: /*SNM0*/
+                    switch (CALLX_M) {
+                    case 0: /*ILL*/
+                        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        break;
+
+                    case 1: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    case 2: /*JR*/
+                        switch (CALLX_N) {
+                        case 0: /*RET*/
+                        case 2: /*JX*/
+                            gen_window_check1(dc, CALLX_S);
+                            gen_jump(dc, cpu_R[CALLX_S]);
+                            break;
+
+                        case 1: /*RETWw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                                gen_advance_ccount(dc);
+                                gen_helper_retw(tmp, tmp);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        case 3: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 3: /*CALLX*/
+                        gen_window_check2(dc, CALLX_S, CALLX_N << 2);
+                        switch (CALLX_N) {
+                        case 0: /*CALLX0*/
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        case 1: /*CALLX4w*/
+                        case 2: /*CALLX8w*/
+                        case 3: /*CALLX12w*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                gen_callw(dc, CALLX_N, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+                        }
+                        break;
+                    }
+                    break;
+
+                case 1: /*MOVSPw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    gen_window_check2(dc, RRR_T, RRR_S);
+                    {
+                        TCGv_i32 pc = tcg_const_i32(dc->pc);
+                        gen_advance_ccount(dc);
+                        gen_helper_movsp(pc);
+                        tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
+                        tcg_temp_free(pc);
+                    }
+                    break;
+
+                case 2: /*SYNC*/
+                    switch (RRR_T) {
+                    case 0: /*ISYNC*/
+                        break;
+
+                    case 1: /*RSYNC*/
+                        break;
+
+                    case 2: /*ESYNC*/
+                        break;
+
+                    case 3: /*DSYNC*/
+                        break;
+
+                    case 8: /*EXCW*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        break;
+
+                    case 12: /*MEMW*/
+                        break;
+
+                    case 13: /*EXTW*/
+                        break;
+
+                    case 15: /*NOP*/
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+                    }
+                    break;
+
+                case 3: /*RFEIx*/
+                    switch (RRR_T) {
+                    case 0: /*RFETx*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        switch (RRR_S) {
+                        case 0: /*RFEx*/
+                            gen_check_privilege(dc);
+                            tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                            gen_helper_check_interrupts(cpu_env);
+                            gen_jump(dc, cpu_SR[EPC1]);
+                            break;
+
+                        case 1: /*RFUEx*/
+                            RESERVED();
+                            break;
+
+                        case 2: /*RFDEx*/
+                            gen_check_privilege(dc);
+                            gen_jump(dc, cpu_SR[
+                                    dc->config->ndepc ? DEPC : EPC1]);
+                            break;
+
+                        case 4: /*RFWOw*/
+                        case 5: /*RFWUw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            gen_check_privilege(dc);
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(1);
+
+                                tcg_gen_andi_i32(
+                                        cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                                tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]);
+
+                                if (RRR_S == 4) {
+                                    tcg_gen_andc_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                } else {
+                                    tcg_gen_or_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                }
+
+                                gen_helper_restore_owb();
+                                gen_helper_check_interrupts(cpu_env);
+                                gen_jump(dc, cpu_SR[EPC1]);
+
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        default: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 1: /*RFIx*/
+                        HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT);
+                        if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) {
+                            gen_check_privilege(dc);
+                            tcg_gen_mov_i32(cpu_SR[PS],
+                                    cpu_SR[EPS2 + RRR_S - 2]);
+                            gen_helper_check_interrupts(cpu_env);
+                            gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]);
+                        } else {
+                            qemu_log("RFI %d is illegal\n", RRR_S);
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
+                        break;
+
+                    case 2: /*RFME*/
+                        TBD();
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    }
+                    break;
+
+                case 4: /*BREAKx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    TBD();
+                    break;
+
+                case 5: /*SYSCALLx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    switch (RRR_S) {
+                    case 0: /*SYSCALLx*/
+                        gen_exception_cause(dc, SYSCALL_CAUSE);
+                        break;
+
+                    case 1: /*SIMCALL*/
+                        if (semihosting_enabled) {
+                            gen_check_privilege(dc);
+                            gen_helper_simcall(cpu_env);
+                        } else {
+                            qemu_log("SIMCALL but semihosting is disabled\n");
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
+                        break;
+
+                    default:
+                        RESERVED();
+                        break;
+                    }
+                    break;
+
+                case 6: /*RSILx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    gen_check_privilege(dc);
+                    gen_window_check1(dc, RRR_T);
+                    tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
+                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
+                    tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
+                    gen_helper_check_interrupts(cpu_env);
+                    gen_jumpi_check_loop_end(dc, 0);
+                    break;
+
+                case 7: /*WAITIx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    gen_check_privilege(dc);
+                    gen_waiti(dc, RRR_S);
+                    break;
+
+                case 8: /*ANY4p*/
+                case 9: /*ALL4p*/
+                case 10: /*ANY8p*/
+                case 11: /*ALL8p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    {
+                        const unsigned shift = (RRR_R & 2) ? 8 : 4;
+                        TCGv_i32 mask = tcg_const_i32(
+                                ((1 << shift) - 1) << RRR_S);
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+
+                        tcg_gen_and_i32(tmp, cpu_SR[BR], mask);
+                        if (RRR_R & 1) { /*ALL*/
+                            tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S);
+                        } else { /*ANY*/
+                            tcg_gen_add_i32(tmp, tmp, mask);
+                        }
+                        tcg_gen_shri_i32(tmp, tmp, RRR_S + shift);
+                        tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR],
+                                tmp, RRR_T, 1);
+                        tcg_temp_free(mask);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 1: /*AND*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 2: /*OR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 3: /*XOR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 4: /*ST1*/
+                switch (RRR_R) {
+                case 0: /*SSR*/
+                    gen_window_check1(dc, RRR_S);
+                    gen_right_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 1: /*SSL*/
+                    gen_window_check1(dc, RRR_S);
+                    gen_left_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 2: /*SSA8L*/
+                    gen_window_check1(dc, RRR_S);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 3: /*SSA8B*/
+                    gen_window_check1(dc, RRR_S);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_left_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 4: /*SSAI*/
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_S | ((RRR_T & 1) << 4));
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 6: /*RER*/
+                    TBD();
+                    break;
+
+                case 7: /*WER*/
+                    TBD();
+                    break;
+
+                case 8: /*ROTWw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    gen_check_privilege(dc);
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
+                        gen_helper_rotw(tmp);
+                        tcg_temp_free(tmp);
+                        reset_used_window(dc);
+                    }
+                    break;
+
+                case 14: /*NSAu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_window_check2(dc, RRR_S, RRR_T);
+                    gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                case 15: /*NSAUu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_window_check2(dc, RRR_S, RRR_T);
+                    gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 5: /*TLB*/
+                HAS_OPTION_BITS(
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION));
+                gen_check_privilege(dc);
+                gen_window_check2(dc, RRR_S, RRR_T);
+                {
+                    TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0);
+
+                    switch (RRR_R & 7) {
+                    case 3: /*RITLB0*/ /*RDTLB0*/
+                        gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 4: /*IITLB*/ /*IDTLB*/
+                        gen_helper_itlb(cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 5: /*PITLB*/ /*PDTLB*/
+                        tcg_gen_movi_i32(cpu_pc, dc->pc);
+                        gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 6: /*WITLB*/ /*WDTLB*/
+                        gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 7: /*RITLB1*/ /*RDTLB1*/
+                        gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    default:
+                        tcg_temp_free(dtlb);
+                        RESERVED();
+                        break;
+                    }
+                    tcg_temp_free(dtlb);
+                }
+                break;
+
+            case 6: /*RT0*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                switch (RRR_S) {
+                case 0: /*NEG*/
+                    tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    break;
+
+                case 1: /*ABS*/
+                    {
+                        int label = gen_new_label();
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        tcg_gen_brcondi_i32(
+                                TCG_COND_GE, cpu_R[RRR_R], 0, label);
+                        tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        gen_set_label(label);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 7: /*reserved*/
+                RESERVED();
+                break;
+
+            case 8: /*ADD*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 9: /*ADD**/
+            case 10:
+            case 11:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8);
+                    tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 12: /*SUB*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*SUB**/
+            case 14:
+            case 15:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12);
+                    tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+            }
+            break;
+
+        case 1: /*RST1*/
+            switch (OP2) {
+            case 0: /*SLLI*/
+            case 1:
+                gen_window_check2(dc, RRR_R, RRR_S);
+                tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S],
+                        32 - (RRR_T | ((OP2 & 1) << 4)));
+                break;
+
+            case 2: /*SRAI*/
+            case 3:
+                gen_window_check2(dc, RRR_R, RRR_T);
+                tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T],
+                        RRR_S | ((OP2 & 1) << 4));
+                break;
+
+            case 4: /*SRLI*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S);
+                break;
+
+            case 6: /*XSR*/
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    if (RSR_SR >= 64) {
+                        gen_check_privilege(dc);
+                    }
+                    gen_window_check1(dc, RRR_T);
+                    tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
+                    gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                    gen_wsr(dc, RSR_SR, tmp);
+                    tcg_temp_free(tmp);
+                    if (!sregnames[RSR_SR]) {
+                        TBD();
+                    }
+                }
+                break;
+
+                /*
+                 * Note: 64 bit ops are used here solely because SAR values
+                 * have range 0..63
+                 */
+#define gen_shift_reg(cmd, reg) do { \
+                    TCGv_i64 tmp = tcg_temp_new_i64(); \
+                    tcg_gen_extu_i32_i64(tmp, reg); \
+                    tcg_gen_##cmd##_i64(v, v, tmp); \
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], v); \
+                    tcg_temp_free_i64(v); \
+                    tcg_temp_free_i64(tmp); \
+                } while (0)
+
+#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR])
+
+            case 8: /*SRC*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 9: /*SRL*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                if (dc->sar_5bit) {
+                    tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 10: /*SLL*/
+                gen_window_check2(dc, RRR_R, RRR_S);
+                if (dc->sar_m32_5bit) {
+                    tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    TCGv_i32 s = tcg_const_i32(32);
+                    tcg_gen_sub_i32(s, s, cpu_SR[SAR]);
+                    tcg_gen_andi_i32(s, s, 0x3f);
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]);
+                    gen_shift_reg(shl, s);
+                    tcg_temp_free(s);
+                }
+                break;
+
+            case 11: /*SRA*/
+                gen_window_check2(dc, RRR_R, RRR_T);
+                if (dc->sar_5bit) {
+                    tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(sar);
+                }
+                break;
+#undef gen_shift
+#undef gen_shift_reg
+
+            case 12: /*MUL16U*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            case 13: /*MUL16S*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 2: /*RST2*/
+            if (OP2 >= 8) {
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+            }
+
+            if (OP2 >= 12) {
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV);
+                int label = gen_new_label();
+                tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label);
+                gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE);
+                gen_set_label(label);
+            }
+
+            switch (OP2) {
+#define BOOLEAN_LOGIC(fn, r, s, t) \
+                do { \
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); \
+                    TCGv_i32 tmp1 = tcg_temp_new_i32(); \
+                    TCGv_i32 tmp2 = tcg_temp_new_i32(); \
+                    \
+                    tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \
+                    tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \
+                    tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \
+                    tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \
+                    tcg_temp_free(tmp1); \
+                    tcg_temp_free(tmp2); \
+                } while (0)
+
+            case 0: /*ANDBp*/
+                BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 1: /*ANDBCp*/
+                BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 2: /*ORBp*/
+                BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 3: /*ORBCp*/
+                BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 4: /*XORBp*/
+                BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T);
+                break;
+
+#undef BOOLEAN_LOGIC
+
+            case 8: /*MULLi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+                tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 10: /*MULUHi*/
+            case 11: /*MULSHi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+                {
+                    TCGv_i64 r = tcg_temp_new_i64();
+                    TCGv_i64 s = tcg_temp_new_i64();
+                    TCGv_i64 t = tcg_temp_new_i64();
+
+                    if (OP2 == 10) {
+                        tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]);
+                    }
+                    tcg_gen_mul_i64(r, s, t);
+                    tcg_gen_shri_i64(r, r, 32);
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r);
+
+                    tcg_temp_free_i64(r);
+                    tcg_temp_free_i64(s);
+                    tcg_temp_free_i64(t);
+                }
+                break;
+
+            case 12: /*QUOUi*/
+                tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*QUOSi*/
+            case 15: /*REMSi*/
+                {
+                    int label1 = gen_new_label();
+                    int label2 = gen_new_label();
+
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000,
+                            label1);
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff,
+                            label1);
+                    tcg_gen_movi_i32(cpu_R[RRR_R],
+                            OP2 == 13 ? 0x80000000 : 0);
+                    tcg_gen_br(label2);
+                    gen_set_label(label1);
+                    if (OP2 == 13) {
+                        tcg_gen_div_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_rem_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    }
+                    gen_set_label(label2);
+                }
+                break;
+
+            case 14: /*REMUi*/
+                tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 3: /*RST3*/
+            switch (OP2) {
+            case 0: /*RSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
+                gen_window_check1(dc, RRR_T);
+                gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
+                break;
+
+            case 1: /*WSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
+                gen_window_check1(dc, RRR_T);
+                gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
+                break;
+
+            case 2: /*SEXTu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    int shift = 24 - RRR_T;
+
+                    if (shift == 24) {
+                        tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else if (shift == 16) {
+                        tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift);
+                        tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift);
+                        tcg_temp_free(tmp);
+                    }
+                }
+                break;
+
+            case 3: /*CLAMPSu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    TCGv_i32 tmp1 = tcg_temp_new_i32();
+                    TCGv_i32 tmp2 = tcg_temp_new_i32();
+                    int label = gen_new_label();
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T);
+                    tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]);
+                    tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7));
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    tcg_gen_brcondi_i32(TCG_COND_EQ, tmp2, 0, label);
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31);
+                    tcg_gen_xori_i32(cpu_R[RRR_R], tmp1,
+                            0xffffffff >> (25 - RRR_T));
+
+                    gen_set_label(label);
+
+                    tcg_temp_free(tmp1);
+                    tcg_temp_free(tmp2);
+                }
+                break;
+
+            case 4: /*MINu*/
+            case 5: /*MAXu*/
+            case 6: /*MINUu*/
+            case 7: /*MAXUu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_LE,
+                        TCG_COND_GE,
+                        TCG_COND_LEU,
+                        TCG_COND_GEU
+                    };
+                    int label = gen_new_label();
+
+                    if (RRR_R != RRR_T) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_S], cpu_R[RRR_T], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_T], cpu_R[RRR_S], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    }
+                    gen_set_label(label);
+                }
+                break;
+
+            case 8: /*MOVEQZ*/
+            case 9: /*MOVNEZ*/
+            case 10: /*MOVLTZ*/
+            case 11: /*MOVGEZ*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_NE,
+                        TCG_COND_EQ,
+                        TCG_COND_GE,
+                        TCG_COND_LT
+                    };
+                    int label = gen_new_label();
+                    tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                }
+                break;
+
+            case 12: /*MOVFp*/
+            case 13: /*MOVTp*/
+                HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    int label = gen_new_label();
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+
+                    tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T);
+                    tcg_gen_brcondi_i32(
+                            OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE,
+                            tmp, 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 14: /*RUR*/
+                gen_window_check1(dc, RRR_R);
+                {
+                    int st = (RRR_S << 4) + RRR_T;
+                    if (uregnames[st]) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]);
+                    } else {
+                        qemu_log("RUR %d not implemented, ", st);
+                        TBD();
+                    }
+                }
+                break;
+
+            case 15: /*WUR*/
+                gen_window_check1(dc, RRR_T);
+                {
+                    if (uregnames[RSR_SR]) {
+                        tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]);
+                    } else {
+                        qemu_log("WUR %d not implemented, ", RSR_SR);
+                        TBD();
+                    }
+                }
+                break;
+
+            }
+            break;
+
+        case 4: /*EXTUI*/
+        case 5:
+            gen_window_check2(dc, RRR_R, RRR_T);
+            {
+                int shiftimm = RRR_S | (OP1 << 4);
+                int maskimm = (1 << (OP2 + 1)) - 1;
+
+                TCGv_i32 tmp = tcg_temp_new_i32();
+                tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm);
+                tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm);
+                tcg_temp_free(tmp);
+            }
+            break;
+
+        case 6: /*CUST0*/
+            RESERVED();
+            break;
+
+        case 7: /*CUST1*/
+            RESERVED();
+            break;
+
+        case 8: /*LSCXp*/
+            HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+            TBD();
+            break;
+
+        case 9: /*LSC4*/
+            gen_window_check2(dc, RRR_S, RRR_T);
+            switch (OP2) {
+            case 0: /*L32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            case 4: /*S32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            default:
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 10: /*FP0*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
+            break;
+
+        case 11: /*FP1*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
+            break;
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    case 1: /*L32R*/
+        gen_window_check1(dc, RRR_T);
+        {
+            TCGv_i32 tmp = tcg_const_i32(
+                    ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ?
+                     0 : ((dc->pc + 3) & ~3)) +
+                    (0xfffc0000 | (RI16_IMM16 << 2)));
+
+            if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+                tcg_gen_add_i32(tmp, tmp, dc->litbase);
+            }
+            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring);
+            tcg_temp_free(tmp);
+        }
+        break;
+
+    case 2: /*LSAI*/
+#define gen_load_store(type, shift) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
+            if (shift) { \
+                gen_load_store_alignment(dc, shift, addr, false); \
+            } \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+        switch (RRI8_R) {
+        case 0: /*L8UI*/
+            gen_load_store(ld8u, 0);
+            break;
+
+        case 1: /*L16UI*/
+            gen_load_store(ld16u, 1);
+            break;
+
+        case 2: /*L32I*/
+            gen_load_store(ld32u, 2);
+            break;
+
+        case 4: /*S8I*/
+            gen_load_store(st8, 0);
+            break;
+
+        case 5: /*S16I*/
+            gen_load_store(st16, 1);
+            break;
+
+        case 6: /*S32I*/
+            gen_load_store(st32, 2);
+            break;
+
+        case 7: /*CACHEc*/
+            if (RRI8_T < 8) {
+                HAS_OPTION(XTENSA_OPTION_DCACHE);
+            }
+
+            switch (RRI8_T) {
+            case 0: /*DPFRc*/
+                break;
+
+            case 1: /*DPFWc*/
+                break;
+
+            case 2: /*DPFROc*/
+                break;
+
+            case 3: /*DPFWOc*/
+                break;
+
+            case 4: /*DHWBc*/
+                break;
+
+            case 5: /*DHWBIc*/
+                break;
+
+            case 6: /*DHIc*/
+                break;
+
+            case 7: /*DIIc*/
+                break;
+
+            case 8: /*DCEc*/
+                switch (OP1) {
+                case 0: /*DPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*DHUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*DIUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 4: /*DIWBc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                case 5: /*DIWBIc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 12: /*IPFc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 13: /*ICEc*/
+                switch (OP1) {
+                case 0: /*IPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*IHUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*IIUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 14: /*IHIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 15: /*IIIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        case 9: /*L16SI*/
+            gen_load_store(ld16s, 1);
+            break;
+#undef gen_load_store
+
+        case 10: /*MOVI*/
+            gen_window_check1(dc, RRI8_T);
+            tcg_gen_movi_i32(cpu_R[RRI8_T],
+                    RRI8_IMM8 | (RRI8_S << 8) |
+                    ((RRI8_S & 0x8) ? 0xfffff000 : 0));
+            break;
+
+#define gen_load_store_no_hw_align(type) do { \
+            TCGv_i32 addr = tcg_temp_local_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \
+            gen_load_store_alignment(dc, 2, addr, true); \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+        case 11: /*L32AIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/
+            break;
+
+        case 12: /*ADDI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE);
+            break;
+
+        case 13: /*ADDMI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8);
+            break;
+
+        case 14: /*S32C1Iy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_window_check2(dc, RRI8_S, RRI8_T);
+            {
+                int label = gen_new_label();
+                TCGv_i32 tmp = tcg_temp_local_new_i32();
+                TCGv_i32 addr = tcg_temp_local_new_i32();
+
+                tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]);
+                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
+                gen_load_store_alignment(dc, 2, addr, true);
+                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring);
+                tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T],
+                        cpu_SR[SCOMPARE1], label);
+
+                tcg_gen_qemu_st32(tmp, addr, dc->cring);
+
+                gen_set_label(label);
+                tcg_temp_free(addr);
+                tcg_temp_free(tmp);
+            }
+            break;
+
+        case 15: /*S32RIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store_no_hw_align(st32); /*TODO release?*/
+            break;
+#undef gen_load_store_no_hw_align
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    case 3: /*LSCIp*/
+        HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+        TBD();
+        break;
+
+    case 4: /*MAC16d*/
+        HAS_OPTION(XTENSA_OPTION_MAC16);
+        TBD();
+        break;
+
+    case 5: /*CALLN*/
+        switch (CALL_N) {
+        case 0: /*CALL0*/
+            tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+            gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
+            break;
+
+        case 1: /*CALL4w*/
+        case 2: /*CALL8w*/
+        case 3: /*CALL12w*/
+            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            gen_window_check1(dc, CALL_N << 2);
+            gen_callwi(dc, CALL_N,
+                    (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
+            break;
+        }
+        break;
+
+    case 6: /*SI*/
+        switch (CALL_N) {
+        case 0: /*J*/
+            gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0);
+            break;
+
+        case 1: /*BZ*/
+            gen_window_check1(dc, BRI12_S);
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQZ*/
+                    TCG_COND_NE, /*BNEZ*/
+                    TCG_COND_LT, /*BLTZ*/
+                    TCG_COND_GE, /*BGEZ*/
+                };
+
+                gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0,
+                        4 + BRI12_IMM12_SE);
+            }
+            break;
+
+        case 2: /*BI0*/
+            gen_window_check1(dc, BRI8_S);
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQI*/
+                    TCG_COND_NE, /*BNEI*/
+                    TCG_COND_LT, /*BLTI*/
+                    TCG_COND_GE, /*BGEI*/
+                };
+
+                gen_brcondi(dc, cond[BRI8_M & 3],
+                        cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE);
+            }
+            break;
+
+        case 3: /*BI1*/
+            switch (BRI8_M) {
+            case 0: /*ENTRYw*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                {
+                    TCGv_i32 pc = tcg_const_i32(dc->pc);
+                    TCGv_i32 s = tcg_const_i32(BRI12_S);
+                    TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
+                    gen_advance_ccount(dc);
+                    gen_helper_entry(pc, s, imm);
+                    tcg_temp_free(imm);
+                    tcg_temp_free(s);
+                    tcg_temp_free(pc);
+                    reset_used_window(dc);
+                }
+                break;
+
+            case 1: /*B1*/
+                switch (BRI8_R) {
+                case 0: /*BFp*/
+                case 1: /*BTp*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S);
+                        gen_brcondi(dc,
+                                BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ,
+                                tmp, 0, 4 + RRI8_IMM8_SE);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 8: /*LOOP*/
+                case 9: /*LOOPNEZ*/
+                case 10: /*LOOPGTZ*/
+                    HAS_OPTION(XTENSA_OPTION_LOOP);
+                    gen_window_check1(dc, RRI8_S);
+                    {
+                        uint32_t lend = dc->pc + RRI8_IMM8 + 4;
+                        TCGv_i32 tmp = tcg_const_i32(lend);
+
+                        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
+                        tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
+                        gen_wsr_lend(dc, LEND, tmp);
+                        tcg_temp_free(tmp);
+
+                        if (BRI8_R > 8) {
+                            int label = gen_new_label();
+                            tcg_gen_brcondi_i32(
+                                    BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT,
+                                    cpu_R[RRI8_S], 0, label);
+                            gen_jumpi(dc, lend, 1);
+                            gen_set_label(label);
+                        }
+
+                        gen_jumpi(dc, dc->next_pc, 0);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 2: /*BLTUI*/
+            case 3: /*BGEUI*/
+                gen_window_check1(dc, BRI8_S);
+                gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU,
+                        cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE);
+                break;
+            }
+            break;
+
+        }
+        break;
+
+    case 7: /*B*/
+        {
+            TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ;
+
+            switch (RRI8_R & 7) {
+            case 0: /*BNONE*/ /*BANY*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 1: /*BEQ*/ /*BNE*/
+            case 2: /*BLT*/ /*BGE*/
+            case 3: /*BLTU*/ /*BGEU*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    static const TCGCond cond[] = {
+                        [1] = TCG_COND_EQ,
+                        [2] = TCG_COND_LT,
+                        [3] = TCG_COND_LTU,
+                        [9] = TCG_COND_NE,
+                        [10] = TCG_COND_GE,
+                        [11] = TCG_COND_GEU,
+                    };
+                    gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                }
+                break;
+
+            case 4: /*BALL*/ /*BNALL*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 5: /*BBC*/ /*BBS*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
+                {
+                    TCGv_i32 bit = tcg_const_i32(1);
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f);
+                    tcg_gen_shl_i32(bit, bit, tmp);
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                    tcg_temp_free(bit);
+                }
+                break;
+
+            case 6: /*BBCI*/ /*BBSI*/
+            case 7:
+                gen_window_check1(dc, RRI8_S);
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_S],
+                            1 << (((RRI8_R & 1) << 4) | RRI8_T));
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            }
+        }
+        break;
+
+#define gen_narrow_load_store(type) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRRN_S, RRRN_T); \
+            tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
+            gen_load_store_alignment(dc, 2, addr, false); \
+            tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+    case 8: /*L32I.Nn*/
+        gen_narrow_load_store(ld32u);
+        break;
+
+    case 9: /*S32I.Nn*/
+        gen_narrow_load_store(st32);
+        break;
+#undef gen_narrow_load_store
+
+    case 10: /*ADD.Nn*/
+        gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T);
+        tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]);
+        break;
+
+    case 11: /*ADDI.Nn*/
+        gen_window_check2(dc, RRRN_R, RRRN_S);
+        tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1);
+        break;
+
+    case 12: /*ST2n*/
+        gen_window_check1(dc, RRRN_S);
+        if (RRRN_T < 8) { /*MOVI.Nn*/
+            tcg_gen_movi_i32(cpu_R[RRRN_S],
+                    RRRN_R | (RRRN_T << 4) |
+                    ((RRRN_T & 6) == 6 ? 0xffffff80 : 0));
+        } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/
+            TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ;
+
+            gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0,
+                    4 + (RRRN_R | ((RRRN_T & 3) << 4)));
+        }
+        break;
+
+    case 13: /*ST3n*/
+        switch (RRRN_R) {
+        case 0: /*MOV.Nn*/
+            gen_window_check2(dc, RRRN_S, RRRN_T);
+            tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]);
+            break;
+
+        case 15: /*S3*/
+            switch (RRRN_T) {
+            case 0: /*RET.Nn*/
+                gen_jump(dc, cpu_R[0]);
+                break;
+
+            case 1: /*RETW.Nn*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                {
+                    TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                    gen_advance_ccount(dc);
+                    gen_helper_retw(tmp, tmp);
+                    gen_jump(dc, tmp);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 2: /*BREAK.Nn*/
+                TBD();
+                break;
+
+            case 3: /*NOP.Nn*/
+                break;
+
+            case 6: /*ILL.Nn*/
+                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
+            break;
+
+        default: /*reserved*/
+            RESERVED();
+            break;
+        }
+        break;
+
+    default: /*reserved*/
+        RESERVED();
+        break;
+    }
+
+    gen_check_loop_end(dc, 0);
+    dc->pc = dc->next_pc;
+
+    return;
+
+invalid_opcode:
+    qemu_log("INVALID(pc = %08x)\n", dc->pc);
+    dc->pc = dc->next_pc;
+#undef HAS_OPTION
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_i32(cpu_pc, dc->pc);
+                gen_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+static void gen_intermediate_code_internal(
+        CPUState *env, TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc;
+    int insn_count = 0;
+    int j, lj = -1;
+    uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    int max_insns = tb->cflags & CF_COUNT_MASK;
+    uint32_t pc_start = tb->pc;
+    uint32_t next_page_start =
+        (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    dc.config = env->config;
+    dc.singlestep_enabled = env->singlestep_enabled;
+    dc.tb = tb;
+    dc.pc = pc_start;
+    dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
+    dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring;
+    dc.lbeg = env->sregs[LBEG];
+    dc.lend = env->sregs[LEND];
+    dc.is_jmp = DISAS_NEXT;
+    dc.ccount_delta = 0;
+
+    init_litbase(&dc);
+    init_sar_tracker(&dc);
+    reset_used_window(&dc);
+
+    gen_icount_start();
+
+    if (env->singlestep_enabled && env->exception_taken) {
+        env->exception_taken = 0;
+        tcg_gen_movi_i32(cpu_pc, dc.pc);
+        gen_exception(&dc, EXCP_DEBUG);
+    }
+
+    do {
+        check_breakpoint(env, &dc);
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc.pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = insn_count;
+        }
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc.pc);
+        }
+
+        ++dc.ccount_delta;
+
+        if (insn_count + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        disas_xtensa_insn(&dc);
+        ++insn_count;
+        if (env->singlestep_enabled) {
+            tcg_gen_movi_i32(cpu_pc, dc.pc);
+            gen_exception(&dc, EXCP_DEBUG);
+            break;
+        }
+    } while (dc.is_jmp == DISAS_NEXT &&
+            insn_count < max_insns &&
+            dc.pc < next_page_start &&
+            gen_opc_ptr < gen_opc_end);
+
+    reset_litbase(&dc);
+    reset_sar_tracker(&dc);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    if (dc.is_jmp == DISAS_NEXT) {
+        gen_jumpi(&dc, dc.pc, 0);
+    }
+    gen_icount_end(tb, insn_count);
+    *gen_opc_ptr = INDEX_op_end;
+
+    if (!search_pc) {
+        tb->size = dc.pc - pc_start;
+        tb->icount = insn_count;
+    }
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+    gen_intermediate_code_internal(env, tb, 1);
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+        int flags)
+{
+    int i, j;
+
+    cpu_fprintf(f, "PC=%08x\n\n", env->pc);
+
+    for (i = j = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", sregnames[i], env->sregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
+
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+
+    for (i = j = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", uregnames[i], env->uregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
+
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+
+    for (i = 0; i < 16; ++i) {
+        cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
+
+    cpu_fprintf(f, "\n");
+
+    for (i = 0; i < env->config->nareg; ++i) {
+        cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index d831684803..e3c63adc3e 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -1560,7 +1560,7 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
         break;
 
     case INDEX_op_ext32u_i64:
-        tcg_out_rld (s, RLDICR, args[0], args[1], 0, 32);
+        tcg_out_rld (s, RLDICL, args[0], args[1], 0, 32);
         break;
 
     case INDEX_op_setcond_i32:
diff --git a/tests/xtensa/Makefile b/tests/xtensa/Makefile
new file mode 100644
index 0000000000..70bd097ec4
--- /dev/null
+++ b/tests/xtensa/Makefile
@@ -0,0 +1,74 @@
+-include ../../config-host.mak
+
+CROSS=xtensa-dc232b-elf-
+
+ifndef XT
+SIM = qemu-system-xtensa
+SIMFLAGS = -M dc232b -nographic -semihosting $(EXTFLAGS) -kernel
+SIMDEBUG = -s -S
+else
+SIM = xt-run
+SIMFLAGS = --xtensa-core=DC_B_232L --exit_with_target_code $(EXTFLAGS)
+SIMDEBUG = --gdbserve=0
+endif
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)gcc -x assembler
+LD      = $(CROSS)ld
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o vectors.o
+
+TESTCASES += test_b.tst
+TESTCASES += test_bi.tst
+#TESTCASES += test_boolean.tst
+TESTCASES += test_bz.tst
+TESTCASES += test_clamps.tst
+TESTCASES += test_fail.tst
+TESTCASES += test_interrupt.tst
+TESTCASES += test_loop.tst
+TESTCASES += test_max.tst
+TESTCASES += test_min.tst
+TESTCASES += test_mmu.tst
+TESTCASES += test_mul16.tst
+TESTCASES += test_mul32.tst
+TESTCASES += test_nsa.tst
+ifdef XT
+TESTCASES += test_pipeline.tst
+endif
+TESTCASES += test_quo.tst
+TESTCASES += test_rem.tst
+TESTCASES += test_rst0.tst
+TESTCASES += test_sar.tst
+TESTCASES += test_sext.tst
+TESTCASES += test_shift.tst
+TESTCASES += test_timer.tst
+TESTCASES += test_windowed.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/xtensa/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/xtensa/%.S
+	$(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT) Makefile
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(TESTCASES)
+
+check: $(addprefix run-, $(TESTCASES))
+
+run-%.tst: %.tst
+	$(SIM) $(SIMFLAGS) ./$<
+
+run-test_fail.tst: test_fail.tst
+	! $(SIM) $(SIMFLAGS) ./$<
+
+debug-%.tst: %.tst
+	$(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$<
+
+clean:
+	$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/xtensa/crt.S b/tests/xtensa/crt.S
new file mode 100644
index 0000000000..d9846acace
--- /dev/null
+++ b/tests/xtensa/crt.S
@@ -0,0 +1,24 @@
+.section .init
+    j       1f
+.section .init.text
+1:
+    movi    a2, _start
+    jx      a2
+
+.text
+.global _start
+_start:
+    movi    a2, 1
+    wsr     a2, windowstart
+    movi    a2, 0
+    wsr     a2, windowbase
+    movi    a1, _fstack
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+
+    call0   main
+
+    mov     a3, a2
+    movi    a2, 1
+    simcall
diff --git a/tests/xtensa/linker.ld b/tests/xtensa/linker.ld
new file mode 100644
index 0000000000..4d0b307fd2
--- /dev/null
+++ b/tests/xtensa/linker.ld
@@ -0,0 +1,112 @@
+OUTPUT_FORMAT("elf32-xtensa-le")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+	ram : ORIGIN = 0xd0000000, LENGTH = 0x08000000  /* 128M */
+	rom : ORIGIN = 0xfe000000, LENGTH = 0x00001000  /* 4k */
+}
+
+SECTIONS
+{
+    .init :
+    {
+        *(.init)
+		*(.init.*)
+    } > rom
+
+    .vector :
+    {
+    . = 0x00000000;
+        *(.vector.window_overflow_4)
+        *(.vector.window_overflow_4.*)
+    . = 0x00000040;
+        *(.vector.window_underflow_4)
+        *(.vector.window_underflow_4.*)
+    . = 0x00000080;
+        *(.vector.window_overflow_8)
+        *(.vector.window_overflow_8.*)
+    . = 0x000000c0;
+        *(.vector.window_underflow_8)
+        *(.vector.window_underflow_8.*)
+    . = 0x00000100;
+        *(.vector.window_overflow_12)
+        *(.vector.window_overflow_12.*)
+    . = 0x00000140;
+        *(.vector.window_underflow_12)
+        *(.vector.window_underflow_12.*)
+
+    . = 0x00000180;
+        *(.vector.level2)
+        *(.vector.level2.*)
+    . = 0x000001c0;
+        *(.vector.level3)
+        *(.vector.level3.*)
+    . = 0x00000200;
+        *(.vector.level4)
+        *(.vector.level4.*)
+    . = 0x00000240;
+        *(.vector.level5)
+        *(.vector.level5.*)
+    . = 0x00000280;
+        *(.vector.level6)
+        *(.vector.level6.*)
+    . = 0x000002c0;
+        *(.vector.level7)
+        *(.vector.level7.*)
+
+    . = 0x00000300;
+        *(.vector.kernel)
+        *(.vector.kernel.*)
+    . = 0x00000340;
+        *(.vector.user)
+        *(.vector.user.*)
+    . = 0x000003c0;
+        *(.vector.double)
+        *(.vector.double.*)
+    } > ram
+
+	.text :
+	{
+		_ftext = .;
+		*(.text .stub .text.* .gnu.linkonce.t.* .literal .literal.*)
+		_etext = .;
+	} > ram
+
+	.rodata :
+	{
+		. = ALIGN(4);
+		_frodata = .;
+		*(.rodata .rodata.* .gnu.linkonce.r.*)
+		*(.rodata1)
+		_erodata = .;
+	} > ram
+
+	.data :
+	{
+		. = ALIGN(4);
+		_fdata = .;
+		*(.data .data.* .gnu.linkonce.d.*)
+		*(.data1)
+		_gp = ALIGN(16);
+		*(.sdata .sdata.* .gnu.linkonce.s.*)
+		_edata = .;
+	} > ram
+
+	.bss :
+	{
+		. = ALIGN(4);
+		_fbss = .;
+		*(.dynsbss)
+		*(.sbss .sbss.* .gnu.linkonce.sb.*)
+		*(.scommon)
+		*(.dynbss)
+		*(.bss .bss.* .gnu.linkonce.b.*)
+		*(COMMON)
+		_ebss = .;
+		_end = .;
+	} > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
diff --git a/tests/xtensa/macros.inc b/tests/xtensa/macros.inc
new file mode 100644
index 0000000000..2d4515e14f
--- /dev/null
+++ b/tests/xtensa/macros.inc
@@ -0,0 +1,68 @@
+.macro test_suite name
+.data
+status: .word result
+result: .space 20
+.text
+.global main
+.align 4
+main:
+.endm
+
+.macro reset_ps
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+.endm
+
+.macro test_suite_end
+    reset_ps
+    movi    a0, status
+    l32i    a2, a0, 0
+    movi    a0, result
+    sub     a2, a2, a0
+    movi    a3, 0
+    loopnez a2, 1f
+    l8ui    a2, a0, 0
+    or      a3, a3, a2
+    addi    a0, a0, 1
+1:
+    exit
+.endm
+
+.macro test name
+.endm
+
+.macro test_end
+99:
+    reset_ps
+    movi    a2, status
+    l32i    a3, a2, 0
+    addi    a3, a3, 1
+    s32i    a3, a2, 0
+.endm
+
+.macro exit
+    movi    a2, 1
+    simcall
+.endm
+
+.macro test_fail
+    movi    a2, status
+    l32i    a2, a2, 0
+    movi    a3, 1
+    s8i     a3, a2, 0
+    j       99f
+.endm
+
+.macro assert cond, arg1, arg2
+    b\cond  \arg1, \arg2, 90f
+    test_fail
+90:
+    nop
+.endm
+
+.macro set_vector vector, addr
+    movi    a2, handler_\vector
+    movi    a3, \addr
+    s32i    a3, a2, 0
+.endm
diff --git a/tests/xtensa/test_b.S b/tests/xtensa/test_b.S
new file mode 100644
index 0000000000..6cbe5f1fca
--- /dev/null
+++ b/tests/xtensa/test_b.S
@@ -0,0 +1,221 @@
+.include "macros.inc"
+
+test_suite b
+
+test bnone
+    movi    a2, 0xa5a5ff00
+    movi    a3, 0x5a5a00ff
+    bnone   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff01
+    bnone   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test beq
+    movi    a2, 0
+    movi    a3, 0
+    beq     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beq     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blt
+    movi    a2, 6
+    movi    a3, 7
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blt     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltu
+    movi    a2, 6
+    movi    a3, 7
+    bltu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test ball
+    movi    a2, 0xa5a5ffa5
+    movi    a3, 0xa5a5ff00
+    ball    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5a5a5
+    ball    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbc
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbc     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbc     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbci
+    movi    a2, 0xfffdffff
+    bbci    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0x00020000
+    bbci    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bany
+    movi    a2, 0xa5a5ff01
+    movi    a3, 0x5a5a00ff
+    bany    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff00
+    bany    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bne
+    movi    a2, 1
+    movi    a3, 0
+    bne     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bne     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bge
+    movi    a2, 7
+    movi    a3, 7
+    bge     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeu
+    movi    a2, 7
+    movi    a3, 7
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnall
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0xa5a5ff00
+    bnall   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ffa5
+    bnall   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbs
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbs     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbs     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbsi
+    movi    a2, 0x00020000
+    bbsi    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0xfffdffff
+    bbsi    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bi.S b/tests/xtensa/test_bi.S
new file mode 100644
index 0000000000..6a5f1dffc9
--- /dev/null
+++ b/tests/xtensa/test_bi.S
@@ -0,0 +1,103 @@
+.include "macros.inc"
+
+test_suite bi
+
+test beqi
+    movi    a2, 7
+    beqi    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beqi    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnei
+    movi    a2, 1
+    bnei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bnei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blti
+    movi    a2, 6
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blti    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgei
+    movi    a2, 7
+    bgei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltui
+    movi    a2, 6
+    bltui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeui
+    movi    a2, 7
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_boolean.S b/tests/xtensa/test_boolean.S
new file mode 100644
index 0000000000..50e6d2c22a
--- /dev/null
+++ b/tests/xtensa/test_boolean.S
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+test_suite boolean
+
+test all4
+    movi    a2, 0xfec0
+    wsr     a2, br
+    all4    b0, b0
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b4
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b8
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b12
+    rsr     a3, br
+    addi    a2, a2, 1
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bz.S b/tests/xtensa/test_bz.S
new file mode 100644
index 0000000000..f9ba6e22e8
--- /dev/null
+++ b/tests/xtensa/test_bz.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+test_suite bz
+
+test beqz
+    movi    a2, 0
+    _beqz   a2, 1f
+    test_fail
+1:
+    movi    a2, 1
+    _beqz   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnez
+    movi    a2, 1
+    _bnez   a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    _bnez   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltz
+    movi    a2, 0xffffffff
+    bltz    a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bltz    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgez
+    movi    a2, 0
+    bgez    a2, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgez    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_clamps.S b/tests/xtensa/test_clamps.S
new file mode 100644
index 0000000000..c186cc98d8
--- /dev/null
+++ b/tests/xtensa/test_clamps.S
@@ -0,0 +1,42 @@
+.include "macros.inc"
+
+test_suite clamps
+
+test clamps
+    movi    a2, 0
+    movi    a3, 0
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x7f
+    movi    a3, 0x7f
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffff80
+    movi    a3, 0xffffff80
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x80
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0xffffff7f
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x7fffffff
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x80000000
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_fail.S b/tests/xtensa/test_fail.S
new file mode 100644
index 0000000000..e8d1b425bc
--- /dev/null
+++ b/tests/xtensa/test_fail.S
@@ -0,0 +1,9 @@
+.include "macros.inc"
+
+test_suite fail
+
+test fail
+    test_fail
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_interrupt.S b/tests/xtensa/test_interrupt.S
new file mode 100644
index 0000000000..68b3ee1492
--- /dev/null
+++ b/tests/xtensa/test_interrupt.S
@@ -0,0 +1,194 @@
+.include "macros.inc"
+
+test_suite interrupt
+
+.macro clear_interrupts
+    movi    a2, 0
+    wsr     a2, intenable
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+    esync
+    rsr     a2, interrupt
+    wsr     a2, intclear
+
+    esync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+.endm
+
+.macro check_l1
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    assert  eqi, a2, 0x10   /* only EXCM is set for level-1 interrupt */
+    rsr     a2, exccause
+    assert  eqi, a2, 4
+.endm
+
+test rsil
+    clear_interrupts
+
+    rsr     a2, ps
+    rsil    a3, 7
+    rsr     a4, ps
+    assert  eq, a2, a3
+    movi    a2, 0xf
+    and     a2, a4, a2
+    assert  eqi, a2, 7
+    xor     a3, a3, a4
+    movi    a2, 0xfffffff0
+    and     a2, a3, a2
+    assert  eqi, a2, 0
+test_end
+
+test soft_disabled
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intclear
+    esync
+    rsr     a3, interrupt
+    assert  eqi, a3, 0
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test soft_intenable
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    rsil    a3, 0
+    wsr     a2, intenable
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_rsil
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_waiti
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    waiti   0
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_user
+    set_vector kernel, 1f
+    set_vector user, 2f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+
+    rsr     a2, ps
+    movi    a3, 0x20
+    or      a2, a2, a3
+    wsr     a2, ps
+    waiti   0
+1:
+    test_fail
+2:
+    check_l1
+test_end
+
+test soft_priority
+    set_vector kernel, 1f
+    set_vector level3, 2f
+    clear_interrupts
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    wsr     a2, intset
+    esync
+1:
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    movi    a3, 0x13
+    assert  eq, a2, a3      /* EXCM and INTMASK are set
+                               for high-priority interrupt */
+test_end
+
+test eps_epc_rfi
+    set_vector level3, 3f
+    clear_interrupts
+    reset_ps
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    rsr     a3, ps
+    esync
+    wsr     a2, intset
+1:
+    esync
+2:
+    test_fail
+3:
+    rsr     a2, eps3
+    assert  eq, a2, a3
+    rsr     a2, epc3
+    movi    a3, 1b
+    assert  ge, a2, a3
+    movi    a3, 2b
+    assert  ge, a3, a2
+    movi    a2, 4f
+    wsr     a2, epc3
+    movi    a2, 0x40003
+    wsr     a2, eps3
+    rfi     3
+    test_fail
+4:
+    rsr     a2, ps
+    movi    a3, 0x40003
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_loop.S b/tests/xtensa/test_loop.S
new file mode 100644
index 0000000000..a5ea933913
--- /dev/null
+++ b/tests/xtensa/test_loop.S
@@ -0,0 +1,77 @@
+.include "macros.inc"
+
+test_suite loop
+
+test loop
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    assert  eqi, a2, 5
+test_end
+
+test loop0
+    movi    a2, 0
+    loop    a2, 1f
+    rsr     a2, lcount
+    assert  eqi, a2, -1
+    j       1f
+1:
+test_end
+
+test loop_jump
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    j       1f
+1:
+    assert  eqi, a2, 1
+test_end
+
+test loop_branch
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    beqi    a2, 3, 1f
+1:
+    assert  eqi, a2, 3
+test_end
+
+test loop_manual
+    movi    a2, 0
+    movi    a3, 5
+    movi    a4, 1f
+    movi    a5, 2f
+    wsr     a3, lcount
+    wsr     a4, lbeg
+    wsr     a5, lend
+    isync
+    j       1f
+.align 4
+1:
+    addi    a2, a2, 1
+2:
+    assert  eqi, a2, 6
+test_end
+
+test loop_excm
+    movi    a2, 0
+    movi    a3, 5
+    rsr     a4, ps
+    movi    a5, 0x10
+    or      a4, a4, a5
+    wsr     a4, ps
+    isync
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    xor     a4, a4, a5
+    isync
+    wsr     a4, ps
+    assert  eqi, a2, 1
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_max.S b/tests/xtensa/test_max.S
new file mode 100644
index 0000000000..2534c9d90b
--- /dev/null
+++ b/tests/xtensa/test_max.S
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite max
+
+test max
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test maxu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_min.S b/tests/xtensa/test_min.S
new file mode 100644
index 0000000000..6d9ddeb1ac
--- /dev/null
+++ b/tests/xtensa/test_min.S
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite min
+
+test min
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test minu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mmu.S b/tests/xtensa/test_mmu.S
new file mode 100644
index 0000000000..52d5774212
--- /dev/null
+++ b/tests/xtensa/test_mmu.S
@@ -0,0 +1,318 @@
+.include "macros.inc"
+
+test_suite mmu
+
+.purgem test
+
+.macro test name
+    movi    a2, 0x00000004
+    idtlb   a2
+    movi    a2, 0x00100004
+    idtlb   a2
+    movi    a2, 0x00200004
+    idtlb   a2
+    movi    a2, 0x00300004
+    idtlb   a2
+    movi    a2, 0x00000007
+    idtlb   a2
+.endm
+
+test tlb_group
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    witlb   a2, a3
+    movi    a3, 0x00200004
+    rdtlb0  a1, a3
+    ritlb0  a2, a3
+    movi    a3, 0x01000001
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    rdtlb1  a1, a3
+    ritlb1  a2, a3
+    movi    a3, 0x04000002
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x01234014
+    assert  eq, a1, a3
+    movi    a3, 0x0123400c
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    idtlb   a3
+    iitlb   a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x00000010
+    and     a1, a1, a3
+    assert  eqi, a1, 0
+    movi    a3, 0x00000008
+    and     a2, a2, a3
+    assert  eqi, a2, 0
+test_end
+
+test itlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    jx      a3
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 16
+    assert  eq, a2, a3
+test_end
+
+test dtlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    l8ui    a2, a3, 0
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 24
+    assert  eq, a2, a3
+test_end
+
+test itlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0xf0000004 /* VPN */
+    witlb   a2, a3
+    movi    a3, 0xf0000000
+    pitlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 17
+    assert  eq, a2, a3
+test_end
+
+test dtlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200007 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200000
+    pdtlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 25
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_privilege
+    set_vector kernel, 3f
+
+    movi    a2, 0x4004f
+    wsr     a2, ps
+1:
+    isync
+    nop
+2:
+    test_fail
+3:
+    movi    a1, 1b
+    rsr     a2, excvaddr
+    rsr     a3, epc1
+    assert  ge, a2, a1
+    assert  ge, a3, a1
+    movi    a1, 2b
+    assert  lt, a2, a1
+    assert  lt, a3, a1
+    rsr     a2, exccause
+    movi    a3, 18
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test load_store_privilege
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0x10
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200001
+    movi    a2, 0x4004f
+    jx      a1
+10:
+    wsr     a2, ps
+    isync
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    movi    a1, 0x000fffff
+    and     a3, a3, a1
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test cring_load_store_privilege
+    set_vector kernel, 0
+    set_vector double, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200004
+    movi    a2, 0x4005f    /* ring 1 + excm => cring == 0 */
+    wsr     a2, ps
+    isync
+    l8ui    a2, a3, 0      /* cring used */
+1:
+    l32e    a2, a3, -4     /* ring used */
+    test_fail
+2:
+    rsr     a2, excvaddr
+    addi    a2, a2, 4
+    assert  eq, a2, a3
+    rsr     a2, depc
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_prohibited
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0xfffff000
+    and     a2, a2, a1
+    movi    a1, 0x4
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+    jx      a1
+    .align  4
+10:
+    nop
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a1
+    rsr     a2, epc1
+    assert  eq, a2, a1
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+test_end
+
+test load_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200002
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+test_end
+
+test store_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000001 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200003
+    l8ui    a2, a3, 0
+1:
+    s8i     a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 29
+    assert  eq, a2, a3
+test_end
+
+test dtlb_autoload
+    set_vector kernel, 0
+
+    movi    a2, 0xd4000000
+    wsr     a2, ptevaddr
+    movi    a3, 0x00001013
+    s32i    a3, a2, 4
+    pdtlb   a2, a3
+    movi    a1, 0x10
+    and     a1, a1, a2
+    assert  eqi, a1, 0
+    l8ui    a1, a3, 0
+    pdtlb   a2, a3
+    movi    a1, 0xfffff010
+    and     a1, a1, a2
+    movi    a3, 0x00001010
+    assert  eq, a1, a3
+    movi    a1, 0xf
+    and     a1, a1, a2
+    assert  lti, a1, 4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul16.S b/tests/xtensa/test_mul16.S
new file mode 100644
index 0000000000..bf94376649
--- /dev/null
+++ b/tests/xtensa/test_mul16.S
@@ -0,0 +1,83 @@
+.include "macros.inc"
+
+test_suite mul16
+
+test mul16u_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x0c9d6bdb
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x9ff1e795
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf91e6bdb
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x031be795
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul32.S b/tests/xtensa/test_mul32.S
new file mode 100644
index 0000000000..fdaf57331b
--- /dev/null
+++ b/tests/xtensa/test_mul32.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+test_suite mul32
+
+test mull
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x5de480a6
+    mull    a5, a2, a4
+    assert  eq, a5, a6
+    mull    a2, a2, a4
+    assert  eq, a2, a6
+    mull    a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+/* unfortunately dc232b doesn't have muluh/mulsh*/
+
+test_suite_end
diff --git a/tests/xtensa/test_nsa.S b/tests/xtensa/test_nsa.S
new file mode 100644
index 0000000000..a5fe5debe4
--- /dev/null
+++ b/tests/xtensa/test_nsa.S
@@ -0,0 +1,59 @@
+.include "macros.inc"
+
+test_suite nsa
+
+test nsa
+    movi    a2, 0
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0xfffffffe
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+test_end
+
+test nsau
+    movi    a2, 0
+    movi    a3, 32
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 0
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 31
+    nsau    a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 1
+    nsau    a2, a2
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_pipeline.S b/tests/xtensa/test_pipeline.S
new file mode 100644
index 0000000000..6be6085fc3
--- /dev/null
+++ b/tests/xtensa/test_pipeline.S
@@ -0,0 +1,157 @@
+.include "macros.inc"
+
+.purgem test
+.macro test name
+    movi    a2, 1f
+    movi    a3, 99f
+0:
+    ipf     a2, 0
+    ipf     a2, 4
+    ipf     a2, 8
+    ipf     a2, 12
+    addi    a2, a2, 16
+    blt     a2, a3, 0b
+    j       1f
+    .align 4
+1:
+.endm
+
+test_suite pipeline
+
+test register_no_stall
+    rsr     a3, ccount
+    add     a5, a6, a6
+    add     a6, a5, a5
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 3
+test_end
+
+test register_stall
+    l32i    a5, a1, 0   /* data cache preload */
+    nop
+    rsr     a3, ccount
+    l32i    a5, a1, 0
+    add     a6, a5, a5  /* M-to-E interlock */
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j0_stall
+    rsr     a3, ccount
+    j       1f          /* E + 2-cycle penalty */
+1:
+    rsr     a4, ccount  /* E */
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j1_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j5_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b_no_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 2, 1f
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 2
+1:
+test_end
+
+test b1_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b5_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+/* PS *SYNC */
+
+test ps_dsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    dsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_esync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    esync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_rsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    rsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_isync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    isync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    movi    a4, 9
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_quo.S b/tests/xtensa/test_quo.S
new file mode 100644
index 0000000000..12debf1fe0
--- /dev/null
+++ b/tests/xtensa/test_quo.S
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite quo
+
+test quou_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x8
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x1
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quou    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test quos_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xfffffffc
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0xfffffff6
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0x80000000
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test quos_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quos    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rem.S b/tests/xtensa/test_rem.S
new file mode 100644
index 0000000000..bb0d5fe202
--- /dev/null
+++ b/tests/xtensa/test_rem.S
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite rem
+
+test remu_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x9aa40af
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x5a5a137f
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x518c46db
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    remu    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test rems_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xf3a27ce7
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x02479b03
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf7315a5a
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test rems_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    rems    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rst0.S b/tests/xtensa/test_rst0.S
new file mode 100644
index 0000000000..3eda565e8a
--- /dev/null
+++ b/tests/xtensa/test_rst0.S
@@ -0,0 +1,148 @@
+.include "macros.inc"
+
+test_suite rst0
+
+test and
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x01250125
+    and     a5, a2, a4
+    assert  eq, a5, a6
+    and     a2, a2, a4
+    assert  eq, a2, a6
+    and     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test or
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb7ffb7ff
+    or      a5, a2, a4
+    assert  eq, a5, a6
+    or      a2, a2, a4
+    assert  eq, a2, a6
+    or      a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test xor
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb6dab6da
+    xor     a5, a2, a4
+    assert  eq, a5, a6
+    xor     a2, a2, a4
+    assert  eq, a2, a6
+    xor     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test add
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb924b924
+    add     a5, a2, a4
+    assert  eq, a5, a6
+    add     a2, a2, a4
+    assert  eq, a2, a6
+    add     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xcca45ec9
+    addx2   a5, a2, a4
+    assert  eq, a5, a6
+    addx2   a2, a2, a4
+    assert  eq, a2, a6
+    addx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf3a3aa13
+    addx4   a5, a2, a4
+    assert  eq, a5, a6
+    addx4   a2, a2, a4
+    assert  eq, a2, a6
+    addx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x41a240a7
+    addx8   a5, a2, a4
+    assert  eq, a5, a6
+    addx8   a2, a2, a4
+    assert  eq, a2, a6
+    addx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test sub
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x6dda9226
+    sub     a5, a2, a4
+    assert  eq, a5, a6
+    sub     a2, a2, a4
+    assert  eq, a2, a6
+    sub     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x815a37cb
+    subx2   a5, a2, a4
+    assert  eq, a5, a6
+    subx2   a2, a2, a4
+    assert  eq, a2, a6
+    subx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xa8598315
+    subx4   a5, a2, a4
+    assert  eq, a5, a6
+    subx4   a2, a2, a4
+    assert  eq, a2, a6
+    subx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf65819a9
+    subx8   a5, a2, a4
+    assert  eq, a5, a6
+    subx8   a2, a2, a4
+    assert  eq, a2, a6
+    subx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sar.S b/tests/xtensa/test_sar.S
new file mode 100644
index 0000000000..40c649ffb8
--- /dev/null
+++ b/tests/xtensa/test_sar.S
@@ -0,0 +1,111 @@
+.include "macros.inc"
+
+test_suite sar
+
+.macro test_sar prefix, imm
+    \prefix\()_set \imm
+    \prefix\()_ver \imm
+.endm
+
+.macro tests_sar prefix
+    test_sar \prefix, 0
+    test_sar \prefix, 1
+    test_sar \prefix, 2
+    test_sar \prefix, 3
+    test_sar \prefix, 0x1f
+    test_sar \prefix, 0x20
+    test_sar \prefix, 0x3f
+    test_sar \prefix, 0x40
+    test_sar \prefix, 0xfffffffe
+.endm
+
+.macro sar_set imm
+    movi    a2, \imm
+    wsr     a2, sar
+.endm
+
+.macro sar_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x3f
+    assert  eq, a2, a3
+.endm
+
+test sar
+    tests_sar sar
+test_end
+
+.macro ssr_set imm
+    movi    a2, \imm
+    ssr     a2
+.endm
+
+.macro ssr_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssr
+    tests_sar ssr
+test_end
+
+.macro ssl_set imm
+    movi    a2, \imm
+    ssl     a2
+.endm
+
+.macro ssl_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - (\imm & 0x1f)
+    assert  eq, a2, a3
+.endm
+
+test ssl
+    tests_sar ssl
+test_end
+
+.macro ssa8l_set imm
+    movi    a2, \imm
+    ssa8l   a2
+.endm
+
+.macro ssa8l_ver imm
+    rsr     a3, sar
+    movi    a2, (\imm & 0x3) << 3
+    assert  eq, a2, a3
+.endm
+
+test ssa8l
+    tests_sar ssa8l
+test_end
+
+.macro ssa8b_set imm
+    movi    a2, \imm
+    ssa8b   a2
+.endm
+
+.macro ssa8b_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - ((\imm & 0x3) << 3)
+    assert  eq, a2, a3
+.endm
+
+test ssa8b
+    tests_sar ssa8b
+test_end
+
+.macro ssai_set imm
+    ssai    \imm & 0x1f
+.endm
+
+.macro ssai_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssai
+    tests_sar ssai
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sext.S b/tests/xtensa/test_sext.S
new file mode 100644
index 0000000000..04dc6500c1
--- /dev/null
+++ b/tests/xtensa/test_sext.S
@@ -0,0 +1,69 @@
+.include "macros.inc"
+
+test_suite sext
+
+test sext
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xfffffaa5
+    movi    a3, 0x000000a5
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000055a
+    movi    a3, 0xffffff5a
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0xffff5a5a
+    movi    a3, 0x00005a5a
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000a5a5
+    movi    a3, 0xffffa5a5
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x00055a5a
+    movi    a3, 0xffff5a5a
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x000aa5a5
+    movi    a3, 0x0000a5a5
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x005a5a5a
+    movi    a3, 0xffda5a5a
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+
+    movi    a2, 0xffa5a5a5
+    movi    a3, 0x0025a5a5
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+test_end
+
+test sext_same_rs
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_shift.S b/tests/xtensa/test_shift.S
new file mode 100644
index 0000000000..a8e43645b7
--- /dev/null
+++ b/tests/xtensa/test_shift.S
@@ -0,0 +1,206 @@
+.include "macros.inc"
+
+test_suite shift
+
+.macro test_shift prefix, dst, src, v, imm
+    \prefix\()_set \dst, \src, \v, \imm
+    \prefix\()_ver \dst, \v, \imm
+.endm
+
+.macro test_shift_sd prefix, v, imm
+    test_shift \prefix, a3, a2, \v, \imm
+    test_shift \prefix, a2, a2, \v, \imm
+.endm
+
+.macro tests_imm_shift prefix, v
+    test_shift_sd \prefix, \v, 1
+    test_shift_sd \prefix, \v, 2
+    test_shift_sd \prefix, \v, 7
+    test_shift_sd \prefix, \v, 8
+    test_shift_sd \prefix, \v, 15
+    test_shift_sd \prefix, \v, 16
+    test_shift_sd \prefix, \v, 31
+.endm
+
+.macro tests_shift prefix, v
+    test_shift_sd \prefix, \v, 0
+    tests_imm_shift \prefix, \v
+    test_shift_sd \prefix, \v, 32
+.endm
+
+
+.macro slli_set dst, src, v, imm
+    movi    \src, \v
+    slli    \dst, \src, \imm
+.endm
+
+.macro slli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) << (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test slli
+    tests_imm_shift slli, 0xa3c51249
+test_end
+
+
+.macro srai_set dst, src, v, imm
+    movi    \src, \v
+    srai    \dst, \src, \imm
+.endm
+
+.macro srai_ver dst, v, imm
+    mov     a2, \dst
+    .if (\imm)
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff) | \
+                ~((((\v) & 0x80000000) >> ((\imm) - 1)) - 1)
+    .else
+    movi    a3, \v
+    .endif
+    assert  eq, a2, a3
+.endm
+
+test srai
+    tests_imm_shift srai, 0x49a3c512
+    tests_imm_shift srai, 0xa3c51249
+test_end
+
+
+.macro srli_set dst, src, v, imm
+    movi    \src, \v
+    srli    \dst, \src, \imm
+.endm
+
+.macro srli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff)
+    assert  eq, a2, a3
+.endm
+
+test srli
+    tests_imm_shift srli, 0x49a3c512
+    tests_imm_shift srli, 0xa3c51249
+test_end
+
+
+.macro sll_set dst, src, v, imm
+    movi    a2, \imm
+    ssl     a2
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_sar_set dst, src, v, imm
+    movi    a2, 32 - \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_ver dst, v, imm
+    slli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sll_sar_ver dst, v, imm
+    slli_ver \dst, \v, \imm
+.endm
+
+test sll
+    tests_shift sll, 0xa3c51249
+    tests_shift sll_sar, 0xa3c51249
+test_end
+
+
+.macro srl_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_ver dst, v, imm
+    srli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro srl_sar_ver dst, v, imm
+    srli_ver \dst, \v, \imm
+.endm
+
+test srl
+    tests_shift srl, 0xa3c51249
+    tests_shift srl_sar, 0xa3c51249
+    tests_shift srl, 0x49a3c512
+    tests_shift srl_sar, 0x49a3c512
+test_end
+
+
+.macro sra_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_ver dst, v, imm
+    srai_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sra_sar_ver dst, v, imm
+    srai_ver \dst, \v, \imm
+.endm
+
+test sra
+    tests_shift sra, 0xa3c51249
+    tests_shift sra_sar, 0xa3c51249
+    tests_shift sra, 0x49a3c512
+    tests_shift sra_sar, 0x49a3c512
+test_end
+
+
+.macro src_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_ver dst, v, imm
+    src_sar_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro src_sar_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) >> (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test src
+    tests_shift src, 0xa3c51249215c3a94
+    tests_shift src_sar, 0xa3c51249215c3a94
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S
new file mode 100644
index 0000000000..ede63955cc
--- /dev/null
+++ b/tests/xtensa/test_timer.S
@@ -0,0 +1,115 @@
+.include "macros.inc"
+
+test_suite timer
+
+test ccount
+    rsr     a3, ccount
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 1
+test_end
+
+test ccompare
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    loop    a3, 1f
+    rsr     a3, interrupt
+    bnez    a3, 2f
+1:
+    test_fail
+2:
+test_end
+
+test ccompare0_interrupt
+    set_vector kernel, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+
+    movi    a2, 0x40
+    wsr     a2, intenable
+    rsil    a2, 0
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
+test_end
+
+test ccompare1_interrupt
+    set_vector level3, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare0
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare1
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x400
+    wsr     a2, intenable
+    rsil    a2, 2
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test ccompare2_interrupt
+    set_vector level5, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare2
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x2000
+    wsr     a2, intenable
+    rsil    a2, 4
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_windowed.S b/tests/xtensa/test_windowed.S
new file mode 100644
index 0000000000..cb2d39e1fd
--- /dev/null
+++ b/tests/xtensa/test_windowed.S
@@ -0,0 +1,302 @@
+.include "macros.inc"
+
+test_suite windowed
+
+.altmacro
+
+.macro reset_window start
+    movi    a2, 0xff
+    wsr     a2, windowstart
+    rsync
+    movi    a2, 0
+    wsr     a2, windowbase
+    rsync
+    movi    a2, \start
+    wsr     a2, windowstart
+    rsync
+.endm
+
+.macro overflow_test shift, window, probe_ok, probe_ex
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    movi    a2, 1 | (((1 << ((\window) / 4)) | 1) << ((\shift) / 4))
+    wsr     a2, windowstart
+    reset_ps
+
+    mov     a2, a\probe_ok
+    set_vector window_overflow_\window, 10f
+1:
+    mov     a2, a\probe_ex
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, windowbase
+    movi    a3, (\shift) / 4
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rfwo
+    test_fail
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    movi    a3, 1 | ((1 << ((\window) / 4)) << ((\shift) / 4))
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+.endm
+
+.macro overflow_tests shift, window, probe
+    .if \probe < 15
+    overflow_test \shift, \window, %((\shift) - 1), \probe
+    overflow_tests \shift, \window, %((\probe) + 1)
+    .endif
+.endm
+
+.macro all_overflow_tests
+    .irp shift, 4, 8, 12
+    .irp window, 4, 8, 12
+    overflow_tests \shift, \window, \shift
+    .endr
+    .endr
+.endm
+
+test overflow
+    all_overflow_tests
+test_end
+
+
+.macro underflow_test window
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    set_vector window_underflow_\window, 10f
+
+    reset_window 1
+    reset_ps
+
+    ssai    2
+    movi    a2, 2f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+1:
+    retw
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  eqi, a2, 1
+    rfwu
+2:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    assert  bsi, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test underflow
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    underflow_test 4
+    underflow_test 8
+    underflow_test 12
+test_end
+
+
+.macro retw_test window
+    reset_window %(1 | (1 << (8 - (\window) / 4)))
+    reset_ps
+
+    ssai    2
+    movi    a2, 1f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+    retw
+    test_fail
+1:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  bci, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test retw
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    retw_test 4
+    retw_test 8
+    retw_test 12
+test_end
+
+test movsp
+    set_vector kernel, 2f
+
+    reset_window 1
+    reset_ps
+1:
+    movsp   a2, a3
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 5
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+
+    set_vector kernel, 0
+
+    reset_window 0x81
+    reset_ps
+
+    movsp   a2, a3
+test_end
+
+test rotw
+    reset_window 0x4b
+    reset_ps
+
+    movi    a3, 0x10
+
+    rotw    1
+    rsr     a2, windowbase
+    assert  eqi, a2, 1
+    movi    a3, 0x11
+    movi    a7, 0x12
+
+    rotw    2
+    rsr     a2, windowbase
+    assert  eqi, a2, 3
+    movi    a3, 0x13
+    movi    a7, 0x14
+    movi    a11, 0x15
+
+    rotw    3
+    rsr     a2, windowbase
+    assert  eqi, a2, 6
+    movi    a3, 0x16
+    movi    a7, 0x17
+
+    movi    a2, 0x44
+    wsr     a2, windowstart
+    rsync
+
+    movi    a2, 0x10
+    assert  eq, a2, a11
+    movi    a11, 0x18
+    movi    a2, 0x11
+    assert  eq, a2, a15
+    movi    a15, 0x19
+
+    rotw    4
+    movi    a2, 0x12
+    assert  eq, a2, a3
+    movi    a2, 0x13
+    assert  eq, a2, a7
+    movi    a2, 0x14
+    assert  eq, a2, a11
+    movi    a2, 0x15
+    assert  eq, a2, a15
+
+    movi    a2, 0x5
+    wsr     a2, windowstart
+    rsync
+
+    rotw    -2
+    movi    a2, 0x18
+    assert  eq, a2, a3
+    movi    a2, 0x19
+    assert  eq, a2, a7
+test_end
+
+.macro callw_test window
+    call\window 2f
+1:
+    test_fail
+    .align  4
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, ps
+    movi    a3, 0x4000f | ((\window) << 14)
+    assert  eq, a2, a3
+    movi    a2, 1b
+    slli    a2, a2, 2
+    ssai    2
+    movi    a3, (\window) / 4
+    src     a2, a3, a2
+    assert  eq, a2, a\window
+.endm
+
+test callw
+    reset_window 0x1
+    reset_ps
+
+    callw_test 4
+    callw_test 8
+    callw_test 12
+test_end
+
+
+.macro entry_test window
+    reset_window 0x1
+    reset_ps
+    movi    a2, 0x4000f | ((\window) << 14)
+    wsr     a2, ps
+    isync
+    movi    a3, 0x12345678
+    j       1f
+    .align  4
+1:
+    entry   a3, 0x5678
+    movi    a2, 0x12340000
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, (\window) / 4
+    rsr     a2, windowstart
+    movi    a3, 1 | (1 << ((\window) / 4))
+    assert  eq, a2, a3
+    rotw    -(\window) / 4
+.endm
+
+test entry
+    entry_test 4
+    entry_test 8
+    entry_test 12
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/vectors.S b/tests/xtensa/vectors.S
new file mode 100644
index 0000000000..265a181239
--- /dev/null
+++ b/tests/xtensa/vectors.S
@@ -0,0 +1,39 @@
+.macro vector name
+
+.section .vector.\name
+    j       1f
+.section .vector.\name\().text
+1:
+    wsr     a2, excsave1
+    movi    a2, handler_\name
+    l32i    a2, a2, 0
+    beqz    a2, 1f
+    jx      a2
+1:
+    movi    a3, 1b
+    movi    a2, 1
+    simcall
+
+.align 4
+.global handler_\name
+handler_\name\(): .word 0
+
+.endm
+
+vector window_overflow_4
+vector window_overflow_8
+vector window_overflow_12
+vector window_underflow_4
+vector window_underflow_8
+vector window_underflow_12
+
+vector level2
+vector level3
+vector level4
+vector level5
+vector level6
+vector level7
+
+vector kernel
+vector user
+vector double
diff --git a/trace-events b/trace-events
index 3fdd60faa4..8bed3bea7a 100644
--- a/trace-events
+++ b/trace-events
@@ -62,7 +62,7 @@ bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
 bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
-bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
+bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_io(int is_write, void *acb) "is_write %d acb %p"
@@ -450,6 +450,13 @@ milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
 milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
 milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
 
+# hw/mipsnet.c
+mipsnet_send(uint32_t size) "sending len=%u"
+mipsnet_receive(uint32_t size) "receiving len=%u"
+mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x"
+mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64
+mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)"
+
 # xen-all.c
 xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx"
 xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i"
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 2e2456e3ac..ffbd1725a4 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -283,13 +283,57 @@ int vnc_tls_validate_certificate(struct VncState *vs)
     return 0;
 }
 
+#if defined(GNUTLS_VERSION_NUMBER) && \
+    GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
+    int rc;
+
+    rc = gnutls_priority_set_direct(s, priority, NULL);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#else
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocols[] = {
+        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
+    };
+    static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
+    static const int kx_x509[] = {
+        GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
+        GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
+    };
+    int rc;
+
+    rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_certificate_type_set_priority(s, cert_types);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_protocol_set_priority(s, protocols);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#endif
 
 int vnc_tls_client_setup(struct VncState *vs,
                          int needX509Creds) {
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
 
     VNC_DEBUG("Do TLS setup\n");
     if (vnc_tls_initialize() < 0) {
@@ -310,21 +354,7 @@ int vnc_tls_client_setup(struct VncState *vs,
             return -1;
         }
 
-        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
+        if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
             gnutls_deinit(vs->tls.session);
             vs->tls.session = NULL;
             vnc_client_error(vs);
diff --git a/vl.c b/vl.c
index 5ba9b35860..b773d2f126 100644
--- a/vl.c
+++ b/vl.c
@@ -2200,6 +2200,7 @@ int main(int argc, char **argv, char **envp)
     error_set_progname(argv[0]);
 
     g_mem_set_vtable(&mem_trace);
+    g_thread_init(NULL);
 
     init_clocks();
 
@@ -3061,7 +3062,7 @@ int main(int argc, char **argv, char **envp)
     if (!data_dir) {
         data_dir = os_find_datadir(argv[0]);
     }
-    /* If all else fails use the install patch specified when building.  */
+    /* If all else fails use the install path specified when building. */
     if (!data_dir) {
         data_dir = CONFIG_QEMU_DATADIR;
     }
diff --git a/xen-all.c b/xen-all.c
index 84420d83a9..1bc2c3c8de 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -620,7 +620,7 @@ static void cpu_ioreq_move(ioreq_t *req)
             }
         }
     } else {
-        target_ulong tmp;
+        uint64_t tmp;
 
         if (req->dir == IOREQ_READ) {
             for (i = 0; i < req->count; i++) {
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 5b247ee092..7bcb86e4f8 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -40,6 +40,13 @@
 #endif
 #define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
 
+/* This is the size of the virtual address space reserve to QEMU that will not
+ * be use by MapCache.
+ * From empirical tests I observed that qemu use 75MB more than the
+ * max_mcache_size.
+ */
+#define NON_MCACHE_MEMORY_SIZE (80 * 1024 * 1024)
+
 #define mapcache_lock()   ((void)0)
 #define mapcache_unlock() ((void)0)
 
@@ -92,15 +99,27 @@ void xen_map_cache_init(void)
     QTAILQ_INIT(&mapcache->locked_entries);
     mapcache->last_address_index = -1;
 
-    getrlimit(RLIMIT_AS, &rlimit_as);
-    if (rlimit_as.rlim_max < MCACHE_MAX_SIZE) {
-        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+    if (geteuid() == 0) {
+        rlimit_as.rlim_cur = RLIM_INFINITY;
+        rlimit_as.rlim_max = RLIM_INFINITY;
+        mapcache->max_mcache_size = MCACHE_MAX_SIZE;
     } else {
-        rlimit_as.rlim_cur = MCACHE_MAX_SIZE;
+        getrlimit(RLIMIT_AS, &rlimit_as);
+        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+
+        if (rlimit_as.rlim_max != RLIM_INFINITY) {
+            fprintf(stderr, "Warning: QEMU's maximum size of virtual"
+                    " memory is not infinity.\n");
+        }
+        if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
+            mapcache->max_mcache_size = rlimit_as.rlim_max -
+                NON_MCACHE_MEMORY_SIZE;
+        } else {
+            mapcache->max_mcache_size = MCACHE_MAX_SIZE;
+        }
     }
 
     setrlimit(RLIMIT_AS, &rlimit_as);
-    mapcache->max_mcache_size = rlimit_as.rlim_cur;
 
     mapcache->nr_buckets =
         (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
diff --git a/xtensa-semi.c b/xtensa-semi.c
new file mode 100644
index 0000000000..ba0e828b32
--- /dev/null
+++ b/xtensa-semi.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helpers.h"
+#include "qemu-log.h"
+
+enum {
+    TARGET_SYS_exit = 1,
+    TARGET_SYS_read = 3,
+    TARGET_SYS_write = 4,
+    TARGET_SYS_open = 5,
+    TARGET_SYS_close = 6,
+    TARGET_SYS_lseek = 19,
+    TARGET_SYS_select_one = 29,
+
+    TARGET_SYS_argc = 1000,
+    TARGET_SYS_argv_sz = 1001,
+    TARGET_SYS_argv = 1002,
+    TARGET_SYS_memset = 1004,
+};
+
+enum {
+    SELECT_ONE_READ   = 1,
+    SELECT_ONE_WRITE  = 2,
+    SELECT_ONE_EXCEPT = 3,
+};
+
+void HELPER(simcall)(CPUState *env)
+{
+    uint32_t *regs = env->regs;
+
+    switch (regs[2]) {
+    case TARGET_SYS_exit:
+        qemu_log("exit(%d) simcall\n", regs[3]);
+        exit(regs[3]);
+        break;
+
+    case TARGET_SYS_read:
+    case TARGET_SYS_write:
+        {
+            bool is_write = regs[2] == TARGET_SYS_write;
+            uint32_t fd = regs[3];
+            uint32_t vaddr = regs[4];
+            uint32_t len = regs[5];
+
+            while (len > 0) {
+                target_phys_addr_t paddr =
+                    cpu_get_phys_page_debug(env, vaddr);
+                uint32_t page_left =
+                    TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
+                uint32_t io_sz = page_left < len ? page_left : len;
+                target_phys_addr_t sz = io_sz;
+                void *buf = cpu_physical_memory_map(paddr, &sz, is_write);
+
+                if (buf) {
+                    vaddr += io_sz;
+                    len -= io_sz;
+                    regs[2] = is_write ?
+                        write(fd, buf, io_sz) :
+                        read(fd, buf, io_sz);
+                    regs[3] = errno;
+                    cpu_physical_memory_unmap(buf, sz, is_write, sz);
+                    if (regs[2] == -1) {
+                        break;
+                    }
+                } else {
+                    regs[2] = -1;
+                    regs[3] = EINVAL;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case TARGET_SYS_open:
+        {
+            char name[1024];
+            int rc;
+            int i;
+
+            for (i = 0; i < ARRAY_SIZE(name); ++i) {
+                rc = cpu_memory_rw_debug(
+                        env, regs[3] + i, (uint8_t *)name + i, 1, 0);
+                if (rc != 0 || name[i] == 0) {
+                    break;
+                }
+            }
+
+            if (rc == 0 && i < ARRAY_SIZE(name)) {
+                regs[2] = open(name, regs[4], regs[5]);
+                regs[3] = errno;
+            } else {
+                regs[2] = -1;
+                regs[3] = EINVAL;
+            }
+        }
+        break;
+
+    case TARGET_SYS_close:
+        if (regs[3] < 3) {
+            regs[2] = regs[3] = 0;
+        } else {
+            regs[2] = close(regs[3]);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_lseek:
+        regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
+        regs[3] = errno;
+        break;
+
+    case TARGET_SYS_select_one:
+        {
+            uint32_t fd = regs[3];
+            uint32_t rq = regs[4];
+            uint32_t target_tv = regs[5];
+            uint32_t target_tvv[2];
+
+            struct timeval tv = {0};
+            fd_set fdset;
+
+            FD_ZERO(&fdset);
+            FD_SET(fd, &fdset);
+
+            if (target_tv) {
+                cpu_memory_rw_debug(env, target_tv,
+                        (uint8_t *)target_tvv, sizeof(target_tvv), 0);
+                tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
+                tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
+            }
+            regs[2] = select(fd + 1,
+                    rq == SELECT_ONE_READ   ? &fdset : NULL,
+                    rq == SELECT_ONE_WRITE  ? &fdset : NULL,
+                    rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
+                    target_tv ? &tv : NULL);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_argc:
+        regs[2] = 1;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv_sz:
+        regs[2] = 128;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv:
+        {
+            struct Argv {
+                uint32_t argptr[2];
+                char text[120];
+            } argv = {
+                {0, 0},
+                "test"
+            };
+
+            argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text));
+            cpu_memory_rw_debug(
+                    env, regs[3], (uint8_t *)&argv, sizeof(argv), 1);
+        }
+        break;
+
+    case TARGET_SYS_memset:
+        {
+            uint32_t base = regs[3];
+            uint32_t sz = regs[5];
+
+            while (sz) {
+                target_phys_addr_t len = sz;
+                void *buf = cpu_physical_memory_map(base, &len, 1);
+
+                if (buf && len) {
+                    memset(buf, regs[4], len);
+                    cpu_physical_memory_unmap(buf, len, 1, len);
+                } else {
+                    len = 1;
+                }
+                base += len;
+                sz -= len;
+            }
+            regs[2] = regs[3];
+            regs[3] = 0;
+        }
+        break;
+
+    default:
+        qemu_log("%s(%d): not implemented\n", __func__, regs[2]);
+        break;
+    }
+}