From 8e6c05cfd6e830b218490afde59ccaeee35ea2cf Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Mon, 19 Apr 2010 17:25:47 +0200
Subject: [PATCH] WIP

---
 sys/emulation/Makefile             |   11 +-
 sys/emulation/x86bios/Makefile     |   10 +
 sys/emulation/x86bios/x86bios.c    |  647 +++
 sys/emulation/x86bios/x86bios.h    |  156 +
 sys/emulation/x86emu/x86emu.c      | 8395 ++++++++++++++++++++++++++++++++++++
 sys/emulation/x86emu/x86emu.h      |  184 +
 sys/emulation/x86emu/x86emu_regs.h |  170 +
 7 files changed, 9567 insertions(+), 6 deletions(-)
 create mode 100644 sys/emulation/x86bios/Makefile
 create mode 100644 sys/emulation/x86bios/x86bios.c
 create mode 100644 sys/emulation/x86bios/x86bios.h
 create mode 100644 sys/emulation/x86emu/x86emu.c
 create mode 100644 sys/emulation/x86emu/x86emu.h
 create mode 100644 sys/emulation/x86emu/x86emu_regs.h

diff --git a/sys/emulation/Makefile b/sys/emulation/Makefile
index 1f83f33..f4d95e8 100644
--- a/sys/emulation/Makefile
+++ b/sys/emulation/Makefile
@@ -1,15 +1,14 @@
 # $DragonFly: src/sys/emulation/Makefile,v 1.4 2008/07/23 16:39:34 dillon Exp $
 #
+# needs to be ported to new net80211 stack
+# SUBDIR= ndis
+
+SUBDIR=	x86bios
 
 .if ${MACHINE_ARCH} == i386
 SUBDIR=linux
-.elif ${MACHINE_ARCH} == x86_64
-SUBDIR=
-.else
+.elif ${MACHINE_ARCH} != x86_64
 .error Unknown MACHINE_ARCH.
 .endif
 
-# needs to be ported to new net80211 stack
-# SUBDIR= ndis
-
 .include <bsd.subdir.mk>
diff --git a/sys/emulation/x86bios/Makefile b/sys/emulation/x86bios/Makefile
new file mode 100644
index 0000000..e38d824
--- /dev/null
+++ b/sys/emulation/x86bios/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD: src/sys/modules/x86bios/Makefile,v 1.3 2009/10/19 20:58:10 jkim Exp $
+
+KMOD=	x86bios
+SRCS=	opt_x86bios.h
+SRCS+=	bus_if.h device_if.h pci_if.h
+
+.PATH:	${.CURDIR}/../x86emu
+SRCS+=	x86bios.c x86emu.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/emulation/x86bios/x86bios.c b/sys/emulation/x86bios/x86bios.c
new file mode 100644
index 0000000..7c5459f
--- /dev/null
+++ b/sys/emulation/x86bios/x86bios.c
@@ -0,0 +1,647 @@
+/*-
+ * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
+ * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD: src/sys/compat/x86bios/x86bios.c,v 1.15 2010/03/25 17:14:47 jkim Exp $
+ */
+
+#include "opt_x86bios.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/spinlock.h>
+#include <sys/sysctl.h>
+
+#include <emulation/x86emu/x86emu.h>
+#include <emulation/x86emu/x86emu_regs.h>
+#include <emulation/x86bios/x86bios.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+
+#include <machine/cpufunc.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#define	X86BIOS_PAGE_SIZE	0x00001000	/* 4K */
+
+#define	X86BIOS_IVT_SIZE	0x00000500	/* 1K + 256 (BDA) */
+#define	X86BIOS_SEG_SIZE	0x00010000	/* 64K */
+#define	X86BIOS_MEM_SIZE	0x00100000	/* 1M */
+
+#define	X86BIOS_IVT_BASE	0x00000000
+#define	X86BIOS_RAM_BASE	0x00001000
+#define	X86BIOS_ROM_BASE	0x000a0000
+
+#define	X86BIOS_ROM_SIZE	(X86BIOS_MEM_SIZE - (uint32_t)x86bios_rom_phys)
+
+#define	X86BIOS_PAGES		(X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE)
+
+#define	X86BIOS_R_DS		_pad1
+#define	X86BIOS_R_SS		_pad2
+
+static struct x86emu x86bios_emu;
+
+static struct lock x86bios_lock;
+
+static void *x86bios_ivt;
+static void *x86bios_rom;
+static void *x86bios_seg;
+
+static vm_offset_t *x86bios_map;
+
+static vm_paddr_t x86bios_rom_phys;
+static vm_paddr_t x86bios_seg_phys;
+
+static int x86bios_fault;
+static uint32_t x86bios_fault_addr;
+static uint16_t x86bios_fault_cs;
+static uint16_t x86bios_fault_ip;
+
+SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD, NULL, "x86bios debugging");
+static int x86bios_trace_call;
+TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call);
+SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0,
+    "Trace far function calls");
+static int x86bios_trace_int;
+TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int);
+SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &x86bios_trace_int, 0,
+    "Trace software interrupt handlers");
+
+static void
+x86bios_set_fault(struct x86emu *emu, uint32_t addr)
+{
+
+	x86bios_fault = 1;
+	x86bios_fault_addr = addr;
+	x86bios_fault_cs = emu->x86.R_CS;
+	x86bios_fault_ip = emu->x86.R_IP;
+	x86emu_halt_sys(emu);
+}
+
+static void *
+x86bios_get_pages(uint32_t offset, size_t size)
+{
+	vm_offset_t page;
+
+	if (offset + size > X86BIOS_MEM_SIZE + X86BIOS_IVT_SIZE)
+		return (NULL);
+
+	if (offset >= X86BIOS_MEM_SIZE)
+		offset -= X86BIOS_MEM_SIZE;
+	page = x86bios_map[offset / X86BIOS_PAGE_SIZE];
+	if (page != 0)
+		return ((void *)(page + offset % X86BIOS_PAGE_SIZE));
+
+	return (NULL);
+}
+
+static void
+x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size)
+{
+	int i, j;
+
+	for (i = pa / X86BIOS_PAGE_SIZE, j = 0;
+	    j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++)
+		x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE;
+}
+
+static uint8_t
+x86bios_emu_rdb(struct x86emu *emu, uint32_t addr)
+{
+	uint8_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+	return (*va);
+}
+
+static uint16_t
+x86bios_emu_rdw(struct x86emu *emu, uint32_t addr)
+{
+	uint16_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+	if ((addr & 1) != 0)
+		return (le16dec(va));
+	else
+#endif
+	return (le16toh(*va));
+}
+
+static uint32_t
+x86bios_emu_rdl(struct x86emu *emu, uint32_t addr)
+{
+	uint32_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+	if ((addr & 3) != 0)
+		return (le32dec(va));
+	else
+#endif
+	return (le32toh(*va));
+}
+
+static void
+x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val)
+{
+	uint8_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+	*va = val;
+}
+
+static void
+x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val)
+{
+	uint16_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+	if ((addr & 1) != 0)
+		le16enc(va, val);
+	else
+#endif
+	*va = htole16(val);
+}
+
+static void
+x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val)
+{
+	uint32_t *va;
+
+	va = x86bios_get_pages(addr, sizeof(*va));
+	if (va == NULL)
+		x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+	if ((addr & 3) != 0)
+		le32enc(va, val);
+	else
+#endif
+	*va = htole32(val);
+}
+
+static uint8_t
+x86bios_emu_inb(struct x86emu *emu, uint16_t port)
+{
+
+	if (port == 0xb2) /* APM scratch register */
+		return (0);
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return (0);
+
+	return (inb(port));
+}
+
+static uint16_t
+x86bios_emu_inw(struct x86emu *emu, uint16_t port)
+{
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return (0);
+
+	return (inw(port));
+}
+
+static uint32_t
+x86bios_emu_inl(struct x86emu *emu, uint16_t port)
+{
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return (0);
+
+	return (inl(port));
+}
+
+static void
+x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val)
+{
+
+	if (port == 0xb2) /* APM scratch register */
+		return;
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	outb(port, val);
+}
+
+static void
+x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val)
+{
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	outw(port, val);
+}
+
+static void
+x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val)
+{
+
+	if (port >= 0x80 && port < 0x88) /* POST status register */
+		return;
+
+	outl(port, val);
+}
+
+static void
+x86bios_emu_get_intr(struct x86emu *emu, int intno)
+{
+	uint16_t *sp;
+	uint32_t iv;
+
+	emu->x86.R_SP -= 6;
+
+	sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP);
+	sp[0] = htole16(emu->x86.R_IP);
+	sp[1] = htole16(emu->x86.R_CS);
+	sp[2] = htole16(emu->x86.R_FLG);
+
+	iv = x86bios_get_intr(intno);
+	emu->x86.R_IP = iv & 0xffff;
+	emu->x86.R_CS = (iv >> 16) & 0xffff;
+	emu->x86.R_FLG &= ~(F_IF | F_TF);
+}
+
+void *
+x86bios_alloc(uint32_t *offset, size_t size)
+{
+	void *vaddr;
+
+	if (offset == NULL || size == 0)
+		return (NULL);
+
+	vaddr = contigmalloc(size, M_DEVBUF, M_NOWAIT, X86BIOS_RAM_BASE,
+	    x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
+	if (vaddr != NULL) {
+		*offset = vtophys(vaddr);
+		x86bios_set_pages((vm_offset_t)vaddr, *offset, size);
+	}
+
+	return (vaddr);
+}
+
+void
+x86bios_free(void *addr, size_t size)
+{
+	vm_paddr_t paddr;
+
+	if (addr == NULL || size == 0)
+		return;
+
+	paddr = vtophys(addr);
+	if (paddr < X86BIOS_RAM_BASE || paddr >= x86bios_rom_phys ||
+	    paddr % X86BIOS_PAGE_SIZE != 0)
+		return;
+
+	bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE,
+	    sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE));
+	contigfree(addr, size, M_DEVBUF);
+}
+
+void
+x86bios_init_regs(struct x86regs *regs)
+{
+
+	bzero(regs, sizeof(*regs));
+	regs->X86BIOS_R_DS = 0x40;
+	regs->X86BIOS_R_SS = x86bios_seg_phys >> 4;
+}
+
+void
+x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
+{
+
+	if (x86bios_map == NULL)
+		return;
+
+	if (x86bios_trace_call)
+		kprintf("Calling 0x%05x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+
+	lockmgr(&x86bios_lock, LK_EXCLUSIVE);
+	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
+	x86bios_fault = 0;
+	x86emu_exec_call(&x86bios_emu, seg, off);
+	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
+	lockmgr(&x86bios_lock, LK_RELEASE);
+
+	if (x86bios_trace_call) {
+		kprintf("Exiting 0x%05x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+		if (x86bios_fault)
+			kprintf("Page fault at 0x%05x from 0x%04x:0x%04x.\n",
+			    x86bios_fault_addr, x86bios_fault_cs,
+			    x86bios_fault_ip);
+	}
+}
+
+uint32_t
+x86bios_get_intr(int intno)
+{
+	uint32_t *iv;
+
+	iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4);
+
+	return (le32toh(*iv));
+}
+
+void
+x86bios_intr(struct x86regs *regs, int intno)
+{
+
+	if (intno < 0 || intno > 255)
+		return;
+
+	if (x86bios_map == NULL)
+		return;
+
+	if (x86bios_trace_int)
+		kprintf("Calling int 0x%x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+
+	lockmgr(&x86bios_lock, LK_EXCLUSIVE);
+	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
+	x86bios_fault = 0;
+	x86emu_exec_intr(&x86bios_emu, intno);
+	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
+	lockmgr(&x86bios_lock, LK_RELEASE);
+
+	if (x86bios_trace_int) {
+		kprintf("Exiting int 0x%x (ax=0x%04x bx=0x%04x "
+		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
+		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
+		    regs->R_DX, regs->R_ES, regs->R_DI);
+		if (x86bios_fault)
+			kprintf("Page fault at 0x%05x from 0x%04x:0x%04x.\n",
+			    x86bios_fault_addr, x86bios_fault_cs,
+			    x86bios_fault_ip);
+	}
+}
+
+void *
+x86bios_offset(uint32_t offset)
+{
+
+	return (x86bios_get_pages(offset, 1));
+}
+
+void *
+x86bios_get_orm(uint32_t offset)
+{
+	uint8_t *p;
+
+	/* Does the shadow ROM contain BIOS POST code for x86? */
+	p = x86bios_offset(offset);
+	if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9)
+		return (NULL);
+
+	return (p);
+}
+
+int
+x86bios_match_device(uint32_t offset, device_t dev)
+{
+	uint8_t *p;
+	uint16_t device, vendor;
+	uint8_t class, progif, subclass;
+
+	/* Does the shadow ROM contain BIOS POST code for x86? */
+	p = x86bios_get_orm(offset);
+	if (p == NULL)
+		return (0);
+
+	/* Does it contain PCI data structure? */
+	p += le16toh(*(uint16_t *)(p + 0x18));
+	if (bcmp(p, "PCIR", 4) != 0 ||
+	    le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0)
+		return (0);
+
+	/* Does it match the vendor, device, and classcode? */
+	vendor = le16toh(*(uint16_t *)(p + 0x04));
+	device = le16toh(*(uint16_t *)(p + 0x06));
+	progif = *(p + 0x0d);
+	subclass = *(p + 0x0e);
+	class = *(p + 0x0f);
+	if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) ||
+	    class != pci_get_class(dev) || subclass != pci_get_subclass(dev) ||
+	    progif != pci_get_progif(dev))
+		return (0);
+
+	return (1);
+}
+
+#if defined(__amd64__) || defined(__i386__)
+#define	PROBE_EBDA	1
+#else
+#define	PROBE_EBDA	0
+#endif
+
+static __inline int
+x86bios_map_mem(void)
+{
+
+	x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE);
+	if (x86bios_ivt == NULL)
+		return (1);
+
+#if PROBE_EBDA
+	/* Probe EBDA via BDA. */
+	x86bios_rom_phys = *(uint16_t *)((vm_offset_t)x86bios_ivt + 0x40e);
+	x86bios_rom_phys = le16toh(x86bios_rom_phys) << 4;
+	if (x86bios_rom_phys != 0 && x86bios_rom_phys < X86BIOS_ROM_BASE &&
+	    X86BIOS_ROM_BASE - x86bios_rom_phys <= 128 * 1024)
+		x86bios_rom_phys =
+		    rounddown(x86bios_rom_phys, X86BIOS_PAGE_SIZE);
+	else
+#endif
+	x86bios_rom_phys = X86BIOS_ROM_BASE;
+	x86bios_rom = pmap_mapdev(x86bios_rom_phys, X86BIOS_ROM_SIZE);
+	if (x86bios_rom == NULL) {
+		pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+		return (1);
+	}
+#if PROBE_EBDA
+	/* Change attribute for EBDA. */
+	if (x86bios_rom_phys < X86BIOS_ROM_BASE &&
+	    pmap_change_attr((vm_offset_t)x86bios_rom,
+	    X86BIOS_ROM_BASE - x86bios_rom_phys, PAT_WRITE_BACK) != 0) {
+		pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+		pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
+		return (1);
+	}
+#endif
+
+	x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK,
+	    X86BIOS_RAM_BASE, x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
+	x86bios_seg_phys = vtophys(x86bios_seg);
+
+	if (bootverbose) {
+		kprintf("x86bios:   IVT 0x%06x-0x%06x at %p\n",
+		    X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE + X86BIOS_IVT_BASE - 1,
+		    x86bios_ivt);
+		kprintf("x86bios:  SSEG 0x%06x-0x%06x at %p\n",
+		    (uint32_t)x86bios_seg_phys,
+		    X86BIOS_SEG_SIZE + (uint32_t)x86bios_seg_phys - 1,
+		    x86bios_seg);
+#if PROBE_EBDA
+		if (x86bios_rom_phys < X86BIOS_ROM_BASE)
+			kprintf("x86bios:  EBDA 0x%06x-0x%06x at %p\n",
+			    (uint32_t)x86bios_rom_phys, X86BIOS_ROM_BASE - 1,
+			    x86bios_rom);
+#endif
+		kprintf("x86bios:   ROM 0x%06x-0x%06x at %p\n",
+		    X86BIOS_ROM_BASE, X86BIOS_MEM_SIZE - X86BIOS_SEG_SIZE - 1,
+		    (void *)((vm_offset_t)x86bios_rom + X86BIOS_ROM_BASE -
+		    (vm_offset_t)x86bios_rom_phys));
+	}
+
+	return (0);
+}
+
+#undef PROBE_EBDA
+
+static __inline void
+x86bios_unmap_mem(void)
+{
+
+	pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+	pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
+	contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF);
+}
+
+static void
+x86bios_init(void *arg __unused)
+{
+	int i;
+
+	lockinit(&x86bios_lock, "x86bios lock", 0, LK_CANRECURSE);
+
+	if (x86bios_map_mem() != 0)
+		return;
+
+	x86bios_map = kmalloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE,
+	    X86BIOS_IVT_SIZE);
+	x86bios_set_pages((vm_offset_t)x86bios_rom, x86bios_rom_phys,
+	    X86BIOS_ROM_SIZE);
+	x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys,
+	    X86BIOS_SEG_SIZE);
+
+	bzero(&x86bios_emu, sizeof(x86bios_emu));
+
+	x86bios_emu.emu_rdb = x86bios_emu_rdb;
+	x86bios_emu.emu_rdw = x86bios_emu_rdw;
+	x86bios_emu.emu_rdl = x86bios_emu_rdl;
+	x86bios_emu.emu_wrb = x86bios_emu_wrb;
+	x86bios_emu.emu_wrw = x86bios_emu_wrw;
+	x86bios_emu.emu_wrl = x86bios_emu_wrl;
+
+	x86bios_emu.emu_inb = x86bios_emu_inb;
+	x86bios_emu.emu_inw = x86bios_emu_inw;
+	x86bios_emu.emu_inl = x86bios_emu_inl;
+	x86bios_emu.emu_outb = x86bios_emu_outb;
+	x86bios_emu.emu_outw = x86bios_emu_outw;
+	x86bios_emu.emu_outl = x86bios_emu_outl;
+
+	for (i = 0; i < 256; i++)
+		x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr;
+}
+
+static void
+x86bios_uninit(void *arg __unused)
+{
+	vm_offset_t *map = x86bios_map;
+
+	lockmgr(&x86bios_lock, LK_EXCLUSIVE);
+	if (x86bios_map != NULL) {
+		kfree(x86bios_map, M_DEVBUF);
+		x86bios_map = NULL;
+	}
+	lockmgr(&x86bios_lock, LK_RELEASE);
+
+	if (map != NULL)
+		x86bios_unmap_mem();
+
+	lockuninit(&x86bios_lock);
+}
+
+static int
+x86bios_modevent(module_t mod __unused, int type, void *data __unused)
+{
+
+	switch (type) {
+	case MOD_LOAD:
+		x86bios_init(NULL);
+		break;
+	case MOD_UNLOAD:
+		x86bios_uninit(NULL);
+		break;
+	default:
+		return (ENOTSUP);
+	}
+
+	return (0);
+}
+
+static moduledata_t x86bios_mod = {
+	"x86bios",
+	x86bios_modevent,
+	NULL,
+};
+
+DECLARE_MODULE(x86bios, x86bios_mod, SI_BOOT2_BIOS, SI_ORDER_ANY);
+MODULE_VERSION(x86bios, 1);
diff --git a/sys/emulation/x86bios/x86bios.h b/sys/emulation/x86bios/x86bios.h
new file mode 100644
index 0000000..0ee59f9
--- /dev/null
+++ b/sys/emulation/x86bios/x86bios.h
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD: src/sys/compat/x86bios/x86bios.h,v 1.5 2009/10/19 20:58:10 jkim Exp $
+ */
+/*
+ * x86 registers were borrowed from x86emu.h x86emu_regs.h
+ * for compatability.
+ */
+
+#ifndef _X86BIOS_H_
+#define	_X86BIOS_H_
+
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#ifdef	__BIG_ENDIAN__
+
+struct x86_register32 {
+	uint32_t		e_reg;
+};
+
+struct x86_register16 {
+	uint16_t		filler0;
+	uint16_t		x_reg;
+};
+
+struct x86_register8 {
+	uint8_t			filler0;
+	uint8_t			filler1;
+	uint8_t			h_reg;
+	uint8_t			l_reg;
+};
+
+#else /* !__BIG_ENDIAN__ */
+
+struct x86_register32 {
+	uint32_t		e_reg;
+};
+
+struct x86_register16 {
+	uint16_t		x_reg;
+};
+
+struct x86_register8 {
+	uint8_t			l_reg;
+	uint8_t			h_reg;
+};
+
+#endif /* __BIG_ENDIAN__ */
+
+union x86_register {
+	struct x86_register32	I32_reg;
+	struct x86_register16	I16_reg;
+	struct x86_register8	I8_reg;
+};
+
+struct x86regs {
+	uint16_t		_pad0;		/* CS */
+	uint16_t		_pad1;		/* DS */
+	uint16_t		register_es;
+	uint16_t		register_fs;
+	uint16_t		register_gs;
+	uint16_t		_pad2;		/* SS */
+	uint32_t		register_flags;
+	union x86_register	register_a;
+	union x86_register	register_b;
+	union x86_register	register_c;
+	union x86_register	register_d;
+
+	union x86_register	_pad3;		/* SP */
+	union x86_register	register_bp;
+	union x86_register	register_si;
+	union x86_register	register_di;
+};
+
+typedef struct x86regs	x86regs_t;
+
+/* 8 bit registers */
+#define	R_AH		register_a.I8_reg.h_reg
+#define	R_AL		register_a.I8_reg.l_reg
+#define	R_BH		register_b.I8_reg.h_reg
+#define	R_BL		register_b.I8_reg.l_reg
+#define	R_CH		register_c.I8_reg.h_reg
+#define	R_CL		register_c.I8_reg.l_reg
+#define	R_DH		register_d.I8_reg.h_reg
+#define	R_DL		register_d.I8_reg.l_reg
+
+/* 16 bit registers */
+#define	R_AX		register_a.I16_reg.x_reg
+#define	R_BX		register_b.I16_reg.x_reg
+#define	R_CX		register_c.I16_reg.x_reg
+#define	R_DX		register_d.I16_reg.x_reg
+
+/* 32 bit extended registers */
+#define	R_EAX		register_a.I32_reg.e_reg
+#define	R_EBX		register_b.I32_reg.e_reg
+#define	R_ECX		register_c.I32_reg.e_reg
+#define	R_EDX		register_d.I32_reg.e_reg
+
+/* special registers */
+#define	R_BP		register_bp.I16_reg.x_reg
+#define	R_SI		register_si.I16_reg.x_reg
+#define	R_DI		register_di.I16_reg.x_reg
+#define	R_FLG		register_flags
+
+/* special registers */
+#define	R_EBP		register_bp.I32_reg.e_reg
+#define	R_ESI		register_si.I32_reg.e_reg
+#define	R_EDI		register_di.I32_reg.e_reg
+#define	R_EFLG		register_flags
+
+/* segment registers */
+#define	R_ES		register_es
+#define	R_FS		register_fs
+#define	R_GS		register_gs
+
+#define	X86BIOS_PHYSTOSEG(x)	(((x) >> 4) & 0xffff)
+#define	X86BIOS_PHYSTOOFF(x)	((x) & 0x000f)
+
+__BEGIN_DECLS
+void	*x86bios_alloc(uint32_t *offset, size_t size);
+void	 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off);
+void	 x86bios_free(void *addr, size_t size);
+uint32_t x86bios_get_intr(int intno);
+void	*x86bios_get_orm(uint32_t offset);
+void	 x86bios_init_regs(struct x86regs *regs);
+void	 x86bios_intr(struct x86regs *regs, int intno);
+int	 x86bios_match_device(uint32_t offset, device_t dev);
+void	*x86bios_offset(uint32_t offset);
+__END_DECLS
+
+#endif /* !_X86BIOS_H_ */
diff --git a/sys/emulation/x86emu/x86emu.c b/sys/emulation/x86emu/x86emu.c
new file mode 100644
index 0000000..efcde64
--- /dev/null
+++ b/sys/emulation/x86emu/x86emu.c
@@ -0,0 +1,8395 @@
+/*	$OpenBSD: x86emu.c,v 1.5 2010/02/17 15:09:47 pirofti Exp $	*/
+/*	$NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $	*/
+
+/*
+ *
+ *  Realmode X86 Emulator Library
+ *
+ *  Copyright (C) 1996-1999 SciTech Software, Inc.
+ *  Copyright (C) David Mosberger-Tang
+ *  Copyright (C) 1999 Egbert Eich
+ *  Copyright (C) 2007 Joerg Sonnenberger
+ *
+ *  ========================================================================
+ *
+ *  Permission to use, copy, modify, distribute, and sell this software and
+ *  its documentation for any purpose is hereby granted without fee,
+ *  provided that the above copyright notice appear in all copies and that
+ *  both that copyright notice and this permission notice appear in
+ *  supporting documentation, and that the name of the authors not be used
+ *  in advertising or publicity pertaining to distribution of the software
+ *  without specific, written prior permission.  The authors makes no
+ *  representations about the suitability of this software for any purpose.
+ *  It is provided "as is" without express or implied warranty.
+ *
+ *  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ *  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ *  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ *  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ *  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ *  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ *  PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD: src/sys/contrib/x86emu/x86emu.c,v 1.5 2010/03/09 22:42:24 delphij Exp $
+ */
+
+#include <emulation/x86emu/x86emu.h>
+#include <emulation/x86emu/x86emu_regs.h>
+
+static void 	x86emu_intr_raise (struct x86emu *, uint8_t type);
+
+static void	x86emu_exec_one_byte(struct x86emu *);
+static void	x86emu_exec_two_byte(struct x86emu *);
+
+static void	fetch_decode_modrm (struct x86emu *);
+static uint8_t	fetch_byte_imm (struct x86emu *);
+static uint16_t	fetch_word_imm (struct x86emu *);
+static uint32_t	fetch_long_imm (struct x86emu *);
+static uint8_t	fetch_data_byte (struct x86emu *, uint32_t offset);
+static uint8_t	fetch_byte (struct x86emu *, u_int segment, uint32_t offset);
+static uint16_t	fetch_data_word (struct x86emu *, uint32_t offset);
+static uint16_t	fetch_word (struct x86emu *, uint32_t segment, uint32_t offset);
+static uint32_t	fetch_data_long (struct x86emu *, uint32_t offset);
+static uint32_t	fetch_long (struct x86emu *, uint32_t segment, uint32_t offset);
+static void	store_data_byte (struct x86emu *, uint32_t offset, uint8_t val);
+static void	store_byte (struct x86emu *, uint32_t segment, uint32_t offset, uint8_t val);
+static void	store_data_word (struct x86emu *, uint32_t offset, uint16_t val);
+static void	store_word (struct x86emu *, uint32_t segment, uint32_t offset, uint16_t val);
+static void	store_data_long (struct x86emu *, uint32_t offset, uint32_t val);
+static void	store_long (struct x86emu *, uint32_t segment, uint32_t offset, uint32_t val);
+static uint8_t*	decode_rl_byte_register(struct x86emu *);
+static uint16_t*	decode_rl_word_register(struct x86emu *);
+static uint32_t* 	decode_rl_long_register(struct x86emu *);
+static uint8_t* 	decode_rh_byte_register(struct x86emu *);
+static uint16_t* 	decode_rh_word_register(struct x86emu *);
+static uint32_t* 	decode_rh_long_register(struct x86emu *);
+static uint16_t* 	decode_rh_seg_register(struct x86emu *);
+static uint32_t	decode_rl_address(struct x86emu *);
+
+static uint8_t 	decode_and_fetch_byte(struct x86emu *);
+static uint16_t 	decode_and_fetch_word(struct x86emu *);
+static uint32_t 	decode_and_fetch_long(struct x86emu *);
+
+static uint8_t 	decode_and_fetch_byte_imm8(struct x86emu *, uint8_t *);
+static uint16_t 	decode_and_fetch_word_imm8(struct x86emu *, uint8_t *);
+static uint32_t 	decode_and_fetch_long_imm8(struct x86emu *, uint8_t *);
+
+static uint16_t 	decode_and_fetch_word_disp(struct x86emu *, int16_t);
+static uint32_t 	decode_and_fetch_long_disp(struct x86emu *, int16_t);
+
+static void	write_back_byte(struct x86emu *, uint8_t);
+static void	write_back_word(struct x86emu *, uint16_t);
+static void	write_back_long(struct x86emu *, uint32_t);
+
+static uint16_t	aaa_word (struct x86emu *, uint16_t d);
+static uint16_t	aas_word (struct x86emu *, uint16_t d);
+static uint16_t	aad_word (struct x86emu *, uint16_t d);
+static uint16_t	aam_word (struct x86emu *, uint8_t d);
+static uint8_t	adc_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	adc_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	adc_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	add_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	add_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	add_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	and_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	and_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	and_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	cmp_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	cmp_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	cmp_long (struct x86emu *, uint32_t d, uint32_t s);
+static void	cmp_byte_no_return (struct x86emu *, uint8_t d, uint8_t s);
+static void	cmp_word_no_return (struct x86emu *, uint16_t d, uint16_t s);
+static void	cmp_long_no_return (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	daa_byte (struct x86emu *, uint8_t d);
+static uint8_t	das_byte (struct x86emu *, uint8_t d);
+static uint8_t	dec_byte (struct x86emu *, uint8_t d);
+static uint16_t	dec_word (struct x86emu *, uint16_t d);
+static uint32_t	dec_long (struct x86emu *, uint32_t d);
+static uint8_t	inc_byte (struct x86emu *, uint8_t d);
+static uint16_t	inc_word (struct x86emu *, uint16_t d);
+static uint32_t	inc_long (struct x86emu *, uint32_t d);
+static uint8_t	or_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	or_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	or_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	neg_byte (struct x86emu *, uint8_t s);
+static uint16_t	neg_word (struct x86emu *, uint16_t s);
+static uint32_t	neg_long (struct x86emu *, uint32_t s);
+static uint8_t	rcl_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	rcl_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	rcl_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	rcr_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	rcr_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	rcr_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	rol_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	rol_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	rol_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	ror_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	ror_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	ror_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	shl_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	shl_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	shl_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	shr_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	shr_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	shr_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint8_t	sar_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	sar_word (struct x86emu *, uint16_t d, uint8_t s);
+static uint32_t	sar_long (struct x86emu *, uint32_t d, uint8_t s);
+static uint16_t	shld_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
+static uint32_t	shld_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
+static uint16_t	shrd_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
+static uint32_t	shrd_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
+static uint8_t	sbb_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	sbb_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	sbb_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	sub_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	sub_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	sub_long (struct x86emu *, uint32_t d, uint32_t s);
+static void	test_byte (struct x86emu *, uint8_t d, uint8_t s);
+static void	test_word (struct x86emu *, uint16_t d, uint16_t s);
+static void	test_long (struct x86emu *, uint32_t d, uint32_t s);
+static uint8_t	xor_byte (struct x86emu *, uint8_t d, uint8_t s);
+static uint16_t	xor_word (struct x86emu *, uint16_t d, uint16_t s);
+static uint32_t	xor_long (struct x86emu *, uint32_t d, uint32_t s);
+static void	imul_byte (struct x86emu *, uint8_t s);
+static void	imul_word (struct x86emu *, uint16_t s);
+static void	imul_long (struct x86emu *, uint32_t s);
+static void	mul_byte (struct x86emu *, uint8_t s);
+static void	mul_word (struct x86emu *, uint16_t s);
+static void	mul_long (struct x86emu *, uint32_t s);
+static void	idiv_byte (struct x86emu *, uint8_t s);
+static void	idiv_word (struct x86emu *, uint16_t s);
+static void	idiv_long (struct x86emu *, uint32_t s);
+static void	div_byte (struct x86emu *, uint8_t s);
+static void	div_word (struct x86emu *, uint16_t s);
+static void	div_long (struct x86emu *, uint32_t s);
+static void	ins (struct x86emu *, int size);
+static void	outs (struct x86emu *, int size);
+static void	push_word (struct x86emu *, uint16_t w);
+static void	push_long (struct x86emu *, uint32_t w);
+static uint16_t	pop_word (struct x86emu *);
+static uint32_t	pop_long (struct x86emu *);
+
+/*
+ * REMARKS:
+ * Handles any pending asychronous interrupts.
+ */
+static void
+x86emu_intr_dispatch(struct x86emu *emu, uint8_t intno)
+{
+	if (emu->_x86emu_intrTab[intno]) {
+		(*emu->_x86emu_intrTab[intno]) (emu, intno);
+	} else {
+		push_word(emu, (uint16_t) emu->x86.R_FLG);
+		CLEAR_FLAG(F_IF);
+		CLEAR_FLAG(F_TF);
+		push_word(emu, emu->x86.R_CS);
+		emu->x86.R_CS = fetch_word(emu, 0, intno * 4 + 2);
+		push_word(emu, emu->x86.R_IP);
+		emu->x86.R_IP = fetch_word(emu, 0, intno * 4);
+	}
+}
+
+static void
+x86emu_intr_handle(struct x86emu *emu)
+{
+	uint8_t intno;
+
+	if (emu->x86.intr & INTR_SYNCH) {
+		intno = emu->x86.intno;
+		emu->x86.intr = 0;
+		x86emu_intr_dispatch(emu, intno);
+	}
+}
+
+/*
+ * PARAMETERS:
+ * intrnum - Interrupt number to raise
+ *
+ * REMARKS:
+ * Raise the specified interrupt to be handled before the execution of the
+ * next instruction.
+ */
+void
+x86emu_intr_raise(struct x86emu *emu, uint8_t intrnum)
+{
+	emu->x86.intno = intrnum;
+	emu->x86.intr |= INTR_SYNCH;
+}
+
+/*
+ * REMARKS:
+ * Main execution loop for the emulator. We return from here when the system
+ * halts, which is normally caused by a stack fault when we return from the
+ * original real mode call.
+ */
+void
+x86emu_exec(struct x86emu *emu)
+{
+	emu->x86.intr = 0;
+
+	if (setjmp(emu->exec_state))
+		return;
+
+	for (;;) {
+		if (emu->x86.intr) {
+			if (((emu->x86.intr & INTR_SYNCH) &&
+			    (emu->x86.intno == 0 || emu->x86.intno == 2)) ||
+			    !ACCESS_FLAG(F_IF)) {
+				x86emu_intr_handle(emu);
+			}
+		}
+		if (emu->x86.R_CS == 0 && emu->x86.R_IP == 0)
+			return;
+		x86emu_exec_one_byte(emu);
+		++emu->cur_cycles;
+	}
+}
+
+void
+x86emu_exec_call(struct x86emu *emu, uint16_t seg, uint16_t off)
+{
+	push_word(emu, 0);
+	push_word(emu, 0);
+	emu->x86.R_CS = seg;
+	emu->x86.R_IP = off;
+
+	x86emu_exec(emu);
+}
+
+void
+x86emu_exec_intr(struct x86emu *emu, uint8_t intr)
+{
+	push_word(emu, emu->x86.R_FLG);
+	CLEAR_FLAG(F_IF);
+	CLEAR_FLAG(F_TF);
+	push_word(emu, 0);
+	push_word(emu, 0);
+	emu->x86.R_CS = (*emu->emu_rdw)(emu, intr * 4 + 2);
+	emu->x86.R_IP = (*emu->emu_rdw)(emu, intr * 4);
+	emu->x86.intr = 0;
+
+	x86emu_exec(emu);
+}
+
+/*
+ * REMARKS:
+ * Halts the system by setting the halted system flag.
+ */
+void
+x86emu_halt_sys(struct x86emu *emu)
+{
+	longjmp(emu->exec_state, 1);
+}
+
+/*
+ * PARAMETERS:
+ * mod		- Mod value from decoded byte
+ * regh	- Reg h value from decoded byte
+ * regl	- Reg l value from decoded byte
+ *
+ * REMARKS:
+ * Raise the specified interrupt to be handled before the execution of the
+ * next instruction.
+ *
+ * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
+ */
+static void
+fetch_decode_modrm(struct x86emu *emu)
+{
+	int fetched;
+
+	fetched = fetch_byte_imm(emu);
+	emu->cur_mod = (fetched >> 6) & 0x03;
+	emu->cur_rh = (fetched >> 3) & 0x07;
+	emu->cur_rl = (fetched >> 0) & 0x07;
+}
+
+/*
+ * RETURNS:
+ * Immediate byte value read from instruction queue
+ *
+ * REMARKS:
+ * This function returns the immediate byte from the instruction queue, and
+ * moves the instruction pointer to the next value.
+ *
+ * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
+ */
+static uint8_t
+fetch_byte_imm(struct x86emu *emu)
+{
+	uint8_t fetched;
+
+	fetched = fetch_byte(emu, emu->x86.R_CS, emu->x86.R_IP);
+	emu->x86.R_IP++;
+	return fetched;
+}
+
+/*
+ * RETURNS:
+ * Immediate word value read from instruction queue
+ *
+ * REMARKS:
+ * This function returns the immediate byte from the instruction queue, and
+ * moves the instruction pointer to the next value.
+ *
+ * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
+ */
+static uint16_t
+fetch_word_imm(struct x86emu *emu)
+{
+	uint16_t fetched;
+
+	fetched = fetch_word(emu, emu->x86.R_CS, emu->x86.R_IP);
+	emu->x86.R_IP += 2;
+	return fetched;
+}
+
+/*
+ * RETURNS:
+ * Immediate lone value read from instruction queue
+ *
+ * REMARKS:
+ * This function returns the immediate byte from the instruction queue, and
+ * moves the instruction pointer to the next value.
+ *
+ * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
+ */
+static uint32_t
+fetch_long_imm(struct x86emu *emu)
+{
+	uint32_t fetched;
+
+	fetched = fetch_long(emu, emu->x86.R_CS, emu->x86.R_IP);
+	emu->x86.R_IP += 4;
+	return fetched;
+}
+
+/*
+ * RETURNS:
+ * Value of the default data segment
+ *
+ * REMARKS:
+ * Inline function that returns the default data segment for the current
+ * instruction.
+ *
+ * On the x86 processor, the default segment is not always DS if there is
+ * no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
+ * addresses relative to SS (ie: on the stack). So, at the minimum, all
+ * decodings of addressing modes would have to set/clear a bit describing
+ * whether the access is relative to DS or SS.  That is the function of the
+ * cpu-state-varible emu->x86.mode. There are several potential states:
+ *
+ * 	repe prefix seen  (handled elsewhere)
+ * 	repne prefix seen  (ditto)
+ *
+ * 	cs segment override
+ * 	ds segment override
+ * 	es segment override
+ * 	fs segment override
+ * 	gs segment override
+ * 	ss segment override
+ *
+ * 	ds/ss select (in absense of override)
+ *
+ * Each of the above 7 items are handled with a bit in the mode field.
+ */
+static uint32_t
+get_data_segment(struct x86emu *emu)
+{
+	switch (emu->x86.mode & SYSMODE_SEGMASK) {
+	case 0:		/* default case: use ds register */
+	case SYSMODE_SEGOVR_DS:
+	case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_DS;
+	case SYSMODE_SEG_DS_SS:/* non-overridden, use ss register */
+		return emu->x86.R_SS;
+	case SYSMODE_SEGOVR_CS:
+	case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_CS;
+	case SYSMODE_SEGOVR_ES:
+	case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_ES;
+	case SYSMODE_SEGOVR_FS:
+	case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_FS;
+	case SYSMODE_SEGOVR_GS:
+	case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_GS;
+	case SYSMODE_SEGOVR_SS:
+	case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
+		return emu->x86.R_SS;
+	}
+	x86emu_halt_sys(emu);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Byte value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint8_t
+fetch_data_byte(struct x86emu *emu, uint32_t offset)
+{
+	return fetch_byte(emu, get_data_segment(emu), offset);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Word value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint16_t
+fetch_data_word(struct x86emu *emu, uint32_t offset)
+{
+	return fetch_word(emu, get_data_segment(emu), offset);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Long value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint32_t
+fetch_data_long(struct x86emu *emu, uint32_t offset)
+{
+	return fetch_long(emu, get_data_segment(emu), offset);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to load data from
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Byte value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint8_t
+fetch_byte(struct x86emu *emu, uint32_t segment, uint32_t offset)
+{
+	return (*emu->emu_rdb) (emu, ((uint32_t) segment << 4) + offset);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to load data from
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Word value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint16_t
+fetch_word(struct x86emu *emu, uint32_t segment, uint32_t offset)
+{
+	return (*emu->emu_rdw) (emu, ((uint32_t) segment << 4) + offset);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to load data from
+ * offset	- Offset to load data from
+ *
+ * RETURNS:
+ * Long value read from the absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
+ */
+static uint32_t
+fetch_long(struct x86emu *emu, uint32_t segment, uint32_t offset)
+{
+	return (*emu->emu_rdl) (emu, ((uint32_t) segment << 4) + offset);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a word value to an segmented memory location. The segment used is
+ * the current 'default' segment, which may have been overridden.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_data_byte(struct x86emu *emu, uint32_t offset, uint8_t val)
+{
+	store_byte(emu, get_data_segment(emu), offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a word value to an segmented memory location. The segment used is
+ * the current 'default' segment, which may have been overridden.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_data_word(struct x86emu *emu, uint32_t offset, uint16_t val)
+{
+	store_word(emu, get_data_segment(emu), offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a long value to an segmented memory location. The segment used is
+ * the current 'default' segment, which may have been overridden.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_data_long(struct x86emu *emu, uint32_t offset, uint32_t val)
+{
+	store_long(emu, get_data_segment(emu), offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to store data at
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a byte value to an absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_byte(struct x86emu *emu, uint32_t segment, uint32_t offset, uint8_t val)
+{
+	(*emu->emu_wrb) (emu, ((uint32_t) segment << 4) + offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to store data at
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a word value to an absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_word(struct x86emu *emu, uint32_t segment, uint32_t offset, uint16_t val)
+{
+	(*emu->emu_wrw) (emu, ((uint32_t) segment << 4) + offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * segment	- Segment to store data at
+ * offset	- Offset to store data at
+ * val		- Value to store
+ *
+ * REMARKS:
+ * Writes a long value to an absolute memory location.
+ *
+ * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
+ */
+static void
+store_long(struct x86emu *emu, uint32_t segment, uint32_t offset, uint32_t val)
+{
+	(*emu->emu_wrl) (emu, ((uint32_t) segment << 4) + offset, val);
+}
+
+/*
+ * PARAMETERS:
+ * reg	- Register to decode
+ *
+ * RETURNS:
+ * Pointer to the appropriate register
+ *
+ * REMARKS:
+ * Return a pointer to the register given by the R/RM field of the
+ * modrm byte, for byte operands. Also enables the decoding of instructions.
+ */
+static uint8_t *
+decode_rm_byte_register(struct x86emu *emu, int reg)
+{
+	switch (reg) {
+	case 0:
+		return &emu->x86.R_AL;
+	case 1:
+		return &emu->x86.R_CL;
+	case 2:
+		return &emu->x86.R_DL;
+	case 3:
+		return &emu->x86.R_BL;
+	case 4:
+		return &emu->x86.R_AH;
+	case 5:
+		return &emu->x86.R_CH;
+	case 6:
+		return &emu->x86.R_DH;
+	case 7:
+		return &emu->x86.R_BH;
+	default:
+		x86emu_halt_sys(emu);
+	}
+}
+
+static uint8_t *
+decode_rl_byte_register(struct x86emu *emu)
+{
+	return decode_rm_byte_register(emu, emu->cur_rl);
+}
+
+static uint8_t *
+decode_rh_byte_register(struct x86emu *emu)
+{
+	return decode_rm_byte_register(emu, emu->cur_rh);
+}
+
+/*
+ * PARAMETERS:
+ * reg	- Register to decode
+ *
+ * RETURNS:
+ * Pointer to the appropriate register
+ *
+ * REMARKS:
+ * Return a pointer to the register given by the R/RM field of the
+ * modrm byte, for word operands.  Also enables the decoding of instructions.
+ */
+static uint16_t *
+decode_rm_word_register(struct x86emu *emu, int reg)
+{
+	switch (reg) {
+	case 0:
+		return &emu->x86.R_AX;
+	case 1:
+		return &emu->x86.R_CX;
+	case 2:
+		return &emu->x86.R_DX;
+	case 3:
+		return &emu->x86.R_BX;
+	case 4:
+		return &emu->x86.R_SP;
+	case 5:
+		return &emu->x86.R_BP;
+	case 6:
+		return &emu->x86.R_SI;
+	case 7:
+		return &emu->x86.R_DI;
+	default:
+		x86emu_halt_sys(emu);
+	}
+}
+
+static uint16_t *
+decode_rl_word_register(struct x86emu *emu)
+{
+	return decode_rm_word_register(emu, emu->cur_rl);
+}
+
+static uint16_t *
+decode_rh_word_register(struct x86emu *emu)
+{
+	return decode_rm_word_register(emu, emu->cur_rh);
+}
+
+/*
+ * PARAMETERS:
+ * reg	- Register to decode
+ *
+ * RETURNS:
+ * Pointer to the appropriate register
+ *
+ * REMARKS:
+ * Return a pointer to the register given by the R/RM field of the
+ * modrm byte, for dword operands.  Also enables the decoding of instructions.
+ */
+static uint32_t *
+decode_rm_long_register(struct x86emu *emu, int reg)
+{
+	switch (reg) {
+	case 0:
+		return &emu->x86.R_EAX;
+	case 1:
+		return &emu->x86.R_ECX;
+	case 2:
+		return &emu->x86.R_EDX;
+	case 3:
+		return &emu->x86.R_EBX;
+	case 4:
+		return &emu->x86.R_ESP;
+	case 5:
+		return &emu->x86.R_EBP;
+	case 6:
+		return &emu->x86.R_ESI;
+	case 7:
+		return &emu->x86.R_EDI;
+	default:
+		x86emu_halt_sys(emu);
+	}
+}
+
+static uint32_t *
+decode_rl_long_register(struct x86emu *emu)
+{
+	return decode_rm_long_register(emu, emu->cur_rl);
+}
+
+static uint32_t *
+decode_rh_long_register(struct x86emu *emu)
+{
+	return decode_rm_long_register(emu, emu->cur_rh);
+}
+
+
+/*
+ * PARAMETERS:
+ * reg	- Register to decode
+ *
+ * RETURNS:
+ * Pointer to the appropriate register
+ *
+ * REMARKS:
+ * Return a pointer to the register given by the R/RM field of the
+ * modrm byte, for word operands, modified from above for the weirdo
+ * special case of segreg operands.  Also enables the decoding of instructions.
+ */
+static uint16_t *
+decode_rh_seg_register(struct x86emu *emu)
+{
+	switch (emu->cur_rh) {
+	case 0:
+		return &emu->x86.R_ES;
+	case 1:
+		return &emu->x86.R_CS;
+	case 2:
+		return &emu->x86.R_SS;
+	case 3:
+		return &emu->x86.R_DS;
+	case 4:
+		return &emu->x86.R_FS;
+	case 5:
+		return &emu->x86.R_GS;
+	default:
+		x86emu_halt_sys(emu);
+	}
+}
+
+/*
+ * Return offset from the SIB Byte.
+ */
+static uint32_t
+decode_sib_address(struct x86emu *emu, int sib, int mod)
+{
+	uint32_t base = 0, i = 0, scale = 1;
+
+	switch (sib & 0x07) {
+	case 0:
+		base = emu->x86.R_EAX;
+		break;
+	case 1:
+		base = emu->x86.R_ECX;
+
+		break;
+	case 2:
+		base = emu->x86.R_EDX;
+		break;
+	case 3:
+		base = emu->x86.R_EBX;
+		break;
+	case 4:
+		base = emu->x86.R_ESP;
+		emu->x86.mode |= SYSMODE_SEG_DS_SS;
+		break;
+	case 5:
+		if (mod == 0) {
+			base = fetch_long_imm(emu);
+		} else {
+			base = emu->x86.R_EBP;
+			emu->x86.mode |= SYSMODE_SEG_DS_SS;
+		}
+		break;
+	case 6:
+		base = emu->x86.R_ESI;
+		break;
+	case 7:
+		base = emu->x86.R_EDI;
+		break;
+	}
+	switch ((sib >> 3) & 0x07) {
+	case 0:
+		i = emu->x86.R_EAX;
+		break;
+	case 1:
+		i = emu->x86.R_ECX;
+		break;
+	case 2:
+		i = emu->x86.R_EDX;
+		break;
+	case 3:
+		i = emu->x86.R_EBX;
+		break;
+	case 4:
+		i = 0;
+		break;
+	case 5:
+		i = emu->x86.R_EBP;
+		break;
+	case 6:
+		i = emu->x86.R_ESI;
+		break;
+	case 7:
+		i = emu->x86.R_EDI;
+		break;
+	}
+	scale = 1 << ((sib >> 6) & 0x03);
+	return base + (i * scale);
+}
+
+/*
+ * PARAMETERS:
+ * rm	- RM value to decode
+ *
+ * RETURNS:
+ * Offset in memory for the address decoding
+ *
+ * REMARKS:
+ * Return the offset given by mod=00, mod=01 or mod=10 addressing.
+ * Also enables the decoding of instructions.
+ */
+static uint32_t
+decode_rl_address(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
+		uint32_t offset, sib;
+		/* 32-bit addressing */
+		switch (emu->cur_rl) {
+		case 0:
+			offset = emu->x86.R_EAX;
+			break;
+		case 1:
+			offset = emu->x86.R_ECX;
+			break;
+		case 2:
+			offset = emu->x86.R_EDX;
+			break;
+		case 3:
+			offset = emu->x86.R_EBX;
+			break;
+		case 4:
+			sib = fetch_byte_imm(emu);
+			offset = decode_sib_address(emu, sib, 0);
+			break;
+		case 5:
+			if (emu->cur_mod == 0) {
+				offset = fetch_long_imm(emu);
+			} else {
+				emu->x86.mode |= SYSMODE_SEG_DS_SS;
+				offset = emu->x86.R_EBP;
+			}
+			break;
+		case 6:
+			offset = emu->x86.R_ESI;
+			break;
+		case 7:
+			offset = emu->x86.R_EDI;
+			break;
+		default:
+			x86emu_halt_sys(emu);
+		}
+		if (emu->cur_mod == 1)
+			offset += (int8_t)fetch_byte_imm(emu);
+		else if (emu->cur_mod == 2)
+			offset += fetch_long_imm(emu);
+		return offset;
+	} else {
+		uint16_t offset;
+
+		/* 16-bit addressing */
+		switch (emu->cur_rl) {
+		case 0:
+			offset = emu->x86.R_BX + emu->x86.R_SI;
+			break;
+		case 1:
+			offset = emu->x86.R_BX + emu->x86.R_DI;
+			break;
+		case 2:
+			emu->x86.mode |= SYSMODE_SEG_DS_SS;
+			offset = emu->x86.R_BP + emu->x86.R_SI;
+			break;
+		case 3:
+			emu->x86.mode |= SYSMODE_SEG_DS_SS;
+			offset = emu->x86.R_BP + emu->x86.R_DI;
+			break;
+		case 4:
+			offset = emu->x86.R_SI;
+			break;
+		case 5:
+			offset = emu->x86.R_DI;
+			break;
+		case 6:
+			if (emu->cur_mod == 0) {
+				offset = fetch_word_imm(emu);
+			} else {
+				emu->x86.mode |= SYSMODE_SEG_DS_SS;
+				offset = emu->x86.R_BP;
+			}
+			break;
+		case 7:
+			offset = emu->x86.R_BX;
+			break;
+		default:
+			x86emu_halt_sys(emu);
+		}
+		if (emu->cur_mod == 1)
+			offset += (int8_t)fetch_byte_imm(emu);
+		else if (emu->cur_mod == 2)
+			offset += fetch_word_imm(emu);
+		return offset;
+	}
+}
+
+static uint8_t
+decode_and_fetch_byte(struct x86emu *emu)
+{
+	if (emu->cur_mod != 3) {
+		emu->cur_offset = decode_rl_address(emu);
+		return fetch_data_byte(emu, emu->cur_offset);
+	} else {
+		return *decode_rl_byte_register(emu);
+	}
+}
+
+static uint16_t
+decode_and_fetch_word_disp(struct x86emu *emu, int16_t disp)
+{
+	if (emu->cur_mod != 3) {
+		/* TODO: A20 gate emulation */
+		emu->cur_offset = decode_rl_address(emu) + disp;
+		if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
+			emu->cur_offset &= 0xffff;
+		return fetch_data_word(emu, emu->cur_offset);
+	} else {
+		return *decode_rl_word_register(emu);
+	}
+}
+
+static uint32_t
+decode_and_fetch_long_disp(struct x86emu *emu, int16_t disp)
+{
+	if (emu->cur_mod != 3) {
+		/* TODO: A20 gate emulation */
+		emu->cur_offset = decode_rl_address(emu) + disp;
+		if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
+			emu->cur_offset &= 0xffff;
+		return fetch_data_long(emu, emu->cur_offset);
+	} else {
+		return *decode_rl_long_register(emu);
+	}
+}
+
+uint16_t
+decode_and_fetch_word(struct x86emu *emu)
+{
+	return decode_and_fetch_word_disp(emu, 0);
+}
+
+uint32_t
+decode_and_fetch_long(struct x86emu *emu)
+{
+	return decode_and_fetch_long_disp(emu, 0);
+}
+
+uint8_t
+decode_and_fetch_byte_imm8(struct x86emu *emu, uint8_t *imm)
+{
+	if (emu->cur_mod != 3) {
+		emu->cur_offset = decode_rl_address(emu);
+		*imm = fetch_byte_imm(emu);
+		return fetch_data_byte(emu, emu->cur_offset);
+	} else {
+		*imm = fetch_byte_imm(emu);
+		return *decode_rl_byte_register(emu);
+	}
+}
+
+static uint16_t
+decode_and_fetch_word_imm8(struct x86emu *emu, uint8_t *imm)
+{
+	if (emu->cur_mod != 3) {
+		emu->cur_offset = decode_rl_address(emu);
+		*imm = fetch_byte_imm(emu);
+		return fetch_data_word(emu, emu->cur_offset);
+	} else {
+		*imm = fetch_byte_imm(emu);
+		return *decode_rl_word_register(emu);
+	}
+}
+
+static uint32_t
+decode_and_fetch_long_imm8(struct x86emu *emu, uint8_t *imm)
+{
+	if (emu->cur_mod != 3) {
+		emu->cur_offset = decode_rl_address(emu);
+		*imm = fetch_byte_imm(emu);
+		return fetch_data_long(emu, emu->cur_offset);
+	} else {
+		*imm = fetch_byte_imm(emu);
+		return *decode_rl_long_register(emu);
+	}
+}
+
+static void
+write_back_byte(struct x86emu *emu, uint8_t val)
+{
+	if (emu->cur_mod != 3)
+		store_data_byte(emu, emu->cur_offset, val);
+	else
+		*decode_rl_byte_register(emu) = val;
+}
+
+static void
+write_back_word(struct x86emu *emu, uint16_t val)
+{
+	if (emu->cur_mod != 3)
+		store_data_word(emu, emu->cur_offset, val);
+	else
+		*decode_rl_word_register(emu) = val;
+}
+
+static void
+write_back_long(struct x86emu *emu, uint32_t val)
+{
+	if (emu->cur_mod != 3)
+		store_data_long(emu, emu->cur_offset, val);
+	else
+		*decode_rl_long_register(emu) = val;
+}
+
+static void
+common_inc_word_long(struct x86emu *emu, union x86emu_register *reg)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		reg->I32_reg.e_reg = inc_long(emu, reg->I32_reg.e_reg);
+	else
+		reg->I16_reg.x_reg = inc_word(emu, reg->I16_reg.x_reg);
+}
+
+static void
+common_dec_word_long(struct x86emu *emu, union x86emu_register *reg)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		reg->I32_reg.e_reg = dec_long(emu, reg->I32_reg.e_reg);
+	else
+		reg->I16_reg.x_reg = dec_word(emu, reg->I16_reg.x_reg);
+}
+
+static void
+common_binop_byte_rm_r(struct x86emu *emu,
+    uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
+{
+	uint32_t destoffset;
+	uint8_t *destreg, srcval;
+	uint8_t destval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_byte_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_byte(emu, destoffset);
+		destval = (*binop)(emu, destval, srcval);
+		store_data_byte(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_byte_register(emu);
+		*destreg = (*binop)(emu, *destreg, srcval);
+	}
+}
+
+static void
+common_binop_ns_byte_rm_r(struct x86emu *emu,
+    void (*binop)(struct x86emu *, uint8_t, uint8_t))
+{
+	uint32_t destoffset;
+	uint8_t destval, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_byte_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_byte(emu, destoffset);
+	} else {
+		destval = *decode_rl_byte_register(emu);
+	}
+	(*binop)(emu, destval, srcval);
+}
+
+static void
+common_binop_word_rm_r(struct x86emu *emu,
+    uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
+{
+	uint32_t destoffset;
+	uint16_t destval, *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_word_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_word(emu, destoffset);
+		destval = (*binop)(emu, destval, srcval);
+		store_data_word(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_word_register(emu);
+		*destreg = (*binop)(emu, *destreg, srcval);
+	}
+}
+
+static void
+common_binop_byte_r_rm(struct x86emu *emu,
+    uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
+{
+	uint8_t *destreg, srcval;
+	uint32_t srcoffset;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_byte_register(emu);
+	if (emu->cur_mod != 3) {
+		srcoffset = decode_rl_address(emu);
+		srcval = fetch_data_byte(emu, srcoffset);
+	} else {
+		srcval = *decode_rl_byte_register(emu);
+	}
+	*destreg = (*binop)(emu, *destreg, srcval);
+}
+
+static void
+common_binop_long_rm_r(struct x86emu *emu,
+    uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
+{
+	uint32_t destoffset;
+	uint32_t destval, *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_long_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_long(emu, destoffset);
+		destval = (*binop)(emu, destval, srcval);
+		store_data_long(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_long_register(emu);
+		*destreg = (*binop)(emu, *destreg, srcval);
+	}
+}
+
+static void
+common_binop_word_long_rm_r(struct x86emu *emu,
+    uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
+    uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_binop_long_rm_r(emu, binop32);
+	else
+		common_binop_word_rm_r(emu, binop16);
+}
+
+static void
+common_binop_ns_word_rm_r(struct x86emu *emu,
+    void (*binop)(struct x86emu *, uint16_t, uint16_t))
+{
+	uint32_t destoffset;
+	uint16_t destval, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_word_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_word(emu, destoffset);
+	} else {
+		destval = *decode_rl_word_register(emu);
+	}
+	(*binop)(emu, destval, srcval);
+}
+
+
+static void
+common_binop_ns_long_rm_r(struct x86emu *emu,
+    void (*binop)(struct x86emu *, uint32_t, uint32_t))
+{
+	uint32_t destoffset;
+	uint32_t destval, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_long_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_long(emu, destoffset);
+	} else {
+		destval = *decode_rl_long_register(emu);
+	}
+	(*binop)(emu, destval, srcval);
+}
+
+static void
+common_binop_ns_word_long_rm_r(struct x86emu *emu,
+    void (*binop16)(struct x86emu *, uint16_t, uint16_t),
+    void (*binop32)(struct x86emu *, uint32_t, uint32_t))
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_binop_ns_long_rm_r(emu, binop32);
+	else
+		common_binop_ns_word_rm_r(emu, binop16);
+}
+
+static void
+common_binop_long_r_rm(struct x86emu *emu,
+    uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
+{
+	uint32_t srcoffset;
+	uint32_t *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	if (emu->cur_mod != 3) {
+		srcoffset = decode_rl_address(emu);
+		srcval = fetch_data_long(emu, srcoffset);
+	} else {
+		srcval = *decode_rl_long_register(emu);
+	}
+	*destreg = (*binop)(emu, *destreg, srcval);
+}
+
+static void
+common_binop_word_r_rm(struct x86emu *emu,
+    uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
+{
+	uint32_t srcoffset;
+	uint16_t *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	if (emu->cur_mod != 3) {
+		srcoffset = decode_rl_address(emu);
+		srcval = fetch_data_word(emu, srcoffset);
+	} else {
+		srcval = *decode_rl_word_register(emu);
+	}
+	*destreg = (*binop)(emu, *destreg, srcval);
+}
+
+static void
+common_binop_word_long_r_rm(struct x86emu *emu,
+    uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
+    uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_binop_long_r_rm(emu, binop32);
+	else
+		common_binop_word_r_rm(emu, binop16);
+}
+
+static void
+common_binop_byte_imm(struct x86emu *emu,
+    uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
+{
+	uint8_t srcval;
+
+	srcval = fetch_byte_imm(emu);
+	emu->x86.R_AL = (*binop)(emu, emu->x86.R_AL, srcval);
+}
+
+static void
+common_binop_word_long_imm(struct x86emu *emu,
+    uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
+    uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t srcval;
+
+		srcval = fetch_long_imm(emu);
+		emu->x86.R_EAX = (*binop32)(emu, emu->x86.R_EAX, srcval);
+	} else {
+		uint16_t srcval;
+
+		srcval = fetch_word_imm(emu);
+		emu->x86.R_AX = (*binop16)(emu, emu->x86.R_AX, srcval);
+	}
+}
+
+static void
+common_push_word_long(struct x86emu *emu, union x86emu_register *reg)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		push_long(emu, reg->I32_reg.e_reg);
+	else
+		push_word(emu, reg->I16_reg.x_reg);
+}
+
+static void
+common_pop_word_long(struct x86emu *emu, union x86emu_register *reg)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		reg->I32_reg.e_reg = pop_long(emu);
+	else
+		reg->I16_reg.x_reg = pop_word(emu);
+}
+
+static void
+common_imul_long_IMM(struct x86emu *emu, int byte_imm)
+{
+	uint32_t srcoffset;
+	uint32_t *destreg, srcval;
+	int32_t imm;
+	uint64_t res;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	if (emu->cur_mod != 3) {
+		srcoffset = decode_rl_address(emu);
+		srcval = fetch_data_long(emu, srcoffset);
+	} else {
+		srcval = *decode_rl_long_register(emu);
+	}
+
+	if (byte_imm)
+		imm = (int8_t)fetch_byte_imm(emu);
+	else
+		imm = fetch_long_imm(emu);
+	res = (int32_t)srcval * imm;
+
+	if (res > 0xffffffff) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	}
+	*destreg = (uint32_t)res;
+}
+
+static void
+common_imul_word_IMM(struct x86emu *emu, int byte_imm)
+{
+	uint32_t srcoffset;
+	uint16_t *destreg, srcval;
+	int16_t imm;
+	uint32_t res;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	if (emu->cur_mod != 3) {
+		srcoffset = decode_rl_address(emu);
+		srcval = fetch_data_word(emu, srcoffset);
+	} else {
+		srcval = *decode_rl_word_register(emu);
+	}
+
+	if (byte_imm)
+		imm = (int8_t)fetch_byte_imm(emu);
+	else
+		imm = fetch_word_imm(emu);
+	res = (int16_t)srcval * imm;
+
+	if (res > 0xffff) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	}
+	*destreg = (uint16_t) res;
+}
+
+static void
+common_imul_imm(struct x86emu *emu, int byte_imm)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_imul_long_IMM(emu, byte_imm);
+	else
+		common_imul_word_IMM(emu, byte_imm);
+}
+
+static void
+common_jmp_near(struct x86emu *emu, int cond)
+{
+	int8_t offset;
+	uint16_t target;
+
+	offset = (int8_t) fetch_byte_imm(emu);
+	target = (uint16_t) (emu->x86.R_IP + (int16_t) offset);
+	if (cond)
+		emu->x86.R_IP = target;
+}
+
+static void
+common_load_far_pointer(struct x86emu *emu, uint16_t *seg)
+{
+	uint16_t *dstreg;
+	uint32_t srcoffset;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod == 3)
+		x86emu_halt_sys(emu);
+
+	dstreg = decode_rh_word_register(emu);
+	srcoffset = decode_rl_address(emu);
+	*dstreg = fetch_data_word(emu, srcoffset);
+	*seg = fetch_data_word(emu, srcoffset + 2);
+}
+
+/* Implementation */
+
+/*
+ * REMARKS:
+ * Handles opcode 0x3a
+ */
+static void
+x86emuOp_cmp_byte_R_RM(struct x86emu *emu)
+{
+	uint8_t *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_byte_register(emu);
+	srcval = decode_and_fetch_byte(emu);
+	cmp_byte(emu, *destreg, srcval);
+}
+
+/*
+ * REMARKS:
+ *
+ * Handles opcode 0x3b
+ */
+static void
+x86emuOp32_cmp_word_R_RM(struct x86emu *emu)
+{
+	uint32_t srcval, *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	srcval = decode_and_fetch_long(emu);
+	cmp_long(emu, *destreg, srcval);
+}
+
+static void
+x86emuOp16_cmp_word_R_RM(struct x86emu *emu)
+{
+	uint16_t srcval, *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	srcval = decode_and_fetch_word(emu);
+	cmp_word(emu, *destreg, srcval);
+}
+
+static void
+x86emuOp_cmp_word_R_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_cmp_word_R_RM(emu);
+	else
+		x86emuOp16_cmp_word_R_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x3c
+ */
+static void
+x86emuOp_cmp_byte_AL_IMM(struct x86emu *emu)
+{
+	uint8_t srcval;
+
+	srcval = fetch_byte_imm(emu);
+	cmp_byte(emu, emu->x86.R_AL, srcval);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x3d
+ */
+static void
+x86emuOp32_cmp_word_AX_IMM(struct x86emu *emu)
+{
+	uint32_t srcval;
+
+	srcval = fetch_long_imm(emu);
+	cmp_long(emu, emu->x86.R_EAX, srcval);
+}
+
+static void
+x86emuOp16_cmp_word_AX_IMM(struct x86emu *emu)
+{
+	uint16_t srcval;
+
+	srcval = fetch_word_imm(emu);
+	cmp_word(emu, emu->x86.R_AX, srcval);
+}
+
+static void
+x86emuOp_cmp_word_AX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_cmp_word_AX_IMM(emu);
+	else
+		x86emuOp16_cmp_word_AX_IMM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x60
+ */
+static void
+x86emuOp_push_all(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t old_sp = emu->x86.R_ESP;
+
+		push_long(emu, emu->x86.R_EAX);
+		push_long(emu, emu->x86.R_ECX);
+		push_long(emu, emu->x86.R_EDX);
+		push_long(emu, emu->x86.R_EBX);
+		push_long(emu, old_sp);
+		push_long(emu, emu->x86.R_EBP);
+		push_long(emu, emu->x86.R_ESI);
+		push_long(emu, emu->x86.R_EDI);
+	} else {
+		uint16_t old_sp = emu->x86.R_SP;
+
+		push_word(emu, emu->x86.R_AX);
+		push_word(emu, emu->x86.R_CX);
+		push_word(emu, emu->x86.R_DX);
+		push_word(emu, emu->x86.R_BX);
+		push_word(emu, old_sp);
+		push_word(emu, emu->x86.R_BP);
+		push_word(emu, emu->x86.R_SI);
+		push_word(emu, emu->x86.R_DI);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x61
+ */
+static void
+x86emuOp_pop_all(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		emu->x86.R_EDI = pop_long(emu);
+		emu->x86.R_ESI = pop_long(emu);
+		emu->x86.R_EBP = pop_long(emu);
+		emu->x86.R_ESP += 4;	/* skip ESP */
+		emu->x86.R_EBX = pop_long(emu);
+		emu->x86.R_EDX = pop_long(emu);
+		emu->x86.R_ECX = pop_long(emu);
+		emu->x86.R_EAX = pop_long(emu);
+	} else {
+		emu->x86.R_DI = pop_word(emu);
+		emu->x86.R_SI = pop_word(emu);
+		emu->x86.R_BP = pop_word(emu);
+		emu->x86.R_SP += 2;/* skip SP */
+		emu->x86.R_BX = pop_word(emu);
+		emu->x86.R_DX = pop_word(emu);
+		emu->x86.R_CX = pop_word(emu);
+		emu->x86.R_AX = pop_word(emu);
+	}
+}
+/*opcode 0x62   ILLEGAL OP, calls x86emuOp_illegal_op() */
+/*opcode 0x63   ILLEGAL OP, calls x86emuOp_illegal_op() */
+
+
+/*
+ * REMARKS:
+ * Handles opcode 0x68
+ */
+static void
+x86emuOp_push_word_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t imm;
+
+		imm = fetch_long_imm(emu);
+		push_long(emu, imm);
+	} else {
+		uint16_t imm;
+
+		imm = fetch_word_imm(emu);
+		push_word(emu, imm);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x6a
+ */
+static void
+x86emuOp_push_byte_IMM(struct x86emu *emu)
+{
+	int16_t imm;
+
+	imm = (int8_t) fetch_byte_imm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		push_long(emu, (int32_t) imm);
+	} else {
+		push_word(emu, imm);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x6c and 0x6d
+ */
+static void
+x86emuOp_ins_word(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		ins(emu, 4);
+	} else {
+		ins(emu, 2);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x6f
+ */
+static void
+x86emuOp_outs_word(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		outs(emu, 4);
+	} else {
+		outs(emu, 2);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x7c
+ */
+static void
+x86emuOp_jump_near_L(struct x86emu *emu)
+{
+	int sf, of;
+
+	sf = ACCESS_FLAG(F_SF) != 0;
+	of = ACCESS_FLAG(F_OF) != 0;
+
+	common_jmp_near(emu, sf != of);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x7d
+ */
+static void
+x86emuOp_jump_near_NL(struct x86emu *emu)
+{
+	int sf, of;
+
+	sf = ACCESS_FLAG(F_SF) != 0;
+	of = ACCESS_FLAG(F_OF) != 0;
+
+	common_jmp_near(emu, sf == of);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x7e
+ */
+static void
+x86emuOp_jump_near_LE(struct x86emu *emu)
+{
+	int sf, of;
+
+	sf = ACCESS_FLAG(F_SF) != 0;
+	of = ACCESS_FLAG(F_OF) != 0;
+
+	common_jmp_near(emu, sf != of || ACCESS_FLAG(F_ZF));
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x7f
+ */
+static void
+x86emuOp_jump_near_NLE(struct x86emu *emu)
+{
+	int sf, of;
+
+	sf = ACCESS_FLAG(F_SF) != 0;
+	of = ACCESS_FLAG(F_OF) != 0;
+
+	common_jmp_near(emu, sf == of && !ACCESS_FLAG(F_ZF));
+}
+
+static
+uint8_t(*const opc80_byte_operation[]) (struct x86emu *, uint8_t d, uint8_t s) =
+{
+	add_byte,		/* 00 */
+	or_byte,		/* 01 */
+	adc_byte,		/* 02 */
+	sbb_byte,		/* 03 */
+	and_byte,		/* 04 */
+	sub_byte,		/* 05 */
+	xor_byte,		/* 06 */
+	cmp_byte,		/* 07 */
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0x80
+ */
+static void
+x86emuOp_opc80_byte_RM_IMM(struct x86emu *emu)
+{
+	uint8_t imm, destval;
+
+	/*
+         * Weirdo special case instruction format.  Part of the opcode
+         * held below in "RH".  Doubly nested case would result, except
+         * that the decoded instruction
+         */
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_byte(emu);
+	imm = fetch_byte_imm(emu);
+	destval = (*opc80_byte_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_byte(emu, destval);
+}
+
+static
+uint16_t(* const opc81_word_operation[])
+    (struct x86emu *, uint16_t d, uint16_t s) =
+{
+	add_word,		/* 00 */
+	or_word,		/* 01 */
+	adc_word,		/* 02 */
+	sbb_word,		/* 03 */
+	and_word,		/* 04 */
+	sub_word,		/* 05 */
+	xor_word,		/* 06 */
+	cmp_word,		/* 07 */
+};
+
+static
+uint32_t(* const opc81_long_operation[])
+    (struct x86emu *, uint32_t d, uint32_t s) =
+{
+	add_long,		/* 00 */
+	or_long,		/* 01 */
+	adc_long,		/* 02 */
+	sbb_long,		/* 03 */
+	and_long,		/* 04 */
+	sub_long,		/* 05 */
+	xor_long,		/* 06 */
+	cmp_long,		/* 07 */
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0x81
+ */
+static void
+x86emuOp32_opc81_word_RM_IMM(struct x86emu *emu)
+{
+	uint32_t destval, imm;
+
+	/*
+         * Weirdo special case instruction format.  Part of the opcode
+         * held below in "RH".  Doubly nested case would result, except
+         * that the decoded instruction
+         */
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_long(emu);
+	imm = fetch_long_imm(emu);
+	destval = (*opc81_long_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_long(emu, destval);
+}
+
+static void
+x86emuOp16_opc81_word_RM_IMM(struct x86emu *emu)
+{
+	uint16_t destval, imm;
+
+	/*
+         * Weirdo special case instruction format.  Part of the opcode
+         * held below in "RH".  Doubly nested case would result, except
+         * that the decoded instruction
+         */
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_word(emu);
+	imm = fetch_word_imm(emu);
+	destval = (*opc81_word_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_word(emu, destval);
+}
+
+static void
+x86emuOp_opc81_word_RM_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_opc81_word_RM_IMM(emu);
+	else
+		x86emuOp16_opc81_word_RM_IMM(emu);
+}
+
+static
+uint8_t(* const opc82_byte_operation[])
+    (struct x86emu *, uint8_t s, uint8_t d) =
+{
+	add_byte,		/* 00 */
+	or_byte,		/* 01 *//* YYY UNUSED ???? */
+	adc_byte,		/* 02 */
+	sbb_byte,		/* 03 */
+	and_byte,		/* 04 *//* YYY UNUSED ???? */
+	sub_byte,		/* 05 */
+	xor_byte,		/* 06 *//* YYY UNUSED ???? */
+	cmp_byte,		/* 07 */
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0x82
+ */
+static void
+x86emuOp_opc82_byte_RM_IMM(struct x86emu *emu)
+{
+	uint8_t imm, destval;
+
+	/*
+         * Weirdo special case instruction format.  Part of the opcode
+         * held below in "RH".  Doubly nested case would result, except
+         * that the decoded instruction Similar to opcode 81, except that
+         * the immediate byte is sign extended to a word length.
+         */
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_byte(emu);
+	imm = fetch_byte_imm(emu);
+	destval = (*opc82_byte_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_byte(emu, destval);
+}
+
+static
+uint16_t(* const opc83_word_operation[])
+    (struct x86emu *, uint16_t s, uint16_t d) =
+{
+	add_word,		/* 00 */
+	or_word,		/* 01 *//* YYY UNUSED ???? */
+	adc_word,		/* 02 */
+	sbb_word,		/* 03 */
+	and_word,		/* 04 *//* YYY UNUSED ???? */
+	sub_word,		/* 05 */
+	xor_word,		/* 06 *//* YYY UNUSED ???? */
+	cmp_word,		/* 07 */
+};
+
+static
+uint32_t(* const opc83_long_operation[])
+    (struct x86emu *, uint32_t s, uint32_t d) =
+{
+	add_long,		/* 00 */
+	or_long,		/* 01 *//* YYY UNUSED ???? */
+	adc_long,		/* 02 */
+	sbb_long,		/* 03 */
+	and_long,		/* 04 *//* YYY UNUSED ???? */
+	sub_long,		/* 05 */
+	xor_long,		/* 06 *//* YYY UNUSED ???? */
+	cmp_long,		/* 07 */
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0x83
+ */
+static void
+x86emuOp32_opc83_word_RM_IMM(struct x86emu *emu)
+{
+	uint32_t destval, imm;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_long(emu);
+	imm = (int8_t) fetch_byte_imm(emu);
+	destval = (*opc83_long_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_long(emu, destval);
+}
+
+static void
+x86emuOp16_opc83_word_RM_IMM(struct x86emu *emu)
+{
+	uint16_t destval, imm;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_word(emu);
+	imm = (int8_t) fetch_byte_imm(emu);
+	destval = (*opc83_word_operation[emu->cur_rh]) (emu, destval, imm);
+	if (emu->cur_rh != 7)
+		write_back_word(emu, destval);
+}
+
+static void
+x86emuOp_opc83_word_RM_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_opc83_word_RM_IMM(emu);
+	else
+		x86emuOp16_opc83_word_RM_IMM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x86
+ */
+static void
+x86emuOp_xchg_byte_RM_R(struct x86emu *emu)
+{
+	uint8_t *srcreg, destval, tmp;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_byte(emu);
+	srcreg = decode_rh_byte_register(emu);
+	tmp = destval;
+	destval = *srcreg;
+	*srcreg = tmp;
+	write_back_byte(emu, destval);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x87
+ */
+static void
+x86emuOp32_xchg_word_RM_R(struct x86emu *emu)
+{
+	uint32_t *srcreg, destval, tmp;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_long(emu);
+	srcreg = decode_rh_long_register(emu);
+	tmp = destval;
+	destval = *srcreg;
+	*srcreg = tmp;
+	write_back_long(emu, destval);
+}
+
+static void
+x86emuOp16_xchg_word_RM_R(struct x86emu *emu)
+{
+	uint16_t *srcreg, destval, tmp;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_word(emu);
+	srcreg = decode_rh_word_register(emu);
+	tmp = destval;
+	destval = *srcreg;
+	*srcreg = tmp;
+	write_back_word(emu, destval);
+}
+
+static void
+x86emuOp_xchg_word_RM_R(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_xchg_word_RM_R(emu);
+	else
+		x86emuOp16_xchg_word_RM_R(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x88
+ */
+static void
+x86emuOp_mov_byte_RM_R(struct x86emu *emu)
+{
+	uint8_t *destreg, *srcreg;
+	uint32_t destoffset;
+
+	fetch_decode_modrm(emu);
+	srcreg = decode_rh_byte_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		store_data_byte(emu, destoffset, *srcreg);
+	} else {
+		destreg = decode_rl_byte_register(emu);
+		*destreg = *srcreg;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x89
+ */
+static void
+x86emuOp32_mov_word_RM_R(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint32_t *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_long_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		store_data_long(emu, destoffset, srcval);
+	} else {
+		destreg = decode_rl_long_register(emu);
+		*destreg = srcval;
+	}
+}
+
+static void
+x86emuOp16_mov_word_RM_R(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint16_t *destreg, srcval;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_word_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		store_data_word(emu, destoffset, srcval);
+	} else {
+		destreg = decode_rl_word_register(emu);
+		*destreg = srcval;
+	}
+}
+
+static void
+x86emuOp_mov_word_RM_R(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_mov_word_RM_R(emu);
+	else
+		x86emuOp16_mov_word_RM_R(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8a
+ */
+static void
+x86emuOp_mov_byte_R_RM(struct x86emu *emu)
+{
+	uint8_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_byte_register(emu);
+	*destreg = decode_and_fetch_byte(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8b
+ */
+static void
+x86emuOp_mov_word_R_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t *destreg;
+
+		fetch_decode_modrm(emu);
+		destreg = decode_rh_long_register(emu);
+		*destreg = decode_and_fetch_long(emu);
+	} else {
+		uint16_t *destreg;
+
+		fetch_decode_modrm(emu);
+		destreg = decode_rh_word_register(emu);
+		*destreg = decode_and_fetch_word(emu);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8c
+ */
+static void
+x86emuOp_mov_word_RM_SR(struct x86emu *emu)
+{
+	uint16_t *destreg, srcval;
+	uint32_t destoffset;
+
+	fetch_decode_modrm(emu);
+	srcval = *decode_rh_seg_register(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		store_data_word(emu, destoffset, srcval);
+	} else {
+		destreg = decode_rl_word_register(emu);
+		*destreg = srcval;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8d
+ */
+static void
+x86emuOp_lea_word_R_M(struct x86emu *emu)
+{
+	uint16_t *srcreg;
+	uint32_t destoffset;
+
+/*
+ * TODO: Need to handle address size prefix!
+ *
+ * lea  eax,[eax+ebx*2] ??
+ */
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod == 3)
+		x86emu_halt_sys(emu);
+
+	srcreg = decode_rh_word_register(emu);
+	destoffset = decode_rl_address(emu);
+	*srcreg = (uint16_t) destoffset;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8e
+ */
+static void
+x86emuOp_mov_word_SR_RM(struct x86emu *emu)
+{
+	uint16_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_seg_register(emu);
+	*destreg = decode_and_fetch_word(emu);
+	/*
+         * Clean up, and reset all the R_xSP pointers to the correct
+         * locations.  This is about 3x too much overhead (doing all the
+         * segreg ptrs when only one is needed, but this instruction
+         * *cannot* be that common, and this isn't too much work anyway.
+         */
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x8f
+ */
+static void
+x86emuOp32_pop_RM(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint32_t destval, *destreg;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = pop_long(emu);
+		store_data_long(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_long_register(emu);
+		*destreg = pop_long(emu);
+	}
+}
+
+static void
+x86emuOp16_pop_RM(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint16_t destval, *destreg;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = pop_word(emu);
+		store_data_word(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_word_register(emu);
+		*destreg = pop_word(emu);
+	}
+}
+
+static void
+x86emuOp_pop_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_pop_RM(emu);
+	else
+		x86emuOp16_pop_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x91
+ */
+static void
+x86emuOp_xchg_word_AX_CX(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_ECX;
+		emu->x86.R_ECX = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_CX;
+		emu->x86.R_CX = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x92
+ */
+static void
+x86emuOp_xchg_word_AX_DX(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_EDX;
+		emu->x86.R_EDX = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_DX;
+		emu->x86.R_DX = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x93
+ */
+static void
+x86emuOp_xchg_word_AX_BX(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_EBX;
+		emu->x86.R_EBX = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_BX;
+		emu->x86.R_BX = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x94
+ */
+static void
+x86emuOp_xchg_word_AX_SP(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_ESP;
+		emu->x86.R_ESP = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_SP;
+		emu->x86.R_SP = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x95
+ */
+static void
+x86emuOp_xchg_word_AX_BP(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_EBP;
+		emu->x86.R_EBP = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_BP;
+		emu->x86.R_BP = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x96
+ */
+static void
+x86emuOp_xchg_word_AX_SI(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_ESI;
+		emu->x86.R_ESI = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_SI;
+		emu->x86.R_SI = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x97
+ */
+static void
+x86emuOp_xchg_word_AX_DI(struct x86emu *emu)
+{
+	uint32_t tmp;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		tmp = emu->x86.R_EAX;
+		emu->x86.R_EAX = emu->x86.R_EDI;
+		emu->x86.R_EDI = tmp;
+	} else {
+		tmp = emu->x86.R_AX;
+		emu->x86.R_AX = emu->x86.R_DI;
+		emu->x86.R_DI = (uint16_t) tmp;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x98
+ */
+static void
+x86emuOp_cbw(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		if (emu->x86.R_AX & 0x8000) {
+			emu->x86.R_EAX |= 0xffff0000;
+		} else {
+			emu->x86.R_EAX &= 0x0000ffff;
+		}
+	} else {
+		if (emu->x86.R_AL & 0x80) {
+			emu->x86.R_AH = 0xff;
+		} else {
+			emu->x86.R_AH = 0x0;
+		}
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x99
+ */
+static void
+x86emuOp_cwd(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		if (emu->x86.R_EAX & 0x80000000) {
+			emu->x86.R_EDX = 0xffffffff;
+		} else {
+			emu->x86.R_EDX = 0x0;
+		}
+	} else {
+		if (emu->x86.R_AX & 0x8000) {
+			emu->x86.R_DX = 0xffff;
+		} else {
+			emu->x86.R_DX = 0x0;
+		}
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x9a
+ */
+static void
+x86emuOp_call_far_IMM(struct x86emu *emu)
+{
+	uint16_t farseg, faroff;
+
+	faroff = fetch_word_imm(emu);
+	farseg = fetch_word_imm(emu);
+	/* XXX
+	 *
+	 * Hooked interrupt vectors calling into our "BIOS" will cause problems
+	 * unless all intersegment stuff is checked for BIOS access.  Check
+	 * needed here.  For moment, let it alone. */
+	push_word(emu, emu->x86.R_CS);
+	emu->x86.R_CS = farseg;
+	push_word(emu, emu->x86.R_IP);
+	emu->x86.R_IP = faroff;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x9c
+ */
+static void
+x86emuOp_pushf_word(struct x86emu *emu)
+{
+	uint32_t flags;
+
+	/* clear out *all* bits not representing flags, and turn on real bits */
+	flags = (emu->x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		push_long(emu, flags);
+	} else {
+		push_word(emu, (uint16_t) flags);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x9d
+ */
+static void
+x86emuOp_popf_word(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		emu->x86.R_EFLG = pop_long(emu);
+	} else {
+		emu->x86.R_FLG = pop_word(emu);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x9e
+ */
+static void
+x86emuOp_sahf(struct x86emu *emu)
+{
+	/* clear the lower bits of the flag register */
+	emu->x86.R_FLG &= 0xffffff00;
+	/* or in the AH register into the flags register */
+	emu->x86.R_FLG |= emu->x86.R_AH;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x9f
+ */
+static void
+x86emuOp_lahf(struct x86emu *emu)
+{
+	emu->x86.R_AH = (uint8_t) (emu->x86.R_FLG & 0xff);
+	/* undocumented TC++ behavior??? Nope.  It's documented, but you have
+	 * too look real hard to notice it. */
+	emu->x86.R_AH |= 0x2;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa0
+ */
+static void
+x86emuOp_mov_AL_M_IMM(struct x86emu *emu)
+{
+	uint16_t offset;
+
+	offset = fetch_word_imm(emu);
+	emu->x86.R_AL = fetch_data_byte(emu, offset);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa1
+ */
+static void
+x86emuOp_mov_AX_M_IMM(struct x86emu *emu)
+{
+	uint16_t offset;
+
+	offset = fetch_word_imm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		emu->x86.R_EAX = fetch_data_long(emu, offset);
+	} else {
+		emu->x86.R_AX = fetch_data_word(emu, offset);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa2
+ */
+static void
+x86emuOp_mov_M_AL_IMM(struct x86emu *emu)
+{
+	uint16_t offset;
+
+	offset = fetch_word_imm(emu);
+	store_data_byte(emu, offset, emu->x86.R_AL);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa3
+ */
+static void
+x86emuOp_mov_M_AX_IMM(struct x86emu *emu)
+{
+	uint16_t offset;
+
+	offset = fetch_word_imm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		store_data_long(emu, offset, emu->x86.R_EAX);
+	} else {
+		store_data_word(emu, offset, emu->x86.R_AX);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa4
+ */
+static void
+x86emuOp_movs_byte(struct x86emu *emu)
+{
+	uint8_t val;
+	uint32_t count;
+	int inc;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -1;
+	else
+		inc = 1;
+	count = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		count = emu->x86.R_CX;
+		emu->x86.R_CX = 0;
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	}
+	while (count--) {
+		val = fetch_data_byte(emu, emu->x86.R_SI);
+		store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, val);
+		emu->x86.R_SI += inc;
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa5
+ */
+static void
+x86emuOp_movs_word(struct x86emu *emu)
+{
+	uint32_t val;
+	int inc;
+	uint32_t count;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		inc = 4;
+	else
+		inc = 2;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -inc;
+
+	count = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		count = emu->x86.R_CX;
+		emu->x86.R_CX = 0;
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	}
+	while (count--) {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			val = fetch_data_long(emu, emu->x86.R_SI);
+			store_long(emu, emu->x86.R_ES, emu->x86.R_DI, val);
+		} else {
+			val = fetch_data_word(emu, emu->x86.R_SI);
+			store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    (uint16_t) val);
+		}
+		emu->x86.R_SI += inc;
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa6
+ */
+static void
+x86emuOp_cmps_byte(struct x86emu *emu)
+{
+	int8_t val1, val2;
+	int inc;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -1;
+	else
+		inc = 1;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
+		/* REPE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			val1 = fetch_data_byte(emu, emu->x86.R_SI);
+			val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_byte(emu, val1, val2);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_SI += inc;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF) == 0)
+				break;
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
+	} else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
+		/* REPNE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			val1 = fetch_data_byte(emu, emu->x86.R_SI);
+			val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_byte(emu, val1, val2);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_SI += inc;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF))
+				break;	/* zero flag set means equal */
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
+	} else {
+		val1 = fetch_data_byte(emu, emu->x86.R_SI);
+		val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+		cmp_byte(emu, val1, val2);
+		emu->x86.R_SI += inc;
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa7
+ */
+static void
+x86emuOp_cmps_word(struct x86emu *emu)
+{
+	uint32_t val1, val2;
+	int inc;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		if (ACCESS_FLAG(F_DF))	/* down */
+			inc = -4;
+		else
+			inc = 4;
+	} else {
+		if (ACCESS_FLAG(F_DF))	/* down */
+			inc = -2;
+		else
+			inc = 2;
+	}
+	if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
+		/* REPE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+				val1 = fetch_data_long(emu, emu->x86.R_SI);
+				val2 = fetch_long(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_long(emu, val1, val2);
+			} else {
+				val1 = fetch_data_word(emu, emu->x86.R_SI);
+				val2 = fetch_word(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
+			}
+			emu->x86.R_CX -= 1;
+			emu->x86.R_SI += inc;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF) == 0)
+				break;
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
+	} else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
+		/* REPNE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+				val1 = fetch_data_long(emu, emu->x86.R_SI);
+				val2 = fetch_long(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_long(emu, val1, val2);
+			} else {
+				val1 = fetch_data_word(emu, emu->x86.R_SI);
+				val2 = fetch_word(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
+			}
+			emu->x86.R_CX -= 1;
+			emu->x86.R_SI += inc;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF))
+				break;	/* zero flag set means equal */
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
+	} else {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			val1 = fetch_data_long(emu, emu->x86.R_SI);
+			val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_long(emu, val1, val2);
+		} else {
+			val1 = fetch_data_word(emu, emu->x86.R_SI);
+			val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
+		}
+		emu->x86.R_SI += inc;
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xa9
+ */
+static void
+x86emuOp_test_AX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		test_long(emu, emu->x86.R_EAX, fetch_long_imm(emu));
+	} else {
+		test_word(emu, emu->x86.R_AX, fetch_word_imm(emu));
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xaa
+ */
+static void
+x86emuOp_stos_byte(struct x86emu *emu)
+{
+	int inc;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -1;
+	else
+		inc = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    emu->x86.R_AL);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_DI += inc;
+		}
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	} else {
+		store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AL);
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xab
+ */
+static void
+x86emuOp_stos_word(struct x86emu *emu)
+{
+	int inc;
+	uint32_t count;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		inc = 4;
+	else
+		inc = 2;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -inc;
+
+	count = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		count = emu->x86.R_CX;
+		emu->x86.R_CX = 0;
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	}
+	while (count--) {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    emu->x86.R_EAX);
+		} else {
+			store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    emu->x86.R_AX);
+		}
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xac
+ */
+static void
+x86emuOp_lods_byte(struct x86emu *emu)
+{
+	int inc;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -1;
+	else
+		inc = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_SI += inc;
+		}
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	} else {
+		emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
+		emu->x86.R_SI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xad
+ */
+static void
+x86emuOp_lods_word(struct x86emu *emu)
+{
+	int inc;
+	uint32_t count;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		inc = 4;
+	else
+		inc = 2;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -inc;
+
+	count = 1;
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* move them until CX is ZERO. */
+		count = emu->x86.R_CX;
+		emu->x86.R_CX = 0;
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	}
+	while (count--) {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			emu->x86.R_EAX = fetch_data_long(emu, emu->x86.R_SI);
+		} else {
+			emu->x86.R_AX = fetch_data_word(emu, emu->x86.R_SI);
+		}
+		emu->x86.R_SI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xae
+ */
+static void
+x86emuOp_scas_byte(struct x86emu *emu)
+{
+	int8_t val2;
+	int inc;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -1;
+	else
+		inc = 1;
+	if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
+		/* REPE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_byte(emu, emu->x86.R_AL, val2);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF) == 0)
+				break;
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
+	} else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
+		/* REPNE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_byte(emu, emu->x86.R_AL, val2);
+			emu->x86.R_CX -= 1;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF))
+				break;	/* zero flag set means equal */
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
+	} else {
+		val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
+		cmp_byte(emu, emu->x86.R_AL, val2);
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xaf
+ */
+static void
+x86emuOp_scas_word(struct x86emu *emu)
+{
+	int inc;
+	uint32_t val;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		inc = 4;
+	else
+		inc = 2;
+
+	if (ACCESS_FLAG(F_DF))	/* down */
+		inc = -inc;
+
+	if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
+		/* REPE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+				val = fetch_long(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_long(emu, emu->x86.R_EAX, val);
+			} else {
+				val = fetch_word(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
+			}
+			emu->x86.R_CX -= 1;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF) == 0)
+				break;
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
+	} else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
+		/* REPNE  */
+		/* move them until CX is ZERO. */
+		while (emu->x86.R_CX != 0) {
+			if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+				val = fetch_long(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_long(emu, emu->x86.R_EAX, val);
+			} else {
+				val = fetch_word(emu, emu->x86.R_ES,
+				    emu->x86.R_DI);
+				cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
+			}
+			emu->x86.R_CX -= 1;
+			emu->x86.R_DI += inc;
+			if (ACCESS_FLAG(F_ZF))
+				break;	/* zero flag set means equal */
+		}
+		emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
+	} else {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_long(emu, emu->x86.R_EAX, val);
+		} else {
+			val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
+			cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
+		}
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xb8
+ */
+static void
+x86emuOp_mov_word_AX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_EAX = fetch_long_imm(emu);
+	else
+		emu->x86.R_AX = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xb9
+ */
+static void
+x86emuOp_mov_word_CX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_ECX = fetch_long_imm(emu);
+	else
+		emu->x86.R_CX = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xba
+ */
+static void
+x86emuOp_mov_word_DX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_EDX = fetch_long_imm(emu);
+	else
+		emu->x86.R_DX = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xbb
+ */
+static void
+x86emuOp_mov_word_BX_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_EBX = fetch_long_imm(emu);
+	else
+		emu->x86.R_BX = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xbc
+ */
+static void
+x86emuOp_mov_word_SP_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_ESP = fetch_long_imm(emu);
+	else
+		emu->x86.R_SP = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xbd
+ */
+static void
+x86emuOp_mov_word_BP_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_EBP = fetch_long_imm(emu);
+	else
+		emu->x86.R_BP = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xbe
+ */
+static void
+x86emuOp_mov_word_SI_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_ESI = fetch_long_imm(emu);
+	else
+		emu->x86.R_SI = fetch_word_imm(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xbf
+ */
+static void
+x86emuOp_mov_word_DI_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		emu->x86.R_EDI = fetch_long_imm(emu);
+	else
+		emu->x86.R_DI = fetch_word_imm(emu);
+}
+/* used by opcodes c0, d0, and d2. */
+static
+uint8_t(* const opcD0_byte_operation[])
+    (struct x86emu *, uint8_t d, uint8_t s) =
+{
+	rol_byte,
+	ror_byte,
+	rcl_byte,
+	rcr_byte,
+	shl_byte,
+	shr_byte,
+	shl_byte,		/* sal_byte === shl_byte  by definition */
+	sar_byte,
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc0
+ */
+static void
+x86emuOp_opcC0_byte_RM_MEM(struct x86emu *emu)
+{
+	uint8_t destval, amt;
+
+	/*
+         * Yet another weirdo special case instruction format.  Part of
+         * the opcode held below in "RH".  Doubly nested case would
+         * result, except that the decoded instruction
+         */
+	fetch_decode_modrm(emu);
+	/* know operation, decode the mod byte to find the addressing mode. */
+	destval = decode_and_fetch_byte_imm8(emu, &amt);
+	destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, amt);
+	write_back_byte(emu, destval);
+}
+/* used by opcodes c1, d1, and d3. */
+static
+uint16_t(* const opcD1_word_operation[])
+    (struct x86emu *, uint16_t s, uint8_t d) =
+{
+	rol_word,
+	ror_word,
+	rcl_word,
+	rcr_word,
+	shl_word,
+	shr_word,
+	shl_word,		/* sal_byte === shl_byte  by definition */
+	sar_word,
+};
+/* used by opcodes c1, d1, and d3. */
+static
+uint32_t(* const opcD1_long_operation[])
+    (struct x86emu *, uint32_t s, uint8_t d) =
+{
+	rol_long,
+	ror_long,
+	rcl_long,
+	rcr_long,
+	shl_long,
+	shr_long,
+	shl_long,		/* sal_byte === shl_byte  by definition */
+	sar_long,
+};
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc1
+ */
+static void
+x86emuOp_opcC1_word_RM_MEM(struct x86emu *emu)
+{
+	uint8_t amt;
+
+	/*
+         * Yet another weirdo special case instruction format.  Part of
+         * the opcode held below in "RH".  Doubly nested case would
+         * result, except that the decoded instruction
+         */
+	fetch_decode_modrm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t destval;
+
+		destval = decode_and_fetch_long_imm8(emu, &amt);
+		destval = (*opcD1_long_operation[emu->cur_rh])
+		    (emu, destval, amt);
+		write_back_long(emu, destval);
+	} else {
+		uint16_t destval;
+
+		destval = decode_and_fetch_word_imm8(emu, &amt);
+		destval = (*opcD1_word_operation[emu->cur_rh])
+		    (emu, destval, amt);
+		write_back_word(emu, destval);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc2
+ */
+static void
+x86emuOp_ret_near_IMM(struct x86emu *emu)
+{
+	uint16_t imm;
+
+	imm = fetch_word_imm(emu);
+	emu->x86.R_IP = pop_word(emu);
+	emu->x86.R_SP += imm;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc6
+ */
+static void
+x86emuOp_mov_byte_RM_IMM(struct x86emu *emu)
+{
+	uint8_t *destreg;
+	uint32_t destoffset;
+	uint8_t imm;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh != 0)
+		x86emu_halt_sys(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		imm = fetch_byte_imm(emu);
+		store_data_byte(emu, destoffset, imm);
+	} else {
+		destreg = decode_rl_byte_register(emu);
+		imm = fetch_byte_imm(emu);
+		*destreg = imm;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc7
+ */
+static void
+x86emuOp32_mov_word_RM_IMM(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint32_t imm, *destreg;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh != 0)
+		x86emu_halt_sys(emu);
+
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		imm = fetch_long_imm(emu);
+		store_data_long(emu, destoffset, imm);
+	} else {
+		destreg = decode_rl_long_register(emu);
+		imm = fetch_long_imm(emu);
+		*destreg = imm;
+	}
+}
+
+static void
+x86emuOp16_mov_word_RM_IMM(struct x86emu *emu)
+{
+	uint32_t destoffset;
+	uint16_t imm, *destreg;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh != 0)
+		x86emu_halt_sys(emu);
+
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		imm = fetch_word_imm(emu);
+		store_data_word(emu, destoffset, imm);
+	} else {
+		destreg = decode_rl_word_register(emu);
+		imm = fetch_word_imm(emu);
+		*destreg = imm;
+	}
+}
+
+static void
+x86emuOp_mov_word_RM_IMM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_mov_word_RM_IMM(emu);
+	else
+		x86emuOp16_mov_word_RM_IMM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc8
+ */
+static void
+x86emuOp_enter(struct x86emu *emu)
+{
+	uint16_t local, frame_pointer;
+	uint8_t nesting;
+	int i;
+
+	local = fetch_word_imm(emu);
+	nesting = fetch_byte_imm(emu);
+	push_word(emu, emu->x86.R_BP);
+	frame_pointer = emu->x86.R_SP;
+	if (nesting > 0) {
+		for (i = 1; i < nesting; i++) {
+			emu->x86.R_BP -= 2;
+			push_word(emu, fetch_word(emu, emu->x86.R_SS,
+			    emu->x86.R_BP));
+		}
+		push_word(emu, frame_pointer);
+	}
+	emu->x86.R_BP = frame_pointer;
+	emu->x86.R_SP = (uint16_t) (emu->x86.R_SP - local);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xc9
+ */
+static void
+x86emuOp_leave(struct x86emu *emu)
+{
+	emu->x86.R_SP = emu->x86.R_BP;
+	emu->x86.R_BP = pop_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xca
+ */
+static void
+x86emuOp_ret_far_IMM(struct x86emu *emu)
+{
+	uint16_t imm;
+
+	imm = fetch_word_imm(emu);
+	emu->x86.R_IP = pop_word(emu);
+	emu->x86.R_CS = pop_word(emu);
+	emu->x86.R_SP += imm;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xcb
+ */
+static void
+x86emuOp_ret_far(struct x86emu *emu)
+{
+	emu->x86.R_IP = pop_word(emu);
+	emu->x86.R_CS = pop_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xcc
+ */
+static void
+x86emuOp_int3(struct x86emu *emu)
+{
+	x86emu_intr_dispatch(emu, 3);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xcd
+ */
+static void
+x86emuOp_int_IMM(struct x86emu *emu)
+{
+	uint8_t intnum;
+
+	intnum = fetch_byte_imm(emu);
+	x86emu_intr_dispatch(emu, intnum);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xce
+ */
+static void
+x86emuOp_into(struct x86emu *emu)
+{
+	if (ACCESS_FLAG(F_OF))
+		x86emu_intr_dispatch(emu, 4);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xcf
+ */
+static void
+x86emuOp_iret(struct x86emu *emu)
+{
+	emu->x86.R_IP = pop_word(emu);
+	emu->x86.R_CS = pop_word(emu);
+	emu->x86.R_FLG = pop_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd0
+ */
+static void
+x86emuOp_opcD0_byte_RM_1(struct x86emu *emu)
+{
+	uint8_t destval;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_byte(emu);
+	destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, 1);
+	write_back_byte(emu, destval);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd1
+ */
+static void
+x86emuOp_opcD1_word_RM_1(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t destval;
+
+		fetch_decode_modrm(emu);
+		destval = decode_and_fetch_long(emu);
+		destval = (*opcD1_long_operation[emu->cur_rh])(emu, destval, 1);
+		write_back_long(emu, destval);
+	} else {
+		uint16_t destval;
+
+		fetch_decode_modrm(emu);
+		destval = decode_and_fetch_word(emu);
+		destval = (*opcD1_word_operation[emu->cur_rh])(emu, destval, 1);
+		write_back_word(emu, destval);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd2
+ */
+static void
+x86emuOp_opcD2_byte_RM_CL(struct x86emu *emu)
+{
+	uint8_t destval;
+
+	fetch_decode_modrm(emu);
+	destval = decode_and_fetch_byte(emu);
+	destval = (*opcD0_byte_operation[emu->cur_rh])
+	    (emu, destval, emu->x86.R_CL);
+	write_back_byte(emu, destval);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd3
+ */
+static void
+x86emuOp_opcD3_word_RM_CL(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		uint32_t destval;
+
+		fetch_decode_modrm(emu);
+		destval = decode_and_fetch_long(emu);
+		destval = (*opcD1_long_operation[emu->cur_rh])
+		    (emu, destval, emu->x86.R_CL);
+		write_back_long(emu, destval);
+	} else {
+		uint16_t destval;
+
+		fetch_decode_modrm(emu);
+		destval = decode_and_fetch_word(emu);
+		destval = (*opcD1_word_operation[emu->cur_rh])
+		    (emu, destval, emu->x86.R_CL);
+		write_back_word(emu, destval);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd4
+ */
+static void
+x86emuOp_aam(struct x86emu *emu)
+{
+	uint8_t a;
+
+	a = fetch_byte_imm(emu);	/* this is a stupid encoding. */
+	if (a != 10) {
+		/* fix: add base decoding aam_word(uint8_t val, int base a) */
+		x86emu_halt_sys(emu);
+	}
+	/* note the type change here --- returning AL and AH in AX. */
+	emu->x86.R_AX = aam_word(emu, emu->x86.R_AL);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd5
+ */
+static void
+x86emuOp_aad(struct x86emu *emu)
+{
+	uint8_t a;
+
+	a = fetch_byte_imm(emu);
+	if (a != 10) {
+		/* fix: add base decoding aad_word(uint16_t val, int base a) */
+		x86emu_halt_sys(emu);
+	}
+	emu->x86.R_AX = aad_word(emu, emu->x86.R_AX);
+}
+/* opcode 0xd6 ILLEGAL OPCODE */
+
+
+/*
+ * REMARKS:
+ * Handles opcode 0xd7
+ */
+static void
+x86emuOp_xlat(struct x86emu *emu)
+{
+	uint16_t addr;
+
+	addr = (uint16_t) (emu->x86.R_BX + (uint8_t) emu->x86.R_AL);
+	emu->x86.R_AL = fetch_data_byte(emu, addr);
+}
+
+/* opcode=0xd8 */
+static void
+x86emuOp_esc_coprocess_d8(struct x86emu *emu)
+{
+}
+/* opcode=0xd9 */
+static void
+x86emuOp_esc_coprocess_d9(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xda */
+static void
+x86emuOp_esc_coprocess_da(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xdb */
+static void
+x86emuOp_esc_coprocess_db(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xdc */
+static void
+x86emuOp_esc_coprocess_dc(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xdd */
+static void
+x86emuOp_esc_coprocess_dd(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xde */
+static void
+x86emuOp_esc_coprocess_de(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+/* opcode=0xdf */
+static void
+x86emuOp_esc_coprocess_df(struct x86emu *emu)
+{
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3)
+		decode_rl_address(emu);
+}
+
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe0
+ */
+static void
+x86emuOp_loopne(struct x86emu *emu)
+{
+	int16_t ip;
+
+	ip = (int8_t) fetch_byte_imm(emu);
+	ip += (int16_t) emu->x86.R_IP;
+	emu->x86.R_CX -= 1;
+	if (emu->x86.R_CX != 0 && !ACCESS_FLAG(F_ZF))	/* CX != 0 and !ZF */
+		emu->x86.R_IP = ip;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe1
+ */
+static void
+x86emuOp_loope(struct x86emu *emu)
+{
+	int16_t ip;
+
+	ip = (int8_t) fetch_byte_imm(emu);
+	ip += (int16_t) emu->x86.R_IP;
+	emu->x86.R_CX -= 1;
+	if (emu->x86.R_CX != 0 && ACCESS_FLAG(F_ZF))	/* CX != 0 and ZF */
+		emu->x86.R_IP = ip;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe2
+ */
+static void
+x86emuOp_loop(struct x86emu *emu)
+{
+	int16_t ip;
+
+	ip = (int8_t) fetch_byte_imm(emu);
+	ip += (int16_t) emu->x86.R_IP;
+	emu->x86.R_CX -= 1;
+	if (emu->x86.R_CX != 0)
+		emu->x86.R_IP = ip;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe3
+ */
+static void
+x86emuOp_jcxz(struct x86emu *emu)
+{
+	uint16_t target;
+	int8_t offset;
+
+	/* jump to byte offset if overflow flag is set */
+	offset = (int8_t) fetch_byte_imm(emu);
+	target = (uint16_t) (emu->x86.R_IP + offset);
+	if (emu->x86.R_CX == 0)
+		emu->x86.R_IP = target;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe4
+ */
+static void
+x86emuOp_in_byte_AL_IMM(struct x86emu *emu)
+{
+	uint8_t port;
+
+	port = (uint8_t) fetch_byte_imm(emu);
+	emu->x86.R_AL = (*emu->emu_inb) (emu, port);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe5
+ */
+static void
+x86emuOp_in_word_AX_IMM(struct x86emu *emu)
+{
+	uint8_t port;
+
+	port = (uint8_t) fetch_byte_imm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		emu->x86.R_EAX = (*emu->emu_inl) (emu, port);
+	} else {
+		emu->x86.R_AX = (*emu->emu_inw) (emu, port);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe6
+ */
+static void
+x86emuOp_out_byte_IMM_AL(struct x86emu *emu)
+{
+	uint8_t port;
+
+	port = (uint8_t) fetch_byte_imm(emu);
+	(*emu->emu_outb) (emu, port, emu->x86.R_AL);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe7
+ */
+static void
+x86emuOp_out_word_IMM_AX(struct x86emu *emu)
+{
+	uint8_t port;
+
+	port = (uint8_t) fetch_byte_imm(emu);
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		(*emu->emu_outl) (emu, port, emu->x86.R_EAX);
+	} else {
+		(*emu->emu_outw) (emu, port, emu->x86.R_AX);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe8
+ */
+static void
+x86emuOp_call_near_IMM(struct x86emu *emu)
+{
+	int16_t ip;
+
+	ip = (int16_t) fetch_word_imm(emu);
+	ip += (int16_t) emu->x86.R_IP;	/* CHECK SIGN */
+	push_word(emu, emu->x86.R_IP);
+	emu->x86.R_IP = ip;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xe9
+ */
+static void
+x86emuOp_jump_near_IMM(struct x86emu *emu)
+{
+	int ip;
+
+	ip = (int16_t) fetch_word_imm(emu);
+	ip += (int16_t) emu->x86.R_IP;
+	emu->x86.R_IP = (uint16_t) ip;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xea
+ */
+static void
+x86emuOp_jump_far_IMM(struct x86emu *emu)
+{
+	uint16_t cs, ip;
+
+	ip = fetch_word_imm(emu);
+	cs = fetch_word_imm(emu);
+	emu->x86.R_IP = ip;
+	emu->x86.R_CS = cs;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xeb
+ */
+static void
+x86emuOp_jump_byte_IMM(struct x86emu *emu)
+{
+	uint16_t target;
+	int8_t offset;
+
+	offset = (int8_t) fetch_byte_imm(emu);
+	target = (uint16_t) (emu->x86.R_IP + offset);
+	emu->x86.R_IP = target;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xec
+ */
+static void
+x86emuOp_in_byte_AL_DX(struct x86emu *emu)
+{
+	emu->x86.R_AL = (*emu->emu_inb) (emu, emu->x86.R_DX);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xed
+ */
+static void
+x86emuOp_in_word_AX_DX(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		emu->x86.R_EAX = (*emu->emu_inl) (emu, emu->x86.R_DX);
+	} else {
+		emu->x86.R_AX = (*emu->emu_inw) (emu, emu->x86.R_DX);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xee
+ */
+static void
+x86emuOp_out_byte_DX_AL(struct x86emu *emu)
+{
+	(*emu->emu_outb) (emu, emu->x86.R_DX, emu->x86.R_AL);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xef
+ */
+static void
+x86emuOp_out_word_DX_AX(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+		(*emu->emu_outl) (emu, emu->x86.R_DX, emu->x86.R_EAX);
+	} else {
+		(*emu->emu_outw) (emu, emu->x86.R_DX, emu->x86.R_AX);
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xf0
+ */
+static void
+x86emuOp_lock(struct x86emu *emu)
+{
+}
+/*opcode 0xf1 ILLEGAL OPERATION */
+
+
+/*
+ * REMARKS:
+ * Handles opcode 0xf5
+ */
+static void
+x86emuOp_cmc(struct x86emu *emu)
+{
+	if (ACCESS_FLAG(F_CF))
+		CLEAR_FLAG(F_CF);
+	else
+		SET_FLAG(F_CF);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xf6
+ */
+static void
+x86emuOp_opcF6_byte_RM(struct x86emu *emu)
+{
+	uint8_t destval, srcval;
+
+	/* long, drawn out code follows.  Double switch for a total of 32
+	 * cases.  */
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh == 1)
+		x86emu_halt_sys(emu);
+
+	if (emu->cur_rh == 0) {
+		destval = decode_and_fetch_byte_imm8(emu, &srcval);
+		test_byte(emu, destval, srcval);
+		return;
+	}
+	destval = decode_and_fetch_byte(emu);
+	switch (emu->cur_rh) {
+	case 2:
+		destval = ~destval;
+		write_back_byte(emu, destval);
+		break;
+	case 3:
+		destval = neg_byte(emu, destval);
+		write_back_byte(emu, destval);
+		break;
+	case 4:
+		mul_byte(emu, destval);
+		break;
+	case 5:
+		imul_byte(emu, destval);
+		break;
+	case 6:
+		div_byte(emu, destval);
+		break;
+	case 7:
+		idiv_byte(emu, destval);
+		break;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xf7
+ */
+static void
+x86emuOp32_opcF7_word_RM(struct x86emu *emu)
+{
+	uint32_t destval, srcval;
+
+	/* long, drawn out code follows.  Double switch for a total of 32
+	 * cases.  */
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh == 1)
+		x86emu_halt_sys(emu);
+
+	if (emu->cur_rh == 0) {
+		if (emu->cur_mod != 3) {
+			uint32_t destoffset;
+
+			destoffset = decode_rl_address(emu);
+			srcval = fetch_long_imm(emu);
+			destval = fetch_data_long(emu, destoffset);
+		} else {
+			srcval = fetch_long_imm(emu);
+			destval = *decode_rl_long_register(emu);
+		}
+		test_long(emu, destval, srcval);
+		return;
+	}
+	destval = decode_and_fetch_long(emu);
+	switch (emu->cur_rh) {
+	case 2:
+		destval = ~destval;
+		write_back_long(emu, destval);
+		break;
+	case 3:
+		destval = neg_long(emu, destval);
+		write_back_long(emu, destval);
+		break;
+	case 4:
+		mul_long(emu, destval);
+		break;
+	case 5:
+		imul_long(emu, destval);
+		break;
+	case 6:
+		div_long(emu, destval);
+		break;
+	case 7:
+		idiv_long(emu, destval);
+		break;
+	}
+}
+static void
+x86emuOp16_opcF7_word_RM(struct x86emu *emu)
+{
+	uint16_t destval, srcval;
+
+	/* long, drawn out code follows.  Double switch for a total of 32
+	 * cases.  */
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh == 1)
+		x86emu_halt_sys(emu);
+
+	if (emu->cur_rh == 0) {
+		if (emu->cur_mod != 3) {
+			uint32_t destoffset;
+
+			destoffset = decode_rl_address(emu);
+			srcval = fetch_word_imm(emu);
+			destval = fetch_data_word(emu, destoffset);
+		} else {
+			srcval = fetch_word_imm(emu);
+			destval = *decode_rl_word_register(emu);
+		}
+		test_word(emu, destval, srcval);
+		return;
+	}
+	destval = decode_and_fetch_word(emu);
+	switch (emu->cur_rh) {
+	case 2:
+		destval = ~destval;
+		write_back_word(emu, destval);
+		break;
+	case 3:
+		destval = neg_word(emu, destval);
+		write_back_word(emu, destval);
+		break;
+	case 4:
+		mul_word(emu, destval);
+		break;
+	case 5:
+		imul_word(emu, destval);
+		break;
+	case 6:
+		div_word(emu, destval);
+		break;
+	case 7:
+		idiv_word(emu, destval);
+		break;
+	}
+}
+static void
+x86emuOp_opcF7_word_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp32_opcF7_word_RM(emu);
+	else
+		x86emuOp16_opcF7_word_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xfe
+ */
+static void
+x86emuOp_opcFE_byte_RM(struct x86emu *emu)
+{
+	uint8_t destval;
+	uint32_t destoffset;
+	uint8_t *destreg;
+
+	/* Yet another special case instruction. */
+	fetch_decode_modrm(emu);
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		switch (emu->cur_rh) {
+		case 0:	/* inc word ptr ... */
+			destval = fetch_data_byte(emu, destoffset);
+			destval = inc_byte(emu, destval);
+			store_data_byte(emu, destoffset, destval);
+			break;
+		case 1:	/* dec word ptr ... */
+			destval = fetch_data_byte(emu, destoffset);
+			destval = dec_byte(emu, destval);
+			store_data_byte(emu, destoffset, destval);
+			break;
+		}
+	} else {
+		destreg = decode_rl_byte_register(emu);
+		switch (emu->cur_rh) {
+		case 0:
+			*destreg = inc_byte(emu, *destreg);
+			break;
+		case 1:
+			*destreg = dec_byte(emu, *destreg);
+			break;
+		}
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0xff
+ */
+static void
+x86emuOp32_opcFF_word_RM(struct x86emu *emu)
+{
+	uint32_t destoffset = 0;
+	uint32_t destval, *destreg;
+
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_long(emu, destoffset);
+		switch (emu->cur_rh) {
+		case 0:	/* inc word ptr ... */
+			destval = inc_long(emu, destval);
+			store_data_long(emu, destoffset, destval);
+			break;
+		case 1:	/* dec word ptr ... */
+			destval = dec_long(emu, destval);
+			store_data_long(emu, destoffset, destval);
+			break;
+		case 6:	/* push word ptr ... */
+			push_long(emu, destval);
+			break;
+		}
+	} else {
+		destreg = decode_rl_long_register(emu);
+		switch (emu->cur_rh) {
+		case 0:
+			*destreg = inc_long(emu, *destreg);
+			break;
+		case 1:
+			*destreg = dec_long(emu, *destreg);
+			break;
+		case 6:
+			push_long(emu, *destreg);
+			break;
+		}
+	}
+}
+
+static void
+x86emuOp16_opcFF_word_RM(struct x86emu *emu)
+{
+	uint32_t destoffset = 0;
+	uint16_t *destreg;
+	uint16_t destval;
+
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_word(emu, destoffset);
+		switch (emu->cur_rh) {
+		case 0:
+			destval = inc_word(emu, destval);
+			store_data_word(emu, destoffset, destval);
+			break;
+		case 1:	/* dec word ptr ... */
+			destval = dec_word(emu, destval);
+			store_data_word(emu, destoffset, destval);
+			break;
+		case 6:	/* push word ptr ... */
+			push_word(emu, destval);
+			break;
+		}
+	} else {
+		destreg = decode_rl_word_register(emu);
+		switch (emu->cur_rh) {
+		case 0:
+			*destreg = inc_word(emu, *destreg);
+			break;
+		case 1:
+			*destreg = dec_word(emu, *destreg);
+			break;
+		case 6:
+			push_word(emu, *destreg);
+			break;
+		}
+	}
+}
+
+static void
+x86emuOp_opcFF_word_RM(struct x86emu *emu)
+{
+	uint32_t destoffset = 0;
+	uint16_t destval, destval2;
+
+	/* Yet another special case instruction. */
+	fetch_decode_modrm(emu);
+	if ((emu->cur_mod == 3 && (emu->cur_rh == 3 || emu->cur_rh == 5)) ||
+	    emu->cur_rh == 7)
+		x86emu_halt_sys(emu);
+	if (emu->cur_rh == 0 || emu->cur_rh == 1 || emu->cur_rh == 6) {
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+			x86emuOp32_opcFF_word_RM(emu);
+		else
+			x86emuOp16_opcFF_word_RM(emu);
+		return;
+	}
+
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		destval = fetch_data_word(emu, destoffset);
+		switch (emu->cur_rh) {
+		case 3:	/* call far ptr ... */
+			destval2 = fetch_data_word(emu, destoffset + 2);
+			push_word(emu, emu->x86.R_CS);
+			emu->x86.R_CS = destval2;
+			push_word(emu, emu->x86.R_IP);
+			emu->x86.R_IP = destval;
+			break;
+		case 5:	/* jmp far ptr ... */
+			destval2 = fetch_data_word(emu, destoffset + 2);
+			emu->x86.R_IP = destval;
+			emu->x86.R_CS = destval2;
+			break;
+		}
+	} else {
+		destval = *decode_rl_word_register(emu);
+	}
+
+	switch (emu->cur_rh) {
+	case 2: /* call word ptr */
+		push_word(emu, emu->x86.R_IP);
+		emu->x86.R_IP = destval;
+		break;
+	case 4: /* jmp */
+		emu->x86.R_IP = destval;
+		break;
+	}
+}
+
+/*
+ *  * Single byte operation code table:
+ */
+static void
+x86emu_exec_one_byte(struct x86emu * emu)
+{
+	uint8_t op1;
+
+	op1 = fetch_byte_imm(emu);
+
+	switch (op1) {
+	case 0x00:
+		common_binop_byte_rm_r(emu, add_byte);
+		break;
+	case 0x01:
+		common_binop_word_long_rm_r(emu, add_word, add_long);
+		break;
+	case 0x02:
+		common_binop_byte_r_rm(emu, add_byte);
+		break;
+	case 0x03:
+		common_binop_word_long_r_rm(emu, add_word, add_long);
+		break;
+	case 0x04:
+		common_binop_byte_imm(emu, add_byte);
+		break;
+	case 0x05:
+		common_binop_word_long_imm(emu, add_word, add_long);
+		break;
+	case 0x06:
+		push_word(emu, emu->x86.R_ES);
+		break;
+	case 0x07:
+		emu->x86.R_ES = pop_word(emu);
+		break;
+
+	case 0x08:
+		common_binop_byte_rm_r(emu, or_byte);
+		break;
+	case 0x09:
+		common_binop_word_long_rm_r(emu, or_word, or_long);
+		break;
+	case 0x0a:
+		common_binop_byte_r_rm(emu, or_byte);
+		break;
+	case 0x0b:
+		common_binop_word_long_r_rm(emu, or_word, or_long);
+		break;
+	case 0x0c:
+		common_binop_byte_imm(emu, or_byte);
+		break;
+	case 0x0d:
+		common_binop_word_long_imm(emu, or_word, or_long);
+		break;
+	case 0x0e:
+		push_word(emu, emu->x86.R_CS);
+		break;
+	case 0x0f:
+		x86emu_exec_two_byte(emu);
+		break;
+
+	case 0x10:
+		common_binop_byte_rm_r(emu, adc_byte);
+		break;
+	case 0x11:
+		common_binop_word_long_rm_r(emu, adc_word, adc_long);
+		break;
+	case 0x12:
+		common_binop_byte_r_rm(emu, adc_byte);
+		break;
+	case 0x13:
+		common_binop_word_long_r_rm(emu, adc_word, adc_long);
+		break;
+	case 0x14:
+		common_binop_byte_imm(emu, adc_byte);
+		break;
+	case 0x15:
+		common_binop_word_long_imm(emu, adc_word, adc_long);
+		break;
+	case 0x16:
+		push_word(emu, emu->x86.R_SS);
+		break;
+	case 0x17:
+		emu->x86.R_SS = pop_word(emu);
+		break;
+
+	case 0x18:
+		common_binop_byte_rm_r(emu, sbb_byte);
+		break;
+	case 0x19:
+		common_binop_word_long_rm_r(emu, sbb_word, sbb_long);
+		break;
+	case 0x1a:
+		common_binop_byte_r_rm(emu, sbb_byte);
+		break;
+	case 0x1b:
+		common_binop_word_long_r_rm(emu, sbb_word, sbb_long);
+		break;
+	case 0x1c:
+		common_binop_byte_imm(emu, sbb_byte);
+		break;
+	case 0x1d:
+		common_binop_word_long_imm(emu, sbb_word, sbb_long);
+		break;
+	case 0x1e:
+		push_word(emu, emu->x86.R_DS);
+		break;
+	case 0x1f:
+		emu->x86.R_DS = pop_word(emu);
+		break;
+
+	case 0x20:
+		common_binop_byte_rm_r(emu, and_byte);
+		break;
+	case 0x21:
+		common_binop_word_long_rm_r(emu, and_word, and_long);
+		break;
+	case 0x22:
+		common_binop_byte_r_rm(emu, and_byte);
+		break;
+	case 0x23:
+		common_binop_word_long_r_rm(emu, and_word, and_long);
+		break;
+	case 0x24:
+		common_binop_byte_imm(emu, and_byte);
+		break;
+	case 0x25:
+		common_binop_word_long_imm(emu, and_word, and_long);
+		break;
+	case 0x26:
+		emu->x86.mode |= SYSMODE_SEGOVR_ES;
+		break;
+	case 0x27:
+		emu->x86.R_AL = daa_byte(emu, emu->x86.R_AL);
+		break;
+
+	case 0x28:
+		common_binop_byte_rm_r(emu, sub_byte);
+		break;
+	case 0x29:
+		common_binop_word_long_rm_r(emu, sub_word, sub_long);
+		break;
+	case 0x2a:
+		common_binop_byte_r_rm(emu, sub_byte);
+		break;
+	case 0x2b:
+		common_binop_word_long_r_rm(emu, sub_word, sub_long);
+		break;
+	case 0x2c:
+		common_binop_byte_imm(emu, sub_byte);
+		break;
+	case 0x2d:
+		common_binop_word_long_imm(emu, sub_word, sub_long);
+		break;
+	case 0x2e:
+		emu->x86.mode |= SYSMODE_SEGOVR_CS;
+		break;
+	case 0x2f:
+		emu->x86.R_AL = das_byte(emu, emu->x86.R_AL);
+		break;
+
+	case 0x30:
+		common_binop_byte_rm_r(emu, xor_byte);
+		break;
+	case 0x31:
+		common_binop_word_long_rm_r(emu, xor_word, xor_long);
+		break;
+	case 0x32:
+		common_binop_byte_r_rm(emu, xor_byte);
+		break;
+	case 0x33:
+		common_binop_word_long_r_rm(emu, xor_word, xor_long);
+		break;
+	case 0x34:
+		common_binop_byte_imm(emu, xor_byte);
+		break;
+	case 0x35:
+		common_binop_word_long_imm(emu, xor_word, xor_long);
+		break;
+	case 0x36:
+		emu->x86.mode |= SYSMODE_SEGOVR_SS;
+		break;
+	case 0x37:
+		emu->x86.R_AX = aaa_word(emu, emu->x86.R_AX);
+		break;
+
+	case 0x38:
+		common_binop_ns_byte_rm_r(emu, cmp_byte_no_return);
+		break;
+	case 0x39:
+		common_binop_ns_word_long_rm_r(emu, cmp_word_no_return,
+		    cmp_long_no_return);
+		break;
+	case 0x3a:
+		x86emuOp_cmp_byte_R_RM(emu);
+		break;
+	case 0x3b:
+		x86emuOp_cmp_word_R_RM(emu);
+		break;
+	case 0x3c:
+		x86emuOp_cmp_byte_AL_IMM(emu);
+		break;
+	case 0x3d:
+		x86emuOp_cmp_word_AX_IMM(emu);
+		break;
+	case 0x3e:
+		emu->x86.mode |= SYSMODE_SEGOVR_DS;
+		break;
+	case 0x3f:
+		emu->x86.R_AX = aas_word(emu, emu->x86.R_AX);
+		break;
+
+	case 0x40:
+		common_inc_word_long(emu, &emu->x86.register_a);
+		break;
+	case 0x41:
+		common_inc_word_long(emu, &emu->x86.register_c);
+		break;
+	case 0x42:
+		common_inc_word_long(emu, &emu->x86.register_d);
+		break;
+	case 0x43:
+		common_inc_word_long(emu, &emu->x86.register_b);
+		break;
+	case 0x44:
+		common_inc_word_long(emu, &emu->x86.register_sp);
+		break;
+	case 0x45:
+		common_inc_word_long(emu, &emu->x86.register_bp);
+		break;
+	case 0x46:
+		common_inc_word_long(emu, &emu->x86.register_si);
+		break;
+	case 0x47:
+		common_inc_word_long(emu, &emu->x86.register_di);
+		break;
+
+	case 0x48:
+		common_dec_word_long(emu, &emu->x86.register_a);
+		break;
+	case 0x49:
+		common_dec_word_long(emu, &emu->x86.register_c);
+		break;
+	case 0x4a:
+		common_dec_word_long(emu, &emu->x86.register_d);
+		break;
+	case 0x4b:
+		common_dec_word_long(emu, &emu->x86.register_b);
+		break;
+	case 0x4c:
+		common_dec_word_long(emu, &emu->x86.register_sp);
+		break;
+	case 0x4d:
+		common_dec_word_long(emu, &emu->x86.register_bp);
+		break;
+	case 0x4e:
+		common_dec_word_long(emu, &emu->x86.register_si);
+		break;
+	case 0x4f:
+		common_dec_word_long(emu, &emu->x86.register_di);
+		break;
+
+	case 0x50:
+		common_push_word_long(emu, &emu->x86.register_a);
+		break;
+	case 0x51:
+		common_push_word_long(emu, &emu->x86.register_c);
+		break;
+	case 0x52:
+		common_push_word_long(emu, &emu->x86.register_d);
+		break;
+	case 0x53:
+		common_push_word_long(emu, &emu->x86.register_b);
+		break;
+	case 0x54:
+		common_push_word_long(emu, &emu->x86.register_sp);
+		break;
+	case 0x55:
+		common_push_word_long(emu, &emu->x86.register_bp);
+		break;
+	case 0x56:
+		common_push_word_long(emu, &emu->x86.register_si);
+		break;
+	case 0x57:
+		common_push_word_long(emu, &emu->x86.register_di);
+		break;
+
+	case 0x58:
+		common_pop_word_long(emu, &emu->x86.register_a);
+		break;
+	case 0x59:
+		common_pop_word_long(emu, &emu->x86.register_c);
+		break;
+	case 0x5a:
+		common_pop_word_long(emu, &emu->x86.register_d);
+		break;
+	case 0x5b:
+		common_pop_word_long(emu, &emu->x86.register_b);
+		break;
+	case 0x5c:
+		common_pop_word_long(emu, &emu->x86.register_sp);
+		break;
+	case 0x5d:
+		common_pop_word_long(emu, &emu->x86.register_bp);
+		break;
+	case 0x5e:
+		common_pop_word_long(emu, &emu->x86.register_si);
+		break;
+	case 0x5f:
+		common_pop_word_long(emu, &emu->x86.register_di);
+		break;
+
+	case 0x60:
+		x86emuOp_push_all(emu);
+		break;
+	case 0x61:
+		x86emuOp_pop_all(emu);
+		break;
+	/* 0x62 bound */
+	/* 0x63 arpl */
+	case 0x64:
+		emu->x86.mode |= SYSMODE_SEGOVR_FS;
+		break;
+	case 0x65:
+		emu->x86.mode |= SYSMODE_SEGOVR_GS;
+		break;
+	case 0x66:
+		emu->x86.mode |= SYSMODE_PREFIX_DATA;
+		break;
+	case 0x67:
+		emu->x86.mode |= SYSMODE_PREFIX_ADDR;
+		break;
+
+	case 0x68:
+		x86emuOp_push_word_IMM(emu);
+		break;
+	case 0x69:
+		common_imul_imm(emu, 0);
+		break;
+	case 0x6a:
+		x86emuOp_push_byte_IMM(emu);
+		break;
+	case 0x6b:
+		common_imul_imm(emu, 1);
+		break;
+	case 0x6c:
+		ins(emu, 1);
+		break;
+	case 0x6d:
+		x86emuOp_ins_word(emu);
+		break;
+	case 0x6e:
+		outs(emu, 1);
+		break;
+	case 0x6f:
+		x86emuOp_outs_word(emu);
+		break;
+
+	case 0x70:
+		common_jmp_near(emu, ACCESS_FLAG(F_OF));
+		break;
+	case 0x71:
+		common_jmp_near(emu, !ACCESS_FLAG(F_OF));
+		break;
+	case 0x72:
+		common_jmp_near(emu, ACCESS_FLAG(F_CF));
+		break;
+	case 0x73:
+		common_jmp_near(emu, !ACCESS_FLAG(F_CF));
+		break;
+	case 0x74:
+		common_jmp_near(emu, ACCESS_FLAG(F_ZF));
+		break;
+	case 0x75:
+		common_jmp_near(emu, !ACCESS_FLAG(F_ZF));
+		break;
+	case 0x76:
+		common_jmp_near(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+		break;
+	case 0x77:
+		common_jmp_near(emu, !ACCESS_FLAG(F_CF) && !ACCESS_FLAG(F_ZF));
+		break;
+
+	case 0x78:
+		common_jmp_near(emu, ACCESS_FLAG(F_SF));
+		break;
+	case 0x79:
+		common_jmp_near(emu, !ACCESS_FLAG(F_SF));
+		break;
+	case 0x7a:
+		common_jmp_near(emu, ACCESS_FLAG(F_PF));
+		break;
+	case 0x7b:
+		common_jmp_near(emu, !ACCESS_FLAG(F_PF));
+		break;
+	case 0x7c:
+		x86emuOp_jump_near_L(emu);
+		break;
+	case 0x7d:
+		x86emuOp_jump_near_NL(emu);
+		break;
+	case 0x7e:
+		x86emuOp_jump_near_LE(emu);
+		break;
+	case 0x7f:
+		x86emuOp_jump_near_NLE(emu);
+		break;
+
+	case 0x80:
+		x86emuOp_opc80_byte_RM_IMM(emu);
+		break;
+	case 0x81:
+		x86emuOp_opc81_word_RM_IMM(emu);
+		break;
+	case 0x82:
+		x86emuOp_opc82_byte_RM_IMM(emu);
+		break;
+	case 0x83:
+		x86emuOp_opc83_word_RM_IMM(emu);
+		break;
+	case 0x84:
+		common_binop_ns_byte_rm_r(emu, test_byte);
+		break;
+	case 0x85:
+		common_binop_ns_word_long_rm_r(emu, test_word, test_long);
+		break;
+	case 0x86:
+		x86emuOp_xchg_byte_RM_R(emu);
+		break;
+	case 0x87:
+		x86emuOp_xchg_word_RM_R(emu);
+		break;
+
+	case 0x88:
+		x86emuOp_mov_byte_RM_R(emu);
+		break;
+	case 0x89:
+		x86emuOp_mov_word_RM_R(emu);
+		break;
+	case 0x8a:
+		x86emuOp_mov_byte_R_RM(emu);
+		break;
+	case 0x8b:
+		x86emuOp_mov_word_R_RM(emu);
+		break;
+	case 0x8c:
+		x86emuOp_mov_word_RM_SR(emu);
+		break;
+	case 0x8d:
+		x86emuOp_lea_word_R_M(emu);
+		break;
+	case 0x8e:
+		x86emuOp_mov_word_SR_RM(emu);
+		break;
+	case 0x8f:
+		x86emuOp_pop_RM(emu);
+		break;
+
+	case 0x90:
+		/* nop */
+		break;
+	case 0x91:
+		x86emuOp_xchg_word_AX_CX(emu);
+		break;
+	case 0x92:
+		x86emuOp_xchg_word_AX_DX(emu);
+		break;
+	case 0x93:
+		x86emuOp_xchg_word_AX_BX(emu);
+		break;
+	case 0x94:
+		x86emuOp_xchg_word_AX_SP(emu);
+		break;
+	case 0x95:
+		x86emuOp_xchg_word_AX_BP(emu);
+		break;
+	case 0x96:
+		x86emuOp_xchg_word_AX_SI(emu);
+		break;
+	case 0x97:
+		x86emuOp_xchg_word_AX_DI(emu);
+		break;
+
+	case 0x98:
+		x86emuOp_cbw(emu);
+		break;
+	case 0x99:
+		x86emuOp_cwd(emu);
+		break;
+	case 0x9a:
+		x86emuOp_call_far_IMM(emu);
+		break;
+	case 0x9b:
+		/* wait */
+		break;
+	case 0x9c:
+		x86emuOp_pushf_word(emu);
+		break;
+	case 0x9d:
+		x86emuOp_popf_word(emu);
+		break;
+	case 0x9e:
+		x86emuOp_sahf(emu);
+		break;
+	case 0x9f:
+		x86emuOp_lahf(emu);
+		break;
+
+	case 0xa0:
+		x86emuOp_mov_AL_M_IMM(emu);
+		break;
+	case 0xa1:
+		x86emuOp_mov_AX_M_IMM(emu);
+		break;
+	case 0xa2:
+		x86emuOp_mov_M_AL_IMM(emu);
+		break;
+	case 0xa3:
+		x86emuOp_mov_M_AX_IMM(emu);
+		break;
+	case 0xa4:
+		x86emuOp_movs_byte(emu);
+		break;
+	case 0xa5:
+		x86emuOp_movs_word(emu);
+		break;
+	case 0xa6:
+		x86emuOp_cmps_byte(emu);
+		break;
+	case 0xa7:
+		x86emuOp_cmps_word(emu);
+		break;
+
+	case 0xa8:
+		test_byte(emu, emu->x86.R_AL, fetch_byte_imm(emu));
+		break;
+	case 0xa9:
+		x86emuOp_test_AX_IMM(emu);
+		break;
+	case 0xaa:
+		x86emuOp_stos_byte(emu);
+		break;
+	case 0xab:
+		x86emuOp_stos_word(emu);
+		break;
+	case 0xac:
+		x86emuOp_lods_byte(emu);
+		break;
+	case 0xad:
+		x86emuOp_lods_word(emu);
+		break;
+	case 0xae:
+		x86emuOp_scas_byte(emu);
+		break;
+	case 0xaf:
+		x86emuOp_scas_word(emu);
+		break;
+
+	case 0xb0:
+		emu->x86.R_AL = fetch_byte_imm(emu);
+		break;
+	case 0xb1:
+		emu->x86.R_CL = fetch_byte_imm(emu);
+		break;
+	case 0xb2:
+		emu->x86.R_DL = fetch_byte_imm(emu);
+		break;
+	case 0xb3:
+		emu->x86.R_BL = fetch_byte_imm(emu);
+		break;
+	case 0xb4:
+		emu->x86.R_AH = fetch_byte_imm(emu);
+		break;
+	case 0xb5:
+		emu->x86.R_CH = fetch_byte_imm(emu);
+		break;
+	case 0xb6:
+		emu->x86.R_DH = fetch_byte_imm(emu);
+		break;
+	case 0xb7:
+		emu->x86.R_BH = fetch_byte_imm(emu);
+		break;
+
+	case 0xb8:
+		x86emuOp_mov_word_AX_IMM(emu);
+		break;
+	case 0xb9:
+		x86emuOp_mov_word_CX_IMM(emu);
+		break;
+	case 0xba:
+		x86emuOp_mov_word_DX_IMM(emu);
+		break;
+	case 0xbb:
+		x86emuOp_mov_word_BX_IMM(emu);
+		break;
+	case 0xbc:
+
+		x86emuOp_mov_word_SP_IMM(emu);
+		break;
+	case 0xbd:
+		x86emuOp_mov_word_BP_IMM(emu);
+		break;
+	case 0xbe:
+		x86emuOp_mov_word_SI_IMM(emu);
+		break;
+	case 0xbf:
+		x86emuOp_mov_word_DI_IMM(emu);
+		break;
+
+	case 0xc0:
+		x86emuOp_opcC0_byte_RM_MEM(emu);
+		break;
+	case 0xc1:
+		x86emuOp_opcC1_word_RM_MEM(emu);
+		break;
+	case 0xc2:
+		x86emuOp_ret_near_IMM(emu);
+		break;
+	case 0xc3:
+		emu->x86.R_IP = pop_word(emu);
+		break;
+	case 0xc4:
+		common_load_far_pointer(emu, &emu->x86.R_ES);
+		break;
+	case 0xc5:
+		common_load_far_pointer(emu, &emu->x86.R_DS);
+		break;
+	case 0xc6:
+		x86emuOp_mov_byte_RM_IMM(emu);
+		break;
+	case 0xc7:
+		x86emuOp_mov_word_RM_IMM(emu);
+		break;
+	case 0xc8:
+		x86emuOp_enter(emu);
+		break;
+	case 0xc9:
+		x86emuOp_leave(emu);
+		break;
+	case 0xca:
+		x86emuOp_ret_far_IMM(emu);
+		break;
+	case 0xcb:
+		x86emuOp_ret_far(emu);
+		break;
+	case 0xcc:
+		x86emuOp_int3(emu);
+		break;
+	case 0xcd:
+		x86emuOp_int_IMM(emu);
+		break;
+	case 0xce:
+		x86emuOp_into(emu);
+		break;
+	case 0xcf:
+		x86emuOp_iret(emu);
+		break;
+
+	case 0xd0:
+		x86emuOp_opcD0_byte_RM_1(emu);
+		break;
+	case 0xd1:
+		x86emuOp_opcD1_word_RM_1(emu);
+		break;
+	case 0xd2:
+		x86emuOp_opcD2_byte_RM_CL(emu);
+		break;
+	case 0xd3:
+		x86emuOp_opcD3_word_RM_CL(emu);
+		break;
+	case 0xd4:
+		x86emuOp_aam(emu);
+		break;
+	case 0xd5:
+		x86emuOp_aad(emu);
+		break;
+	/* 0xd6 Undocumented SETALC instruction */
+	case 0xd7:
+		x86emuOp_xlat(emu);
+		break;
+	case 0xd8:
+		x86emuOp_esc_coprocess_d8(emu);
+		break;
+	case 0xd9:
+		x86emuOp_esc_coprocess_d9(emu);
+		break;
+	case 0xda:
+		x86emuOp_esc_coprocess_da(emu);
+		break;
+	case 0xdb:
+		x86emuOp_esc_coprocess_db(emu);
+		break;
+	case 0xdc:
+		x86emuOp_esc_coprocess_dc(emu);
+		break;
+	case 0xdd:
+		x86emuOp_esc_coprocess_dd(emu);
+		break;
+	case 0xde:
+		x86emuOp_esc_coprocess_de(emu);
+		break;
+	case 0xdf:
+		x86emuOp_esc_coprocess_df(emu);
+		break;
+
+	case 0xe0:
+		x86emuOp_loopne(emu);
+		break;
+	case 0xe1:
+		x86emuOp_loope(emu);
+		break;
+	case 0xe2:
+		x86emuOp_loop(emu);
+		break;
+	case 0xe3:
+		x86emuOp_jcxz(emu);
+		break;
+	case 0xe4:
+		x86emuOp_in_byte_AL_IMM(emu);
+		break;
+	case 0xe5:
+		x86emuOp_in_word_AX_IMM(emu);
+		break;
+	case 0xe6:
+		x86emuOp_out_byte_IMM_AL(emu);
+		break;
+	case 0xe7:
+		x86emuOp_out_word_IMM_AX(emu);
+		break;
+
+	case 0xe8:
+		x86emuOp_call_near_IMM(emu);
+		break;
+	case 0xe9:
+		x86emuOp_jump_near_IMM(emu);
+		break;
+	case 0xea:
+		x86emuOp_jump_far_IMM(emu);
+		break;
+	case 0xeb:
+		x86emuOp_jump_byte_IMM(emu);
+		break;
+	case 0xec:
+		x86emuOp_in_byte_AL_DX(emu);
+		break;
+	case 0xed:
+		x86emuOp_in_word_AX_DX(emu);
+		break;
+	case 0xee:
+		x86emuOp_out_byte_DX_AL(emu);
+		break;
+	case 0xef:
+		x86emuOp_out_word_DX_AX(emu);
+		break;
+
+	case 0xf0:
+		x86emuOp_lock(emu);
+		break;
+	case 0xf2:
+		emu->x86.mode |= SYSMODE_PREFIX_REPNE;
+		break;
+	case 0xf3:
+		emu->x86.mode |= SYSMODE_PREFIX_REPE;
+		break;
+	case 0xf4:
+		x86emu_halt_sys(emu);
+		break;
+	case 0xf5:
+		x86emuOp_cmc(emu);
+		break;
+	case 0xf6:
+		x86emuOp_opcF6_byte_RM(emu);
+		break;
+	case 0xf7:
+		x86emuOp_opcF7_word_RM(emu);
+		break;
+
+	case 0xf8:
+		CLEAR_FLAG(F_CF);
+		break;
+	case 0xf9:
+		SET_FLAG(F_CF);
+		break;
+	case 0xfa:
+		CLEAR_FLAG(F_IF);
+		break;
+	case 0xfb:
+		SET_FLAG(F_IF);
+		break;
+	case 0xfc:
+		CLEAR_FLAG(F_DF);
+		break;
+	case 0xfd:
+		SET_FLAG(F_DF);
+		break;
+	case 0xfe:
+		x86emuOp_opcFE_byte_RM(emu);
+		break;
+	case 0xff:
+		x86emuOp_opcFF_word_RM(emu);
+		break;
+	default:
+		x86emu_halt_sys(emu);
+		break;
+	}
+	if (op1 != 0x26 && op1 != 0x2e && op1 != 0x36 && op1 != 0x3e &&
+	    (op1 | 3) != 0x67)
+		emu->x86.mode &= ~SYSMODE_CLRMASK;
+}
+
+static void
+common_jmp_long(struct x86emu *emu, int cond)
+{
+	int16_t target;
+
+	target = (int16_t) fetch_word_imm(emu);
+	target += (int16_t) emu->x86.R_IP;
+	if (cond)
+		emu->x86.R_IP = (uint16_t) target;
+}
+
+static void
+common_set_byte(struct x86emu *emu, int cond)
+{
+	uint32_t destoffset;
+	uint8_t *destreg, destval;
+
+	fetch_decode_modrm(emu);
+	destval = cond ? 0x01 : 0x00;
+	if (emu->cur_mod != 3) {
+		destoffset = decode_rl_address(emu);
+		store_data_byte(emu, destoffset, destval);
+	} else {
+		destreg = decode_rl_byte_register(emu);
+		*destreg = destval;
+	}
+}
+
+static void
+common_bitstring32(struct x86emu *emu, int op)
+{
+	int bit;
+	uint32_t srcval, *shiftreg, mask;
+
+	fetch_decode_modrm(emu);
+	shiftreg = decode_rh_long_register(emu);
+	srcval = decode_and_fetch_long_disp(emu, (int16_t) *shiftreg >> 5);
+	bit = *shiftreg & 0x1F;
+	mask =  0x1 << bit;
+	CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
+
+	switch (op) {
+	case 0:
+		break;
+	case 1:
+		write_back_long(emu, srcval | mask);
+		break;
+	case 2:
+		write_back_long(emu, srcval & ~mask);
+		break;
+	case 3:
+		write_back_long(emu, srcval ^ mask);
+		break;
+	}
+}
+
+static void
+common_bitstring16(struct x86emu *emu, int op)
+{
+	int bit;
+	uint16_t srcval, *shiftreg, mask;
+
+	fetch_decode_modrm(emu);
+	shiftreg = decode_rh_word_register(emu);
+	srcval = decode_and_fetch_word_disp(emu, (int16_t) *shiftreg >> 4);
+	bit = *shiftreg & 0xF;
+	mask =  0x1 << bit;
+	CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
+
+	switch (op) {
+	case 0:
+		break;
+	case 1:
+		write_back_word(emu, srcval | mask);
+		break;
+	case 2:
+		write_back_word(emu, srcval & ~mask);
+		break;
+	case 3:
+		write_back_word(emu, srcval ^ mask);
+		break;
+	}
+}
+
+static void
+common_bitstring(struct x86emu *emu, int op)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_bitstring32(emu, op);
+	else
+		common_bitstring16(emu, op);
+}
+
+static void
+common_bitsearch32(struct x86emu *emu, int diff)
+{
+	uint32_t srcval, *dstreg;
+
+	fetch_decode_modrm(emu);
+	dstreg = decode_rh_long_register(emu);
+	srcval = decode_and_fetch_long(emu);
+	CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	for (*dstreg = 0; *dstreg < 32; *dstreg += diff) {
+		if ((srcval >> *dstreg) & 1)
+			break;
+	}
+}
+
+static void
+common_bitsearch16(struct x86emu *emu, int diff)
+{
+	uint16_t srcval, *dstreg;
+
+	fetch_decode_modrm(emu);
+	dstreg = decode_rh_word_register(emu);
+	srcval = decode_and_fetch_word(emu);
+	CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	for (*dstreg = 0; *dstreg < 16; *dstreg += diff) {
+		if ((srcval >> *dstreg) & 1)
+			break;
+	}
+}
+
+static void
+common_bitsearch(struct x86emu *emu, int diff)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_bitsearch32(emu, diff);
+	else
+		common_bitsearch16(emu, diff);
+}
+
+static void
+common_shift32(struct x86emu *emu, int shift_left, int use_cl)
+{
+	uint8_t shift;
+	uint32_t destval, *shiftreg;
+
+	fetch_decode_modrm(emu);
+	shiftreg = decode_rh_long_register(emu);
+	if (use_cl) {
+		destval = decode_and_fetch_long(emu);
+		shift = emu->x86.R_CL;
+	} else {
+		destval = decode_and_fetch_long_imm8(emu, &shift);
+	}
+	if (shift_left)
+		destval = shld_long(emu, destval, *shiftreg, shift);
+	else
+		destval = shrd_long(emu, destval, *shiftreg, shift);
+	write_back_long(emu, destval);
+}
+
+static void
+common_shift16(struct x86emu *emu, int shift_left, int use_cl)
+{
+	uint8_t shift;
+	uint16_t destval, *shiftreg;
+
+	fetch_decode_modrm(emu);
+	shiftreg = decode_rh_word_register(emu);
+	if (use_cl) {
+		destval = decode_and_fetch_word(emu);
+		shift = emu->x86.R_CL;
+	} else {
+		destval = decode_and_fetch_word_imm8(emu, &shift);
+	}
+	if (shift_left)
+		destval = shld_word(emu, destval, *shiftreg, shift);
+	else
+		destval = shrd_word(emu, destval, *shiftreg, shift);
+	write_back_word(emu, destval);
+}
+
+static void
+common_shift(struct x86emu *emu, int shift_left, int use_cl)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		common_shift32(emu, shift_left, use_cl);
+	else
+		common_shift16(emu, shift_left, use_cl);
+}
+
+/*
+ * Implementation
+ */
+#define xorl(a,b)   ((a) && !(b)) || (!(a) && (b))
+
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0x31
+ */
+static void
+x86emuOp2_rdtsc(struct x86emu *emu)
+{
+	emu->x86.R_EAX = emu->cur_cycles & 0xffffffff;
+	emu->x86.R_EDX = emu->cur_cycles >> 32;
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa0
+ */
+static void
+x86emuOp2_push_FS(struct x86emu *emu)
+{
+	push_word(emu, emu->x86.R_FS);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa1
+ */
+static void
+x86emuOp2_pop_FS(struct x86emu *emu)
+{
+	emu->x86.R_FS = pop_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa1
+ */
+#if defined(__i386__) || defined(__amd64__)
+static void
+hw_cpuid(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
+{
+	__asm__ __volatile__("cpuid"
+			     : "=a" (*a), "=b" (*b),
+			       "=c" (*c), "=d" (*d)
+			     : "a" (*a), "c" (*c)
+			     : "cc");
+}
+#endif
+static void
+x86emuOp2_cpuid(struct x86emu *emu)
+{
+#if defined(__i386__) || defined(__amd64__)
+	hw_cpuid(&emu->x86.R_EAX, &emu->x86.R_EBX, &emu->x86.R_ECX,
+	    &emu->x86.R_EDX);
+#endif
+	switch (emu->x86.R_EAX) {
+	case 0:
+		emu->x86.R_EAX = 1;
+#if !defined(__i386__) && !defined(__amd64__)
+		/* "GenuineIntel" */
+		emu->x86.R_EBX = 0x756e6547;
+		emu->x86.R_EDX = 0x49656e69;
+		emu->x86.R_ECX = 0x6c65746e;
+#endif
+		break;
+	case 1:
+#if !defined(__i386__) && !defined(__amd64__)
+		emu->x86.R_EAX = 0x00000480;
+		emu->x86.R_EBX = emu->x86.R_ECX = 0;
+		emu->x86.R_EDX = 0x00000002;
+#else
+		emu->x86.R_EDX &= 0x00000012;
+#endif
+		break;
+	default:
+		emu->x86.R_EAX = emu->x86.R_EBX = emu->x86.R_ECX =
+		    emu->x86.R_EDX = 0;
+		break;
+	}
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa3
+ */
+static void
+x86emuOp2_bt_R(struct x86emu *emu)
+{
+	common_bitstring(emu, 0);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa4
+ */
+static void
+x86emuOp2_shld_IMM(struct x86emu *emu)
+{
+	common_shift(emu, 1, 0);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa5
+ */
+static void
+x86emuOp2_shld_CL(struct x86emu *emu)
+{
+	common_shift(emu, 1, 1);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa8
+ */
+static void
+x86emuOp2_push_GS(struct x86emu *emu)
+{
+	push_word(emu, emu->x86.R_GS);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xa9
+ */
+static void
+x86emuOp2_pop_GS(struct x86emu *emu)
+{
+	emu->x86.R_GS = pop_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xab
+ */
+static void
+x86emuOp2_bts_R(struct x86emu *emu)
+{
+	common_bitstring(emu, 1);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xac
+ */
+static void
+x86emuOp2_shrd_IMM(struct x86emu *emu)
+{
+	common_shift(emu, 0, 0);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xad
+ */
+static void
+x86emuOp2_shrd_CL(struct x86emu *emu)
+{
+	common_shift(emu, 0, 1);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xaf
+ */
+static void
+x86emuOp2_32_imul_R_RM(struct x86emu *emu)
+{
+	uint32_t *destreg, srcval;
+	uint64_t res;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	srcval = decode_and_fetch_long(emu);
+	res = (int32_t) *destreg * (int32_t)srcval;
+	if (res > 0xffffffff) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	}
+	*destreg = (uint32_t) res;
+}
+
+static void
+x86emuOp2_16_imul_R_RM(struct x86emu *emu)
+{
+	uint16_t *destreg, srcval;
+	uint32_t res;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	srcval = decode_and_fetch_word(emu);
+	res = (int16_t) * destreg * (int16_t)srcval;
+	if (res > 0xFFFF) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	}
+	*destreg = (uint16_t) res;
+}
+
+static void
+x86emuOp2_imul_R_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp2_32_imul_R_RM(emu);
+	else
+		x86emuOp2_16_imul_R_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb2
+ */
+static void
+x86emuOp2_lss_R_IMM(struct x86emu *emu)
+{
+	common_load_far_pointer(emu, &emu->x86.R_SS);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb3
+ */
+static void
+x86emuOp2_btr_R(struct x86emu *emu)
+{
+	common_bitstring(emu, 2);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb4
+ */
+static void
+x86emuOp2_lfs_R_IMM(struct x86emu *emu)
+{
+	common_load_far_pointer(emu, &emu->x86.R_FS);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb5
+ */
+static void
+x86emuOp2_lgs_R_IMM(struct x86emu *emu)
+{
+	common_load_far_pointer(emu, &emu->x86.R_GS);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb6
+ */
+static void
+x86emuOp2_32_movzx_byte_R_RM(struct x86emu *emu)
+{
+	uint32_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	*destreg = decode_and_fetch_byte(emu);
+}
+
+static void
+x86emuOp2_16_movzx_byte_R_RM(struct x86emu *emu)
+{
+	uint16_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	*destreg = decode_and_fetch_byte(emu);
+}
+
+static void
+x86emuOp2_movzx_byte_R_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp2_32_movzx_byte_R_RM(emu);
+	else
+		x86emuOp2_16_movzx_byte_R_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xb7
+ */
+static void
+x86emuOp2_movzx_word_R_RM(struct x86emu *emu)
+{
+	uint32_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	*destreg = decode_and_fetch_word(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xba
+ */
+static void
+x86emuOp2_32_btX_I(struct x86emu *emu)
+{
+	int bit;
+	uint32_t srcval, mask;
+	uint8_t shift;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh < 4)
+		x86emu_halt_sys(emu);
+
+	srcval = decode_and_fetch_long_imm8(emu, &shift);
+	bit = shift & 0x1F;
+	mask = (0x1 << bit);
+
+	switch (emu->cur_rh) {
+	case 5:
+		write_back_long(emu, srcval | mask);
+		break;
+	case 6:
+		write_back_long(emu, srcval & ~mask);
+		break;
+	case 7:
+		write_back_long(emu, srcval ^ mask);
+		break;
+	}
+	CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
+}
+
+static void
+x86emuOp2_16_btX_I(struct x86emu *emu)
+{
+	int bit;
+
+	uint16_t srcval, mask;
+	uint8_t shift;
+
+	fetch_decode_modrm(emu);
+	if (emu->cur_rh < 4)
+		x86emu_halt_sys(emu);
+
+	srcval = decode_and_fetch_word_imm8(emu, &shift);
+	bit = shift & 0xF;
+	mask = (0x1 << bit);
+	switch (emu->cur_rh) {
+	case 5:
+		write_back_word(emu, srcval | mask);
+		break;
+	case 6:
+		write_back_word(emu, srcval & ~mask);
+		break;
+	case 7:
+		write_back_word(emu, srcval ^ mask);
+		break;
+	}
+	CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
+}
+
+static void
+x86emuOp2_btX_I(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp2_32_btX_I(emu);
+	else
+		x86emuOp2_16_btX_I(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xbb
+ */
+static void
+x86emuOp2_btc_R(struct x86emu *emu)
+{
+	common_bitstring(emu, 3);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xbc
+ */
+static void
+x86emuOp2_bsf(struct x86emu *emu)
+{
+	common_bitsearch(emu, +1);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xbd
+ */
+static void
+x86emuOp2_bsr(struct x86emu *emu)
+{
+	common_bitsearch(emu, -1);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xbe
+ */
+static void
+x86emuOp2_32_movsx_byte_R_RM(struct x86emu *emu)
+{
+	uint32_t *destreg;
+
+	destreg = decode_rh_long_register(emu);
+	*destreg = (int32_t)(int8_t)decode_and_fetch_byte(emu);
+}
+
+static void
+x86emuOp2_16_movsx_byte_R_RM(struct x86emu *emu)
+{
+	uint16_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_word_register(emu);
+	*destreg = (int16_t)(int8_t)decode_and_fetch_byte(emu);
+}
+
+static void
+x86emuOp2_movsx_byte_R_RM(struct x86emu *emu)
+{
+	if (emu->x86.mode & SYSMODE_PREFIX_DATA)
+		x86emuOp2_32_movsx_byte_R_RM(emu);
+	else
+		x86emuOp2_16_movsx_byte_R_RM(emu);
+}
+
+/*
+ * REMARKS:
+ * Handles opcode 0x0f,0xbf
+ */
+static void
+x86emuOp2_movsx_word_R_RM(struct x86emu *emu)
+{
+	uint32_t *destreg;
+
+	fetch_decode_modrm(emu);
+	destreg = decode_rh_long_register(emu);
+	*destreg = (int32_t)(int16_t)decode_and_fetch_word(emu);
+}
+
+static void
+x86emu_exec_two_byte(struct x86emu * emu)
+{
+	uint8_t op2;
+
+	op2 = fetch_byte_imm(emu);
+
+	switch (op2) {
+	/* 0x00 Group F (ring 0 PM)      */
+	/* 0x01 Group G (ring 0 PM)      */
+	/* 0x02 lar (ring 0 PM)          */
+	/* 0x03 lsl (ring 0 PM)          */
+	/* 0x05 loadall (undocumented)   */
+	/* 0x06 clts (ring 0 PM)         */
+	/* 0x07 loadall (undocumented)   */
+	/* 0x08 invd (ring 0 PM)         */
+	/* 0x09 wbinvd (ring 0 PM)       */
+
+	/* 0x20 mov reg32(op2); break;creg (ring 0 PM) */
+	/* 0x21 mov reg32(op2); break;dreg (ring 0 PM) */
+	/* 0x22 mov creg(op2); break;reg32 (ring 0 PM) */
+	/* 0x23 mov dreg(op2); break;reg32 (ring 0 PM) */
+	/* 0x24 mov reg32(op2); break;treg (ring 0 PM) */
+	/* 0x26 mov treg(op2); break;reg32 (ring 0 PM) */
+
+	case 0x31:
+		x86emuOp2_rdtsc(emu);
+		break;
+
+	case 0x80:
+		common_jmp_long(emu, ACCESS_FLAG(F_OF));
+		break;
+	case 0x81:
+		common_jmp_long(emu, !ACCESS_FLAG(F_OF));
+		break;
+	case 0x82:
+		common_jmp_long(emu, ACCESS_FLAG(F_CF));
+		break;
+	case 0x83:
+		common_jmp_long(emu, !ACCESS_FLAG(F_CF));
+		break;
+	case 0x84:
+		common_jmp_long(emu, ACCESS_FLAG(F_ZF));
+		break;
+	case 0x85:
+		common_jmp_long(emu, !ACCESS_FLAG(F_ZF));
+		break;
+	case 0x86:
+		common_jmp_long(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+		break;
+	case 0x87:
+		common_jmp_long(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
+		break;
+	case 0x88:
+		common_jmp_long(emu, ACCESS_FLAG(F_SF));
+		break;
+	case 0x89:
+		common_jmp_long(emu, !ACCESS_FLAG(F_SF));
+		break;
+	case 0x8a:
+		common_jmp_long(emu, ACCESS_FLAG(F_PF));
+		break;
+	case 0x8b:
+		common_jmp_long(emu, !ACCESS_FLAG(F_PF));
+		break;
+	case 0x8c:
+		common_jmp_long(emu, xorl(ACCESS_FLAG(F_SF),
+		    ACCESS_FLAG(F_OF)));
+		break;
+	case 0x8d:
+		common_jmp_long(emu, !(xorl(ACCESS_FLAG(F_SF),
+		    ACCESS_FLAG(F_OF))));
+		break;
+	case 0x8e:
+		common_jmp_long(emu, (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))
+		    || ACCESS_FLAG(F_ZF)));
+		break;
+	case 0x8f:
+		common_jmp_long(emu,
+		    !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		    ACCESS_FLAG(F_ZF)));
+		break;
+
+	case 0x90:
+		common_set_byte(emu, ACCESS_FLAG(F_OF));
+		break;
+	case 0x91:
+		common_set_byte(emu, !ACCESS_FLAG(F_OF));
+		break;
+	case 0x92:
+		common_set_byte(emu, ACCESS_FLAG(F_CF));
+		break;
+	case 0x93:
+		common_set_byte(emu, !ACCESS_FLAG(F_CF));
+		break;
+	case 0x94:
+		common_set_byte(emu, ACCESS_FLAG(F_ZF));
+		break;
+	case 0x95:
+		common_set_byte(emu, !ACCESS_FLAG(F_ZF));
+		break;
+	case 0x96:
+		common_set_byte(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+		break;
+	case 0x97:
+		common_set_byte(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
+		break;
+	case 0x98:
+		common_set_byte(emu, ACCESS_FLAG(F_SF));
+		break;
+	case 0x99:
+		common_set_byte(emu, !ACCESS_FLAG(F_SF));
+		break;
+	case 0x9a:
+		common_set_byte(emu, ACCESS_FLAG(F_PF));
+		break;
+	case 0x9b:
+		common_set_byte(emu, !ACCESS_FLAG(F_PF));
+		break;
+	case 0x9c:
+		common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
+		    ACCESS_FLAG(F_OF)));
+		break;
+	case 0x9d:
+		common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
+		    ACCESS_FLAG(F_OF)));
+		break;
+	case 0x9e:
+		common_set_byte(emu,
+		    (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		    ACCESS_FLAG(F_ZF)));
+		break;
+	case 0x9f:
+		common_set_byte(emu,
+		    !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		    ACCESS_FLAG(F_ZF)));
+		break;
+
+	case 0xa0:
+		x86emuOp2_push_FS(emu);
+		break;
+	case 0xa1:
+		x86emuOp2_pop_FS(emu);
+		break;
+	case 0xa2:
+		x86emuOp2_cpuid(emu);
+		break;
+	case 0xa3:
+		x86emuOp2_bt_R(emu);
+		break;
+	case 0xa4:
+		x86emuOp2_shld_IMM(emu);
+		break;
+	case 0xa5:
+		x86emuOp2_shld_CL(emu);
+		break;
+	case 0xa8:
+		x86emuOp2_push_GS(emu);
+		break;
+	case 0xa9:
+		x86emuOp2_pop_GS(emu);
+		break;
+	case 0xab:
+		x86emuOp2_bts_R(emu);
+		break;
+	case 0xac:
+		x86emuOp2_shrd_IMM(emu);
+		break;
+	case 0xad:
+		x86emuOp2_shrd_CL(emu);
+		break;
+	case 0xaf:
+		x86emuOp2_imul_R_RM(emu);
+		break;
+
+	/* 0xb0 TODO: cmpxchg */
+	/* 0xb1 TODO: cmpxchg */
+	case 0xb2:
+		x86emuOp2_lss_R_IMM(emu);
+		break;
+	case 0xb3:
+		x86emuOp2_btr_R(emu);
+		break;
+	case 0xb4:
+		x86emuOp2_lfs_R_IMM(emu);
+		break;
+	case 0xb5:
+		x86emuOp2_lgs_R_IMM(emu);
+		break;
+	case 0xb6:
+		x86emuOp2_movzx_byte_R_RM(emu);
+		break;
+	case 0xb7:
+		x86emuOp2_movzx_word_R_RM(emu);
+		break;
+	case 0xba:
+		x86emuOp2_btX_I(emu);
+		break;
+	case 0xbb:
+		x86emuOp2_btc_R(emu);
+		break;
+	case 0xbc:
+		x86emuOp2_bsf(emu);
+		break;
+	case 0xbd:
+		x86emuOp2_bsr(emu);
+		break;
+	case 0xbe:
+		x86emuOp2_movsx_byte_R_RM(emu);
+		break;
+	case 0xbf:
+		x86emuOp2_movsx_word_R_RM(emu);
+		break;
+
+	/* 0xc0 TODO: xadd */
+	/* 0xc1 TODO: xadd */
+	/* 0xc8 TODO: bswap */
+	/* 0xc9 TODO: bswap */
+	/* 0xca TODO: bswap */
+	/* 0xcb TODO: bswap */
+	/* 0xcc TODO: bswap */
+	/* 0xcd TODO: bswap */
+	/* 0xce TODO: bswap */
+	/* 0xcf TODO: bswap */
+
+	default:
+		x86emu_halt_sys(emu);
+		break;
+	}
+}
+
+/*
+* Carry Chain Calculation
+*
+* This represents a somewhat expensive calculation which is
+* apparently required to emulate the setting of the OF and AF flag.
+* The latter is not so important, but the former is.  The overflow
+* flag is the XOR of the top two bits of the carry chain for an
+* addition (similar for subtraction).  Since we do not want to
+* simulate the addition in a bitwise manner, we try to calculate the
+* carry chain given the two operands and the result.
+*
+* So, given the following table, which represents the addition of two
+* bits, we can derive a formula for the carry chain.
+*
+* a   b   cin   r     cout
+* 0   0   0     0     0
+* 0   0   1     1     0
+* 0   1   0     1     0
+* 0   1   1     0     1
+* 1   0   0     1     0
+* 1   0   1     0     1
+* 1   1   0     0     1
+* 1   1   1     1     1
+*
+* Construction of table for cout:
+*
+* ab
+* r  \  00   01   11  10
+* |------------------
+* 0  |   0    1    1   1
+* 1  |   0    0    1   0
+*
+* By inspection, one gets:  cc = ab +  r'(a + b)
+*
+* That represents alot of operations, but NO CHOICE....
+*
+* Borrow Chain Calculation.
+*
+* The following table represents the subtraction of two bits, from
+* which we can derive a formula for the borrow chain.
+*
+* a   b   bin   r     bout
+* 0   0   0     0     0
+* 0   0   1     1     1
+* 0   1   0     1     1
+* 0   1   1     0     1
+* 1   0   0     1     0
+* 1   0   1     0     0
+* 1   1   0     0     0
+* 1   1   1     1     1
+*
+* Construction of table for cout:
+*
+* ab
+* r  \  00   01   11  10
+* |------------------
+* 0  |   0    1    0   0
+* 1  |   1    1    1   0
+*
+* By inspection, one gets:  bc = a'b +  r(a' + b)
+*
+ */
+
+/*
+ * Global Variables
+ */
+
+static uint32_t x86emu_parity_tab[8] =
+{
+	0x96696996,
+	0x69969669,
+	0x69969669,
+	0x96696996,
+	0x69969669,
+	0x96696996,
+	0x96696996,
+	0x69969669,
+};
+#define PARITY(x)   (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
+#define XOR2(x) 	(((x) ^ ((x)>>1)) & 0x1)
+
+
+/*
+ * REMARKS:
+ * Implements the AAA instruction and side effects.
+ */
+static uint16_t
+aaa_word(struct x86emu *emu, uint16_t d)
+{
+	uint16_t res;
+	if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+		d += 0x6;
+		d += 0x100;
+		SET_FLAG(F_AF);
+		SET_FLAG(F_CF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_AF);
+	}
+	res = (uint16_t) (d & 0xFF0F);
+	CLEAR_FLAG(F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the AAA instruction and side effects.
+ */
+static uint16_t
+aas_word(struct x86emu *emu, uint16_t d)
+{
+	uint16_t res;
+	if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+		d -= 0x6;
+		d -= 0x100;
+		SET_FLAG(F_AF);
+		SET_FLAG(F_CF);
+	} else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_AF);
+	}
+	res = (uint16_t) (d & 0xFF0F);
+	CLEAR_FLAG(F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the AAD instruction and side effects.
+ */
+static uint16_t
+aad_word(struct x86emu *emu, uint16_t d)
+{
+	uint16_t l;
+	uint8_t hb, lb;
+
+	hb = (uint8_t) ((d >> 8) & 0xff);
+	lb = (uint8_t) ((d & 0xff));
+	l = (uint16_t) ((lb + 10 * hb) & 0xFF);
+
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(l == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
+	return l;
+}
+
+/*
+ * REMARKS:
+ * Implements the AAM instruction and side effects.
+ */
+static uint16_t
+aam_word(struct x86emu *emu, uint8_t d)
+{
+	uint16_t h, l;
+
+	h = (uint16_t) (d / 10);
+	l = (uint16_t) (d % 10);
+	l |= (uint16_t) (h << 8);
+
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(l == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
+	return l;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADC instruction and side effects.
+ */
+static uint8_t
+adc_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	if (ACCESS_FLAG(F_CF))
+		res = 1 + d + s;
+	else
+		res = d + s;
+
+	CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADC instruction and side effects.
+ */
+static uint16_t
+adc_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	if (ACCESS_FLAG(F_CF))
+		res = 1 + d + s;
+	else
+		res = d + s;
+
+	CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADC instruction and side effects.
+ */
+static uint32_t
+adc_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t lo;	/* all operands in native machine order */
+	uint32_t hi;
+	uint32_t res;
+	uint32_t cc;
+
+	if (ACCESS_FLAG(F_CF)) {
+		lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
+		res = 1 + d + s;
+	} else {
+		lo = (d & 0xFFFF) + (s & 0xFFFF);
+		res = d + s;
+	}
+	hi = (lo >> 16) + (d >> 16) + (s >> 16);
+
+	CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADD instruction and side effects.
+ */
+static uint8_t
+add_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	res = d + s;
+	CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADD instruction and side effects.
+ */
+static uint16_t
+add_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	res = d + s;
+	CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ADD instruction and side effects.
+ */
+static uint32_t
+add_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t lo;	/* all operands in native machine order */
+	uint32_t hi;
+	uint32_t res;
+	uint32_t cc;
+
+	lo = (d & 0xFFFF) + (s & 0xFFFF);
+	res = d + s;
+	hi = (lo >> 16) + (d >> 16) + (s >> 16);
+
+	CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (s & d) | ((~res) & (s | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the AND instruction and side effects.
+ */
+static uint8_t
+and_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint8_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	/* set the flags  */
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the AND instruction and side effects.
+ */
+static uint16_t
+and_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint16_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	/* set the flags  */
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the AND instruction and side effects.
+ */
+static uint32_t
+and_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	/* set the flags  */
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the CMP instruction and side effects.
+ */
+static uint8_t
+cmp_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CLEAR_FLAG(F_CF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return d;
+}
+
+static void
+cmp_byte_no_return(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	cmp_byte(emu, d, s);
+}
+
+/*
+ * REMARKS:
+ * Implements the CMP instruction and side effects.
+ */
+static uint16_t
+cmp_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return d;
+}
+
+static void
+cmp_word_no_return(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	cmp_word(emu, d, s);
+}
+
+/*
+ * REMARKS:
+ * Implements the CMP instruction and side effects.
+ */
+static uint32_t
+cmp_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return d;
+}
+
+static void
+cmp_long_no_return(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	cmp_long(emu, d, s);
+}
+
+/*
+ * REMARKS:
+ * Implements the DAA instruction and side effects.
+ */
+static uint8_t
+daa_byte(struct x86emu *emu, uint8_t d)
+{
+	uint32_t res = d;
+	if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+		res += 6;
+		SET_FLAG(F_AF);
+	}
+	if (res > 0x9F || ACCESS_FLAG(F_CF)) {
+		res += 0x60;
+		SET_FLAG(F_CF);
+	}
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the DAS instruction and side effects.
+ */
+static uint8_t
+das_byte(struct x86emu *emu, uint8_t d)
+{
+	if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+		d -= 6;
+		SET_FLAG(F_AF);
+	}
+	if (d > 0x9F || ACCESS_FLAG(F_CF)) {
+		d -= 0x60;
+		SET_FLAG(F_CF);
+	}
+	CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(d == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
+	return d;
+}
+
+/*
+ * REMARKS:
+ * Implements the DEC instruction and side effects.
+ */
+static uint8_t
+dec_byte(struct x86emu *emu, uint8_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - 1;
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	/* based on sub_byte, uses s==1.  */
+	bc = (res & (~d | 1)) | (~d & 1);
+	/* carry flag unchanged */
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the DEC instruction and side effects.
+ */
+static uint16_t
+dec_word(struct x86emu *emu, uint16_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - 1;
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	/* based on the sub_byte routine, with s==1 */
+	bc = (res & (~d | 1)) | (~d & 1);
+	/* carry flag unchanged */
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the DEC instruction and side effects.
+ */
+static uint32_t
+dec_long(struct x86emu *emu, uint32_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - 1;
+
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | 1)) | (~d & 1);
+	/* carry flag unchanged */
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the INC instruction and side effects.
+ */
+static uint8_t
+inc_byte(struct x86emu *emu, uint8_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	res = d + 1;
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = ((1 & d) | (~res)) & (1 | d);
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the INC instruction and side effects.
+ */
+static uint16_t
+inc_word(struct x86emu *emu, uint16_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	res = d + 1;
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (1 & d) | ((~res) & (1 | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the INC instruction and side effects.
+ */
+static uint32_t
+inc_long(struct x86emu *emu, uint32_t d)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t cc;
+
+	res = d + 1;
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the carry chain  SEE NOTE AT TOP. */
+	cc = (1 & d) | ((~res) & (1 | d));
+	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint8_t
+or_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint8_t res;	/* all operands in native machine order */
+
+	res = d | s;
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint16_t
+or_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint16_t res;	/* all operands in native machine order */
+
+	res = d | s;
+	/* set the carry flag to be bit 8 */
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint32_t
+or_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d | s;
+
+	/* set the carry flag to be bit 8 */
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint8_t
+neg_byte(struct x86emu *emu, uint8_t s)
+{
+	uint8_t res;
+	uint8_t bc;
+
+	CONDITIONAL_SET_FLAG(s != 0, F_CF);
+	res = (uint8_t) - s;
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+	/* calculate the borrow chain --- modified such that d=0.
+	 * substitutiing d=0 into     bc= res&(~d|s)|(~d&s); (the one used for
+	 * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
+	 * res&0xfff... == res.  Similarly ~d&s == s.  So the simplified
+	 * result is: */
+	bc = res | s;
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint16_t
+neg_word(struct x86emu *emu, uint16_t s)
+{
+	uint16_t res;
+	uint16_t bc;
+
+	CONDITIONAL_SET_FLAG(s != 0, F_CF);
+	res = (uint16_t) - s;
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain --- modified such that d=0.
+	 * substitutiing d=0 into     bc= res&(~d|s)|(~d&s); (the one used for
+	 * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
+	 * res&0xfff... == res.  Similarly ~d&s == s.  So the simplified
+	 * result is: */
+	bc = res | s;
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the OR instruction and side effects.
+ */
+static uint32_t
+neg_long(struct x86emu *emu, uint32_t s)
+{
+	uint32_t res;
+	uint32_t bc;
+
+	CONDITIONAL_SET_FLAG(s != 0, F_CF);
+	res = (uint32_t) - s;
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain --- modified such that d=0.
+	 * substitutiing d=0 into     bc= res&(~d|s)|(~d&s); (the one used for
+	 * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
+	 * res&0xfff... == res.  Similarly ~d&s == s.  So the simplified
+	 * result is: */
+	bc = res | s;
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCL instruction and side effects.
+ */
+static uint8_t
+rcl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask, cf;
+
+	/* s is the rotate distance.  It varies from 0 - 8. */
+	/* have
+	 *
+	 * CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+	 *
+	 * want to rotate through the carry by "s" bits.  We could loop, but
+	 * that's inefficient.  So the width is 9, and we split into three
+	 * parts:
+	 *
+	 * The new carry flag   (was B_n) the stuff in B_n-1 .. B_0 the stuff
+	 * in B_7 .. B_n+1
+	 *
+	 * The new rotate is done mod 9, and given this, for a rotation of n
+	 * bits (mod 9) the new carry flag is then located n bits from the MSB.
+	 * The low part is then shifted up cnt bits, and the high part is or'd
+	 * in.  Using CAPS for new values, and lowercase for the original
+	 * values, this can be expressed as:
+	 *
+	 * IF n > 0 1) CF <-  b_(8-n) 2) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0
+	 * 3) B_(n-1) <- cf 4) B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1))
+	 */
+	res = d;
+	if ((cnt = s % 9) != 0) {
+		/* extract the new CARRY FLAG. */
+		/* CF <-  b_(8-n)             */
+		cf = (d >> (8 - cnt)) & 0x1;
+
+		/*
+		 * Get the low stuff which rotated into the range B_7 .. B_cnt
+		 * B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0
+		 * note that the right hand side done by the mask.
+		 */
+		res = (d << cnt) & 0xff;
+
+		/*
+		 * now the high stuff which rotated around into the positions
+		 * B_cnt-2 .. B_0
+		 * B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1))
+		 * shift it downward, 7-(n-2) = 9-n positions. and mask off
+		 * the result before or'ing in.
+		 */
+		mask = (1 << (cnt - 1)) - 1;
+		res |= (d >> (9 - cnt)) & mask;
+
+		/* if the carry flag was set, or it in.  */
+		if (ACCESS_FLAG(F_CF)) {	/* carry flag is set */
+			/* B_(n-1) <- cf */
+			res |= 1 << (cnt - 1);
+		}
+		/* set the new carry flag, based on the variable "cf" */
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		/* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
+		 * the most significant bit.  Blecck. */
+		/* parenthesized this expression since it appears to be
+		 * causing OF to be misset */
+		CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
+		    F_OF);
+
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCL instruction and side effects.
+ */
+static uint16_t
+rcl_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask, cf;
+
+	res = d;
+	if ((cnt = s % 17) != 0) {
+		cf = (d >> (16 - cnt)) & 0x1;
+		res = (d << cnt) & 0xffff;
+		mask = (1 << (cnt - 1)) - 1;
+		res |= (d >> (17 - cnt)) & mask;
+		if (ACCESS_FLAG(F_CF)) {
+			res |= 1 << (cnt - 1);
+		}
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
+		    F_OF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCL instruction and side effects.
+ */
+static uint32_t
+rcl_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	uint32_t res, cnt, mask, cf;
+
+	res = d;
+	if ((cnt = s % 33) != 0) {
+		cf = (d >> (32 - cnt)) & 0x1;
+		res = (d << cnt) & 0xffffffff;
+		mask = (1 << (cnt - 1)) - 1;
+		res |= (d >> (33 - cnt)) & mask;
+		if (ACCESS_FLAG(F_CF)) {	/* carry flag is set */
+			res |= 1 << (cnt - 1);
+		}
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
+		    F_OF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCR instruction and side effects.
+ */
+static uint8_t
+rcr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res, cnt;
+	uint32_t mask, cf, ocf = 0;
+
+	/* rotate right through carry */
+	/* s is the rotate distance.  It varies from 0 - 8. d is the byte
+	 * object rotated.
+	 *
+	 * have
+	 *
+	 * CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+	 *
+	 * The new rotate is done mod 9, and given this, for a rotation of n
+	 * bits (mod 9) the new carry flag is then located n bits from the LSB.
+	 * The low part is then shifted up cnt bits, and the high part is or'd
+	 * in.  Using CAPS for new values, and lowercase for the original
+	 * values, this can be expressed as:
+	 *
+	 * IF n > 0
+	 *	1) CF <-  b_(n-1)
+	 *	2) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n)
+	 * 	3) B_(8-n) <- cf 4) B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0)
+	 */
+	res = d;
+	if ((cnt = s % 9) != 0) {
+		/* extract the new CARRY FLAG. */
+		/* CF <-  b_(n-1)              */
+		if (cnt == 1) {
+			cf = d & 0x1;
+			/* note hackery here.  Access_flag(..) evaluates to
+			 * either 0 if flag not set non-zero if flag is set.
+			 * doing access_flag(..) != 0 casts that into either
+			 * 0..1 in any representation of the flags register
+			 * (i.e. packed bit array or unpacked.) */
+			ocf = ACCESS_FLAG(F_CF) != 0;
+		} else
+			cf = (d >> (cnt - 1)) & 0x1;
+
+		/* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_n  */
+		/* note that the right hand side done by the mask This is
+		 * effectively done by shifting the object to the right.  The
+		 * result must be masked, in case the object came in and was
+		 * treated as a negative number.  Needed??? */
+
+		mask = (1 << (8 - cnt)) - 1;
+		res = (d >> cnt) & mask;
+
+		/* now the high stuff which rotated around into the positions
+		 * B_cnt-2 .. B_0 */
+		/* B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0) */
+		/* shift it downward, 7-(n-2) = 9-n positions. and mask off
+		 * the result before or'ing in. */
+		res |= (d << (9 - cnt));
+
+		/* if the carry flag was set, or it in.  */
+		if (ACCESS_FLAG(F_CF)) {	/* carry flag is set */
+			/* B_(8-n) <- cf */
+			res |= 1 << (8 - cnt);
+		}
+		/* set the new carry flag, based on the variable "cf" */
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		/* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
+		 * the most significant bit.  Blecck. */
+		/* parenthesized... */
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
+			    F_OF);
+		}
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCR instruction and side effects.
+ */
+static uint16_t
+rcr_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	uint32_t res, cnt;
+	uint32_t mask, cf, ocf = 0;
+
+	/* rotate right through carry */
+	res = d;
+	if ((cnt = s % 17) != 0) {
+		if (cnt == 1) {
+			cf = d & 0x1;
+			ocf = ACCESS_FLAG(F_CF) != 0;
+		} else
+			cf = (d >> (cnt - 1)) & 0x1;
+		mask = (1 << (16 - cnt)) - 1;
+		res = (d >> cnt) & mask;
+		res |= (d << (17 - cnt));
+		if (ACCESS_FLAG(F_CF)) {
+			res |= 1 << (16 - cnt);
+		}
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
+			    F_OF);
+		}
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the RCR instruction and side effects.
+ */
+static uint32_t
+rcr_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	uint32_t res, cnt;
+	uint32_t mask, cf, ocf = 0;
+
+	/* rotate right through carry */
+	res = d;
+	if ((cnt = s % 33) != 0) {
+		if (cnt == 1) {
+			cf = d & 0x1;
+			ocf = ACCESS_FLAG(F_CF) != 0;
+		} else
+			cf = (d >> (cnt - 1)) & 0x1;
+		mask = (1 << (32 - cnt)) - 1;
+		res = (d >> cnt) & mask;
+		if (cnt != 1)
+			res |= (d << (33 - cnt));
+		if (ACCESS_FLAG(F_CF)) {	/* carry flag is set */
+			res |= 1 << (32 - cnt);
+		}
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
+			    F_OF);
+		}
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROL instruction and side effects.
+ */
+static uint8_t
+rol_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask;
+
+	/* rotate left */
+	/* s is the rotate distance.  It varies from 0 - 8. d is the byte
+	 * object rotated.
+	 *
+	 * have
+	 *
+	 * CF  B_7 ... B_0
+	 *
+	 * The new rotate is done mod 8. Much simpler than the "rcl" or "rcr"
+	 * operations.
+	 *
+	 * IF n > 0 1) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) 2) B_(n-1) ..
+	 * B_(0) <-  b_(7) .. b_(8-n) */
+	res = d;
+	if ((cnt = s % 8) != 0) {
+		/* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) */
+		res = (d << cnt);
+
+		/* B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n) */
+		mask = (1 << cnt) - 1;
+		res |= (d >> (8 - cnt)) & mask;
+
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+		/* OVERFLOW is set *IFF* s==1, then it is the xor of CF and
+		 * the most significant bit.  Blecck. */
+		CONDITIONAL_SET_FLAG(s == 1 &&
+		    XOR2((res & 0x1) + ((res >> 6) & 0x2)),
+		    F_OF);
+	} if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROL instruction and side effects.
+ */
+static uint16_t
+rol_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask;
+
+	res = d;
+	if ((cnt = s % 16) != 0) {
+		res = (d << cnt);
+		mask = (1 << cnt) - 1;
+		res |= (d >> (16 - cnt)) & mask;
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+		CONDITIONAL_SET_FLAG(s == 1 &&
+		    XOR2((res & 0x1) + ((res >> 14) & 0x2)),
+		    F_OF);
+	} if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROL instruction and side effects.
+ */
+static uint32_t
+rol_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	uint32_t res, cnt, mask;
+
+	res = d;
+	if ((cnt = s % 32) != 0) {
+		res = (d << cnt);
+		mask = (1 << cnt) - 1;
+		res |= (d >> (32 - cnt)) & mask;
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+		CONDITIONAL_SET_FLAG(s == 1 &&
+		    XOR2((res & 0x1) + ((res >> 30) & 0x2)),
+		    F_OF);
+	} if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROR instruction and side effects.
+ */
+static uint8_t
+ror_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask;
+
+	/* rotate right */
+	/* s is the rotate distance.  It varies from 0 - 8. d is the byte
+	 * object rotated.
+	 *
+	 * have
+	 *
+	 * B_7 ... B_0
+	 *
+	 * The rotate is done mod 8.
+	 *
+	 * IF n > 0 1) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) 2) B_(7) ..
+	 * B_(8-n) <-  b_(n-1) .. b_(0) */
+	res = d;
+	if ((cnt = s % 8) != 0) {	/* not a typo, do nada if cnt==0 */
+		/* B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0) */
+		res = (d << (8 - cnt));
+
+		/* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) */
+		mask = (1 << (8 - cnt)) - 1;
+		res |= (d >> (cnt)) & mask;
+
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+		/* OVERFLOW is set *IFF* s==1, then it is the xor of the two
+		 * most significant bits.  Blecck. */
+		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
+	} else if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROR instruction and side effects.
+ */
+static uint16_t
+ror_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int res, cnt, mask;
+
+	res = d;
+	if ((cnt = s % 16) != 0) {
+		res = (d << (16 - cnt));
+		mask = (1 << (16 - cnt)) - 1;
+		res |= (d >> (cnt)) & mask;
+		CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
+	} else if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the ROR instruction and side effects.
+ */
+static uint32_t
+ror_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	uint32_t res, cnt, mask;
+
+	res = d;
+	if ((cnt = s % 32) != 0) {
+		res = (d << (32 - cnt));
+		mask = (1 << (32 - cnt)) - 1;
+		res |= (d >> (cnt)) & mask;
+		CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
+	} else if (s != 0) {
+		/* set the new carry flag, Note that it is the low order bit
+		 * of the result!!!                               */
+		CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHL instruction and side effects.
+ */
+static uint8_t
+shl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 8) {
+		cnt = s % 8;
+
+		/* last bit shifted out goes into carry flag */
+		if (cnt > 0) {
+			res = d << cnt;
+			cf = d & (1 << (8 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = (uint8_t) d;
+		}
+
+		if (cnt == 1) {
+			/* Needs simplification. */
+			CONDITIONAL_SET_FLAG(
+			    (((res & 0x80) == 0x80) ^
+				(ACCESS_FLAG(F_CF) != 0)),
+			/* was (emu->x86.R_FLG&F_CF)==F_CF)), */
+			    F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHL instruction and side effects.
+ */
+static uint16_t
+shl_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 16) {
+		cnt = s % 16;
+		if (cnt > 0) {
+			res = d << cnt;
+			cf = d & (1 << (16 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = (uint16_t) d;
+		}
+
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(
+			    (((res & 0x8000) == 0x8000) ^
+				(ACCESS_FLAG(F_CF) != 0)),
+			    F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHL instruction and side effects.
+ */
+static uint32_t
+shl_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 32) {
+		cnt = s % 32;
+		if (cnt > 0) {
+			res = d << cnt;
+			cf = d & (1 << (32 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
+			    ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHR instruction and side effects.
+ */
+static uint8_t
+shr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 8) {
+		cnt = s % 8;
+		if (cnt > 0) {
+			cf = d & (1 << (cnt - 1));
+			res = d >> cnt;
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = (uint8_t) d;
+		}
+
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHR instruction and side effects.
+ */
+static uint16_t
+shr_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 16) {
+		cnt = s % 16;
+		if (cnt > 0) {
+			cf = d & (1 << (cnt - 1));
+			res = d >> cnt;
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+		SET_FLAG(F_ZF);
+		CLEAR_FLAG(F_SF);
+		CLEAR_FLAG(F_PF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHR instruction and side effects.
+ */
+static uint32_t
+shr_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 32) {
+		cnt = s % 32;
+		if (cnt > 0) {
+			cf = d & (1 << (cnt - 1));
+			res = d >> cnt;
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+		SET_FLAG(F_ZF);
+		CLEAR_FLAG(F_SF);
+		CLEAR_FLAG(F_PF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SAR instruction and side effects.
+ */
+static uint8_t
+sar_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf, mask, sf;
+
+	res = d;
+	sf = d & 0x80;
+	cnt = s % 8;
+	if (cnt > 0 && cnt < 8) {
+		mask = (1 << (8 - cnt)) - 1;
+		cf = d & (1 << (cnt - 1));
+		res = (d >> cnt) & mask;
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		if (sf) {
+			res |= ~mask;
+		}
+		CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	} else if (cnt >= 8) {
+		if (sf) {
+			res = 0xff;
+			SET_FLAG(F_CF);
+			CLEAR_FLAG(F_ZF);
+			SET_FLAG(F_SF);
+			SET_FLAG(F_PF);
+		} else {
+			res = 0;
+			CLEAR_FLAG(F_CF);
+			SET_FLAG(F_ZF);
+			CLEAR_FLAG(F_SF);
+			CLEAR_FLAG(F_PF);
+		}
+	}
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SAR instruction and side effects.
+ */
+static uint16_t
+sar_word(struct x86emu *emu, uint16_t d, uint8_t s)
+{
+	unsigned int cnt, res, cf, mask, sf;
+
+	sf = d & 0x8000;
+	cnt = s % 16;
+	res = d;
+	if (cnt > 0 && cnt < 16) {
+		mask = (1 << (16 - cnt)) - 1;
+		cf = d & (1 << (cnt - 1));
+		res = (d >> cnt) & mask;
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		if (sf) {
+			res |= ~mask;
+		}
+		CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+		CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	} else if (cnt >= 16) {
+		if (sf) {
+			res = 0xffff;
+			SET_FLAG(F_CF);
+			CLEAR_FLAG(F_ZF);
+			SET_FLAG(F_SF);
+			SET_FLAG(F_PF);
+		} else {
+			res = 0;
+			CLEAR_FLAG(F_CF);
+			SET_FLAG(F_ZF);
+			CLEAR_FLAG(F_SF);
+			CLEAR_FLAG(F_PF);
+		}
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SAR instruction and side effects.
+ */
+static uint32_t
+sar_long(struct x86emu *emu, uint32_t d, uint8_t s)
+{
+	uint32_t cnt, res, cf, mask, sf;
+
+	sf = d & 0x80000000;
+	cnt = s % 32;
+	res = d;
+	if (cnt > 0 && cnt < 32) {
+		mask = (1 << (32 - cnt)) - 1;
+		cf = d & (1 << (cnt - 1));
+		res = (d >> cnt) & mask;
+		CONDITIONAL_SET_FLAG(cf, F_CF);
+		if (sf) {
+			res |= ~mask;
+		}
+		CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+		CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	} else if (cnt >= 32) {
+		if (sf) {
+			res = 0xffffffff;
+			SET_FLAG(F_CF);
+			CLEAR_FLAG(F_ZF);
+			SET_FLAG(F_SF);
+			SET_FLAG(F_PF);
+		} else {
+			res = 0;
+			CLEAR_FLAG(F_CF);
+			SET_FLAG(F_ZF);
+			CLEAR_FLAG(F_SF);
+			CLEAR_FLAG(F_PF);
+		}
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHLD instruction and side effects.
+ */
+static uint16_t
+shld_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 16) {
+		cnt = s % 16;
+		if (cnt > 0) {
+			res = (d << cnt) | (fill >> (16 - cnt));
+			cf = d & (1 << (16 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
+				(ACCESS_FLAG(F_CF) != 0)), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHLD instruction and side effects.
+ */
+static uint32_t
+shld_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 32) {
+		cnt = s % 32;
+		if (cnt > 0) {
+			res = (d << cnt) | (fill >> (32 - cnt));
+			cf = d & (1 << (32 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
+			    ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
+		CLEAR_FLAG(F_OF);
+		CLEAR_FLAG(F_SF);
+		SET_FLAG(F_PF);
+		SET_FLAG(F_ZF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHRD instruction and side effects.
+ */
+static uint16_t
+shrd_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 16) {
+		cnt = s % 16;
+		if (cnt > 0) {
+			cf = d & (1 << (cnt - 1));
+			res = (d >> cnt) | (fill << (16 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+		SET_FLAG(F_ZF);
+		CLEAR_FLAG(F_SF);
+		CLEAR_FLAG(F_PF);
+	}
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SHRD instruction and side effects.
+ */
+static uint32_t
+shrd_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
+{
+	unsigned int cnt, res, cf;
+
+	if (s < 32) {
+		cnt = s % 32;
+		if (cnt > 0) {
+			cf = d & (1 << (cnt - 1));
+			res = (d >> cnt) | (fill << (32 - cnt));
+			CONDITIONAL_SET_FLAG(cf, F_CF);
+			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+		} else {
+			res = d;
+		}
+		if (cnt == 1) {
+			CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+		} else {
+			CLEAR_FLAG(F_OF);
+		}
+	} else {
+		res = 0;
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+		SET_FLAG(F_ZF);
+		CLEAR_FLAG(F_SF);
+		CLEAR_FLAG(F_PF);
+	}
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SBB instruction and side effects.
+ */
+static uint8_t
+sbb_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	if (ACCESS_FLAG(F_CF))
+		res = d - s - 1;
+	else
+		res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SBB instruction and side effects.
+ */
+static uint16_t
+sbb_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	if (ACCESS_FLAG(F_CF))
+		res = d - s - 1;
+	else
+		res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SBB instruction and side effects.
+ */
+static uint32_t
+sbb_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	if (ACCESS_FLAG(F_CF))
+		res = d - s - 1;
+	else
+		res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SUB instruction and side effects.
+ */
+static uint8_t
+sub_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint8_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SUB instruction and side effects.
+ */
+static uint16_t
+sub_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return (uint16_t) res;
+}
+
+/*
+ * REMARKS:
+ * Implements the SUB instruction and side effects.
+ */
+static uint32_t
+sub_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+	uint32_t bc;
+
+	res = d - s;
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+
+	/* calculate the borrow chain.  See note at top */
+	bc = (res & (~d | s)) | (~d & s);
+	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the TEST instruction and side effects.
+ */
+static void
+test_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	/* AF == dont care */
+	CLEAR_FLAG(F_CF);
+}
+
+/*
+ * REMARKS:
+ * Implements the TEST instruction and side effects.
+ */
+static void
+test_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	/* AF == dont care */
+	CLEAR_FLAG(F_CF);
+}
+
+/*
+ * REMARKS:
+ * Implements the TEST instruction and side effects.
+ */
+static void
+test_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d & s;
+
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	/* AF == dont care */
+	CLEAR_FLAG(F_CF);
+}
+
+/*
+ * REMARKS:
+ * Implements the XOR instruction and side effects.
+ */
+static uint8_t
+xor_byte(struct x86emu *emu, uint8_t d, uint8_t s)
+{
+	uint8_t res;	/* all operands in native machine order */
+
+	res = d ^ s;
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the XOR instruction and side effects.
+ */
+static uint16_t
+xor_word(struct x86emu *emu, uint16_t d, uint16_t s)
+{
+	uint16_t res;	/* all operands in native machine order */
+
+	res = d ^ s;
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the XOR instruction and side effects.
+ */
+static uint32_t
+xor_long(struct x86emu *emu, uint32_t d, uint32_t s)
+{
+	uint32_t res;	/* all operands in native machine order */
+
+	res = d ^ s;
+	CLEAR_FLAG(F_OF);
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Implements the IMUL instruction and side effects.
+ */
+static void
+imul_byte(struct x86emu *emu, uint8_t s)
+{
+	int16_t res = (int16_t) ((int8_t) emu->x86.R_AL * (int8_t) s);
+
+	emu->x86.R_AX = res;
+	if (((emu->x86.R_AL & 0x80) == 0 && emu->x86.R_AH == 0x00) ||
+	    ((emu->x86.R_AL & 0x80) != 0 && emu->x86.R_AH == 0xFF)) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the IMUL instruction and side effects.
+ */
+static void
+imul_word(struct x86emu *emu, uint16_t s)
+{
+	int32_t res = (int16_t) emu->x86.R_AX * (int16_t) s;
+
+	emu->x86.R_AX = (uint16_t) res;
+	emu->x86.R_DX = (uint16_t) (res >> 16);
+	if (((emu->x86.R_AX & 0x8000) == 0 && emu->x86.R_DX == 0x00) ||
+	    ((emu->x86.R_AX & 0x8000) != 0 && emu->x86.R_DX == 0xFF)) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the IMUL instruction and side effects.
+ */
+static void
+imul_long(struct x86emu *emu, uint32_t s)
+{
+	int64_t res;
+
+	res = (int64_t)(int32_t)emu->x86.R_EAX * (int32_t)s;
+	emu->x86.R_EAX = (uint32_t)res;
+	emu->x86.R_EDX = ((uint64_t)res) >> 32;
+	if (((emu->x86.R_EAX & 0x80000000) == 0 && emu->x86.R_EDX == 0x00) ||
+	    ((emu->x86.R_EAX & 0x80000000) != 0 && emu->x86.R_EDX == 0xFF)) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the MUL instruction and side effects.
+ */
+static void
+mul_byte(struct x86emu *emu, uint8_t s)
+{
+	uint16_t res = (uint16_t) (emu->x86.R_AL * s);
+
+	emu->x86.R_AX = res;
+	if (emu->x86.R_AH == 0) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the MUL instruction and side effects.
+ */
+static void
+mul_word(struct x86emu *emu, uint16_t s)
+{
+	uint32_t res = emu->x86.R_AX * s;
+
+	emu->x86.R_AX = (uint16_t) res;
+	emu->x86.R_DX = (uint16_t) (res >> 16);
+	if (emu->x86.R_DX == 0) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the MUL instruction and side effects.
+ */
+static void
+mul_long(struct x86emu *emu, uint32_t s)
+{
+	uint64_t res = (uint64_t) emu->x86.R_EAX * s;
+
+	emu->x86.R_EAX = (uint32_t) res;
+	emu->x86.R_EDX = (uint32_t) (res >> 32);
+
+	if (emu->x86.R_EDX == 0) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	} else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the IDIV instruction and side effects.
+ */
+static void
+idiv_byte(struct x86emu *emu, uint8_t s)
+{
+	int32_t dvd, div, mod;
+
+	dvd = (int16_t) emu->x86.R_AX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (int8_t) s;
+	mod = dvd % (int8_t) s;
+	if (div > 0x7f || div < -0x7f) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	emu->x86.R_AL = (int8_t) div;
+	emu->x86.R_AH = (int8_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the IDIV instruction and side effects.
+ */
+static void
+idiv_word(struct x86emu *emu, uint16_t s)
+{
+	int32_t dvd, div, mod;
+
+	dvd = (((int32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (int16_t) s;
+	mod = dvd % (int16_t) s;
+	if (div > 0x7fff || div < -0x7fff) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_SF);
+	CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+	emu->x86.R_AX = (uint16_t) div;
+	emu->x86.R_DX = (uint16_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the IDIV instruction and side effects.
+ */
+static void
+idiv_long(struct x86emu *emu, uint32_t s)
+{
+	int64_t dvd, div, mod;
+
+	dvd = (((int64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (int32_t) s;
+	mod = dvd % (int32_t) s;
+	if (div > 0x7fffffff || div < -0x7fffffff) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+	emu->x86.R_EAX = (uint32_t) div;
+	emu->x86.R_EDX = (uint32_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the DIV instruction and side effects.
+ */
+static void
+div_byte(struct x86emu *emu, uint8_t s)
+{
+	uint32_t dvd, div, mod;
+
+	dvd = emu->x86.R_AX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (uint8_t) s;
+	mod = dvd % (uint8_t) s;
+	if (div > 0xff) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	emu->x86.R_AL = (uint8_t) div;
+	emu->x86.R_AH = (uint8_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the DIV instruction and side effects.
+ */
+static void
+div_word(struct x86emu *emu, uint16_t s)
+{
+	uint32_t dvd, div, mod;
+
+	dvd = (((uint32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (uint16_t) s;
+	mod = dvd % (uint16_t) s;
+	if (div > 0xffff) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_SF);
+	CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+	emu->x86.R_AX = (uint16_t) div;
+	emu->x86.R_DX = (uint16_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the DIV instruction and side effects.
+ */
+static void
+div_long(struct x86emu *emu, uint32_t s)
+{
+	uint64_t dvd, div, mod;
+
+	dvd = (((uint64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
+	if (s == 0) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	div = dvd / (uint32_t) s;
+	mod = dvd % (uint32_t) s;
+	if (div > 0xffffffff) {
+		x86emu_intr_raise(emu, 8);
+		return;
+	}
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_ZF);
+	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
+
+	emu->x86.R_EAX = (uint32_t) div;
+	emu->x86.R_EDX = (uint32_t) mod;
+}
+
+/*
+ * REMARKS:
+ * Implements the IN string instruction and side effects.
+ */
+static void
+ins(struct x86emu *emu, int size)
+{
+	int inc = size;
+
+	if (ACCESS_FLAG(F_DF)) {
+		inc = -size;
+	}
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* in until CX is ZERO. */
+		uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
+		    emu->x86.R_ECX : emu->x86.R_CX);
+		switch (size) {
+		case 1:
+			while (count--) {
+				store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
+				    (*emu->emu_inb) (emu, emu->x86.R_DX));
+				emu->x86.R_DI += inc;
+			}
+			break;
+
+		case 2:
+			while (count--) {
+				store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
+				    (*emu->emu_inw) (emu, emu->x86.R_DX));
+				emu->x86.R_DI += inc;
+			}
+			break;
+		case 4:
+			while (count--) {
+				store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
+				    (*emu->emu_inl) (emu, emu->x86.R_DX));
+				emu->x86.R_DI += inc;
+				break;
+			}
+		}
+		emu->x86.R_CX = 0;
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			emu->x86.R_ECX = 0;
+		}
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	} else {
+		switch (size) {
+		case 1:
+			store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    (*emu->emu_inb) (emu, emu->x86.R_DX));
+			break;
+		case 2:
+			store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    (*emu->emu_inw) (emu, emu->x86.R_DX));
+			break;
+		case 4:
+			store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
+			    (*emu->emu_inl) (emu, emu->x86.R_DX));
+			break;
+		}
+		emu->x86.R_DI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Implements the OUT string instruction and side effects.
+ */
+static void
+outs(struct x86emu *emu, int size)
+{
+	int inc = size;
+
+	if (ACCESS_FLAG(F_DF)) {
+		inc = -size;
+	}
+	if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+		/* dont care whether REPE or REPNE */
+		/* out until CX is ZERO. */
+		uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
+		    emu->x86.R_ECX : emu->x86.R_CX);
+		switch (size) {
+		case 1:
+			while (count--) {
+				(*emu->emu_outb) (emu, emu->x86.R_DX,
+				    fetch_byte(emu, emu->x86.R_ES,
+				    emu->x86.R_SI));
+				emu->x86.R_SI += inc;
+			}
+			break;
+
+		case 2:
+			while (count--) {
+				(*emu->emu_outw) (emu, emu->x86.R_DX,
+				    fetch_word(emu, emu->x86.R_ES,
+				    emu->x86.R_SI));
+				emu->x86.R_SI += inc;
+			}
+			break;
+		case 4:
+			while (count--) {
+				(*emu->emu_outl) (emu, emu->x86.R_DX,
+				    fetch_long(emu, emu->x86.R_ES,
+				    emu->x86.R_SI));
+				emu->x86.R_SI += inc;
+				break;
+			}
+		}
+		emu->x86.R_CX = 0;
+		if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
+			emu->x86.R_ECX = 0;
+		}
+		emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+	} else {
+		switch (size) {
+		case 1:
+			(*emu->emu_outb) (emu, emu->x86.R_DX,
+			    fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI));
+			break;
+		case 2:
+			(*emu->emu_outw) (emu, emu->x86.R_DX,
+			    fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI));
+			break;
+		case 4:
+			(*emu->emu_outl) (emu, emu->x86.R_DX,
+			    fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI));
+			break;
+		}
+		emu->x86.R_SI += inc;
+	}
+}
+
+/*
+ * REMARKS:
+ * Pushes a word onto the stack.
+ *
+ * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
+ */
+static void
+push_word(struct x86emu *emu, uint16_t w)
+{
+	emu->x86.R_SP -= 2;
+	store_word(emu, emu->x86.R_SS, emu->x86.R_SP, w);
+}
+
+/*
+ * REMARKS:
+ * Pushes a long onto the stack.
+ *
+ * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
+ */
+static void
+push_long(struct x86emu *emu, uint32_t w)
+{
+	emu->x86.R_SP -= 4;
+	store_long(emu, emu->x86.R_SS, emu->x86.R_SP, w);
+}
+
+/*
+ * REMARKS:
+ * Pops a word from the stack.
+ *
+ * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
+ */
+static uint16_t
+pop_word(struct x86emu *emu)
+{
+	uint16_t res;
+
+	res = fetch_word(emu, emu->x86.R_SS, emu->x86.R_SP);
+	emu->x86.R_SP += 2;
+	return res;
+}
+
+/*
+ * REMARKS:
+ * Pops a long from the stack.
+ *
+ * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
+ */
+static uint32_t
+pop_long(struct x86emu *emu)
+{
+	uint32_t res;
+
+	res = fetch_long(emu, emu->x86.R_SS, emu->x86.R_SP);
+	emu->x86.R_SP += 4;
+	return res;
+}
diff --git a/sys/emulation/x86emu/x86emu.h b/sys/emulation/x86emu/x86emu.h
new file mode 100644
index 0000000..497771a
--- /dev/null
+++ b/sys/emulation/x86emu/x86emu.h
@@ -0,0 +1,184 @@
+/*	$NetBSD: x86emu.h,v 1.1 2007/12/01 20:14:10 joerg Exp $	*/
+/*	$OpenBSD: x86emu.h,v 1.3 2009/06/06 03:45:05 matthieu Exp $ */
+/*	$FreeBSD: src/sys/contrib/x86emu/x86emu.h,v 1.2 2009/09/09 05:53:26 delphij Exp $	*/
+
+/****************************************************************************
+*
+*  Realmode X86 Emulator Library
+*
+*  Copyright (C) 1996-1999 SciTech Software, Inc.
+*  Copyright (C) David Mosberger-Tang
+*  Copyright (C) 1999 Egbert Eich
+*  Copyright (C) 2007 Joerg Sonnenberger
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_X86EMU_H
+#define __X86EMU_X86EMU_H
+
+#include <sys/types.h>
+#include <sys/endian.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <machine/setjmp.h>
+#else
+#include <setjmp.h>
+#endif
+
+/*
+ * General EAX, EBX, ECX, EDX type registers.  Note that for
+ * portability, and speed, the issue of byte swapping is not addressed
+ * in the registers.  All registers are stored in the default format
+ * available on the host machine.  The only critical issue is that the
+ * registers should line up EXACTLY in the same manner as they do in
+ * the 386.  That is:
+ *
+ * EAX & 0xff  === AL
+ * EAX & 0xffff == AX
+ *
+ * etc.  The result is that alot of the calculations can then be
+ * done using the native instruction set fully.
+ */
+
+#ifdef	__BIG_ENDIAN__
+
+struct x86emu_register32 {
+	uint32_t e_reg;
+};
+
+struct x86emu_register16 {
+	uint16_t filler0;
+	uint16_t x_reg;
+};
+
+struct x86emu_register8 {
+	uint8_t filler0, filler1;
+	uint8_t h_reg, l_reg;
+};
+
+#else /* !__BIG_ENDIAN__ */
+
+struct x86emu_register32 {
+	uint32_t e_reg;
+};
+
+struct x86emu_register16 {
+	uint16_t x_reg;
+};
+
+struct x86emu_register8 {
+	uint8_t l_reg, h_reg;
+};
+
+#endif /* BIG_ENDIAN */
+
+union x86emu_register {
+	struct x86emu_register32	I32_reg;
+	struct x86emu_register16	I16_reg;
+	struct x86emu_register8		I8_reg;
+};
+
+struct x86emu_regs {
+	uint16_t		register_cs;
+	uint16_t		register_ds;
+	uint16_t		register_es;
+	uint16_t		register_fs;
+	uint16_t		register_gs;
+	uint16_t		register_ss;
+	uint32_t		register_flags;
+	union x86emu_register	register_a;
+	union x86emu_register	register_b;
+	union x86emu_register	register_c;
+	union x86emu_register	register_d;
+
+	union x86emu_register	register_sp;
+	union x86emu_register	register_bp;
+	union x86emu_register	register_si;
+	union x86emu_register	register_di;
+	union x86emu_register	register_ip;
+
+	/*
+	 * MODE contains information on:
+	 *  REPE prefix             2 bits  repe,repne
+	 *  SEGMENT overrides       5 bits  normal,DS,SS,CS,ES
+	 *  Delayed flag set        3 bits  (zero, signed, parity)
+	 *  reserved                6 bits
+	 *  interrupt #             8 bits  instruction raised interrupt
+	 *  BIOS video segregs      4 bits
+	 *  Interrupt Pending       1 bits
+	 *  Extern interrupt        1 bits
+	 *  Halted                  1 bits
+	 */
+	uint32_t		mode;
+	volatile int		intr;   /* mask of pending interrupts */
+	uint8_t			intno;
+	uint8_t			__pad[3];
+};
+
+struct x86emu {
+	char			*mem_base;
+	size_t			mem_size;
+	void        		*sys_private;
+	struct x86emu_regs	x86;
+
+	jmp_buf		exec_state;
+
+	uint64_t	cur_cycles;
+
+	unsigned int	cur_mod:2;
+	unsigned int	cur_rl:3;
+	unsigned int	cur_rh:3;
+	uint32_t	cur_offset;
+
+	uint8_t  	(*emu_rdb)(struct x86emu *, uint32_t addr);
+	uint16_t 	(*emu_rdw)(struct x86emu *, uint32_t addr);
+	uint32_t 	(*emu_rdl)(struct x86emu *, uint32_t addr);
+	void		(*emu_wrb)(struct x86emu *, uint32_t addr,uint8_t val);
+	void		(*emu_wrw)(struct x86emu *, uint32_t addr, uint16_t val);
+	void		(*emu_wrl)(struct x86emu *, uint32_t addr, uint32_t val);
+
+	uint8_t  	(*emu_inb)(struct x86emu *, uint16_t addr);
+	uint16_t 	(*emu_inw)(struct x86emu *, uint16_t addr);
+	uint32_t 	(*emu_inl)(struct x86emu *, uint16_t addr);
+	void		(*emu_outb)(struct x86emu *, uint16_t addr, uint8_t val);
+	void		(*emu_outw)(struct x86emu *, uint16_t addr, uint16_t val);
+	void		(*emu_outl)(struct x86emu *, uint16_t addr, uint32_t val);
+
+	void 		(*_x86emu_intrTab[256])(struct x86emu *, int);
+};
+
+__BEGIN_DECLS
+
+void	x86emu_init_default(struct x86emu *);
+
+/* decode.c */
+
+void 	x86emu_exec(struct x86emu *);
+void	x86emu_exec_call(struct x86emu *, uint16_t, uint16_t);
+void	x86emu_exec_intr(struct x86emu *, uint8_t);
+void 	x86emu_halt_sys(struct x86emu *) __dead2;
+
+__END_DECLS
+
+#endif /* __X86EMU_X86EMU_H */
diff --git a/sys/emulation/x86emu/x86emu_regs.h b/sys/emulation/x86emu/x86emu_regs.h
new file mode 100644
index 0000000..5b49e8a
--- /dev/null
+++ b/sys/emulation/x86emu/x86emu_regs.h
@@ -0,0 +1,170 @@
+/*	$NetBSD: x86emu_regs.h,v 1.1 2007/12/01 20:14:10 joerg Exp $	*/
+/*	$OpenBSD: x86emu_regs.h,v 1.2 2009/06/06 03:45:05 matthieu Exp $ */
+
+/****************************************************************************
+*
+*  Realmode X86 Emulator Library
+*
+*  Copyright (C) 1996-1999 SciTech Software, Inc.
+*  Copyright (C) David Mosberger-Tang
+*  Copyright (C) 1999 Egbert Eich
+*  Copyright (C) 2007 Joerg Sonnenberger
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_REGS_H
+#define __X86EMU_REGS_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* 8 bit registers */
+#define R_AH  register_a.I8_reg.h_reg
+#define R_AL  register_a.I8_reg.l_reg
+#define R_BH  register_b.I8_reg.h_reg
+#define R_BL  register_b.I8_reg.l_reg
+#define R_CH  register_c.I8_reg.h_reg
+#define R_CL  register_c.I8_reg.l_reg
+#define R_DH  register_d.I8_reg.h_reg
+#define R_DL  register_d.I8_reg.l_reg
+
+/* 16 bit registers */
+#define R_AX  register_a.I16_reg.x_reg
+#define R_BX  register_b.I16_reg.x_reg
+#define R_CX  register_c.I16_reg.x_reg
+#define R_DX  register_d.I16_reg.x_reg
+
+/* 32 bit extended registers */
+#define R_EAX  register_a.I32_reg.e_reg
+#define R_EBX  register_b.I32_reg.e_reg
+#define R_ECX  register_c.I32_reg.e_reg
+#define R_EDX  register_d.I32_reg.e_reg
+
+/* special registers */
+#define R_SP  register_sp.I16_reg.x_reg
+#define R_BP  register_bp.I16_reg.x_reg
+#define R_SI  register_si.I16_reg.x_reg
+#define R_DI  register_di.I16_reg.x_reg
+#define R_IP  register_ip.I16_reg.x_reg
+#define R_FLG register_flags
+
+/* special registers */
+#define R_ESP  register_sp.I32_reg.e_reg
+#define R_EBP  register_bp.I32_reg.e_reg
+#define R_ESI  register_si.I32_reg.e_reg
+#define R_EDI  register_di.I32_reg.e_reg
+#define R_EIP  register_ip.I32_reg.e_reg
+#define R_EFLG register_flags
+
+/* segment registers */
+#define R_CS  register_cs
+#define R_DS  register_ds
+#define R_SS  register_ss
+#define R_ES  register_es
+#define R_FS  register_fs
+#define R_GS  register_gs
+
+/* flag conditions   */
+#define FB_CF 0x0001            /* CARRY flag  */
+#define FB_PF 0x0004            /* PARITY flag */
+#define FB_AF 0x0010            /* AUX  flag   */
+#define FB_ZF 0x0040            /* ZERO flag   */
+#define FB_SF 0x0080            /* SIGN flag   */
+#define FB_TF 0x0100            /* TRAP flag   */
+#define FB_IF 0x0200            /* INTERRUPT ENABLE flag */
+#define FB_DF 0x0400            /* DIR flag    */
+#define FB_OF 0x0800            /* OVERFLOW flag */
+
+/* 80286 and above always have bit#1 set */
+#define F_ALWAYS_ON  (0x0002)   /* flag bits always on */
+
+/*
+ * Define a mask for only those flag bits we will ever pass back
+ * (via PUSHF)
+ */
+#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF)
+
+/* following bits masked in to a 16bit quantity */
+
+#define F_CF 0x0001             /* CARRY flag  */
+#define F_PF 0x0004             /* PARITY flag */
+#define F_AF 0x0010             /* AUX  flag   */
+#define F_ZF 0x0040             /* ZERO flag   */
+#define F_SF 0x0080             /* SIGN flag   */
+#define F_TF 0x0100             /* TRAP flag   */
+#define F_IF 0x0200             /* INTERRUPT ENABLE flag */
+#define F_DF 0x0400             /* DIR flag    */
+#define F_OF 0x0800             /* OVERFLOW flag */
+
+#define SET_FLAG(flag)        	(emu->x86.R_FLG |= (flag))
+#define CLEAR_FLAG(flag)      	(emu->x86.R_FLG &= ~(flag))
+#define ACCESS_FLAG(flag)     	(emu->x86.R_FLG & (flag))
+#define CLEARALL_FLAG(m)    	(emu->x86.R_FLG = 0)
+
+#define CONDITIONAL_SET_FLAG(COND,FLAG) \
+  if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG)
+
+#define F_PF_CALC 0x010000      /* PARITY flag has been calced    */
+#define F_ZF_CALC 0x020000      /* ZERO flag has been calced      */
+#define F_SF_CALC 0x040000      /* SIGN flag has been calced      */
+
+#define F_ALL_CALC      0xff0000        /* All have been calced   */
+
+/*
+ * Emulator machine state.
+ * Segment usage control.
+ */
+#define SYSMODE_SEG_DS_SS       0x00000001
+#define SYSMODE_SEGOVR_CS       0x00000002
+#define SYSMODE_SEGOVR_DS       0x00000004
+#define SYSMODE_SEGOVR_ES       0x00000008
+#define SYSMODE_SEGOVR_FS       0x00000010
+#define SYSMODE_SEGOVR_GS       0x00000020
+#define SYSMODE_SEGOVR_SS       0x00000040
+#define SYSMODE_PREFIX_REPE     0x00000080
+#define SYSMODE_PREFIX_REPNE    0x00000100
+#define SYSMODE_PREFIX_DATA     0x00000200
+#define SYSMODE_PREFIX_ADDR     0x00000400
+#define SYSMODE_INTR_PENDING    0x10000000
+#define SYSMODE_EXTRN_INTR      0x20000000
+#define SYSMODE_HALTED          0x40000000
+
+#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS      | \
+						 SYSMODE_SEGOVR_CS      | \
+						 SYSMODE_SEGOVR_DS      | \
+						 SYSMODE_SEGOVR_ES      | \
+						 SYSMODE_SEGOVR_FS      | \
+						 SYSMODE_SEGOVR_GS      | \
+						 SYSMODE_SEGOVR_SS)
+#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS      | \
+						 SYSMODE_SEGOVR_CS      | \
+						 SYSMODE_SEGOVR_DS      | \
+						 SYSMODE_SEGOVR_ES      | \
+						 SYSMODE_SEGOVR_FS      | \
+						 SYSMODE_SEGOVR_GS      | \
+						 SYSMODE_SEGOVR_SS      | \
+						 SYSMODE_PREFIX_DATA    | \
+						 SYSMODE_PREFIX_ADDR)
+
+#define  INTR_SYNCH           0x1
+
+#endif /* __X86EMU_REGS_H */
-- 
1.6.6.1

