summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/amd64/conf/files.amd643
-rw-r--r--sys/arch/amd64/include/vga_post.h43
-rw-r--r--sys/arch/amd64/pci/vga_post.c230
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/arch/i386/conf/files.i3863
-rw-r--r--sys/arch/i386/include/vga_post.h43
-rw-r--r--sys/arch/i386/pci/vga_post.c231
-rw-r--r--sys/conf/files5
-rw-r--r--sys/dev/pci/vga_pci.c12
-rw-r--r--sys/dev/pci/vga_pcivar.h5
-rw-r--r--sys/dev/x86emu/x86emu.c8102
-rw-r--r--sys/dev/x86emu/x86emu.h186
-rw-r--r--sys/dev/x86emu/x86emu_regs.h170
-rw-r--r--sys/dev/x86emu/x86emu_util.c158
15 files changed, 9190 insertions, 7 deletions
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 25a3c1bac64..10ffde59e04 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.267 2009/06/03 07:13:48 pirofti Exp $
+# $OpenBSD: GENERIC,v 1.268 2009/06/06 00:35:00 pirofti Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -275,6 +275,7 @@ pckbd* at pckbc? # PC keyboard
pms* at pckbc? # PS/2 mouse for wsmouse
pmsi* at pckbc? # PS/2 "Intelli"mouse for wsmouse
vga0 at isa?
+option VGA_POST # we can repost video cards
vga* at pci?
wsdisplay* at vga?
wskbd* at pckbd? mux 1
diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64
index d60980af530..ef617ff155b 100644
--- a/sys/arch/amd64/conf/files.amd64
+++ b/sys/arch/amd64/conf/files.amd64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.amd64,v 1.49 2009/05/31 03:20:10 matthieu Exp $
+# $OpenBSD: files.amd64,v 1.50 2009/06/06 00:35:00 pirofti Exp $
maxpartitions 16
maxusers 2 16 128
@@ -109,6 +109,7 @@ include "dev/pci/files.pci"
file arch/amd64/pci/pci_machdep.c pci
file arch/amd64/pci/iommu.c pci
file arch/amd64/pci/pciide_machdep.c pciide
+file arch/amd64/pci/vga_post.c vga_pci & vga_post
include "dev/puc/files.puc"
diff --git a/sys/arch/amd64/include/vga_post.h b/sys/arch/amd64/include/vga_post.h
new file mode 100644
index 00000000000..36a9a2d4680
--- /dev/null
+++ b/sys/arch/amd64/include/vga_post.h
@@ -0,0 +1,43 @@
+/* $NetBSD: vga_post.h,v 1.2 2008/03/29 17:40:22 jmcneill Exp $ */
+/* $OpenBSD: vga_post.h,v 1.1 2009/06/06 00:35:00 pirofti Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef _X86_VGA_POST_H_
+#define _X86_VGA_POST_H_
+
+#ifdef _KERNEL
+struct vga_post;
+
+struct vga_post *vga_post_init(int, int, int);
+void vga_post_free(struct vga_post *);
+void vga_post_call(struct vga_post *);
+#endif
+#endif
diff --git a/sys/arch/amd64/pci/vga_post.c b/sys/arch/amd64/pci/vga_post.c
new file mode 100644
index 00000000000..35f6840acf1
--- /dev/null
+++ b/sys/arch/amd64/pci/vga_post.c
@@ -0,0 +1,230 @@
+/* $NetBSD: vga_post.c,v 1.12 2009/03/15 21:32:36 cegger Exp $ */
+/* $OpenBSD: vga_post.c,v 1.1 2009/06/06 00:35:00 pirofti Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <uvm/uvm_extern.h>
+#include <uvm/uvm_page.h>
+
+#include <machine/pio.h>
+
+#include <machine/vga_post.h>
+
+#include <lib/libkern/x86emu.h>
+#include <lib/libkern/x86emu_regs.h>
+
+#define BASE_MEMORY 65536 /* How much memory to allocate in Real Mode */
+
+struct vga_post {
+ struct X86EMU emu;
+ vaddr_t sys_image;
+ uint32_t initial_eax;
+ uint8_t bios_data[PAGE_SIZE];
+ struct pglist ram_backing;
+};
+
+#ifdef DDB
+static struct vga_post *ddb_vgapostp;
+void ddb_vgapost(void);
+#endif
+
+static uint8_t
+vm86_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
+vm86_emu_inw(struct X86EMU *emu, uint16_t port)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return 0;
+
+ return inw(port);
+}
+
+static uint32_t
+vm86_emu_inl(struct X86EMU *emu, uint16_t port)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return 0;
+
+ return inl(port);
+}
+
+static void
+vm86_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
+vm86_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
+vm86_emu_outl(struct X86EMU *emu, uint16_t port, uint32_t val)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return;
+
+ outl(port, val);
+}
+
+struct vga_post *
+vga_post_init(int bus, int device, int function)
+{
+ struct vga_post *sc;
+ vaddr_t iter;
+ struct vm_page *pg;
+ vaddr_t sys_image, sys_bios_data;
+ int err;
+
+ sys_bios_data = uvm_km_valloc(kernel_map, PAGE_SIZE);
+ if (sys_bios_data == 0)
+ return NULL;
+
+ sys_image = uvm_km_valloc(kernel_map, 1024 * 1024);
+ if (sys_image == 0) {
+ uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
+ return NULL;
+ }
+ sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
+
+ err = uvm_pglistalloc(BASE_MEMORY, 0, (paddr_t)-1, 0, 0,
+ &sc->ram_backing, BASE_MEMORY/PAGE_SIZE, UVM_PLA_WAITOK);
+ if (err) {
+ uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
+ free(sc, M_DEVBUF);
+ return NULL;
+ }
+
+ sc->sys_image = sys_image;
+ sc->emu.sys_private = sc;
+
+ pmap_kenter_pa(sys_bios_data, 0, VM_PROT_READ);
+ pmap_update(pmap_kernel());
+ memcpy((void *)sc->bios_data, (void *)sys_bios_data, PAGE_SIZE);
+ pmap_kremove(sys_bios_data, PAGE_SIZE);
+ uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
+
+ iter = 0;
+ TAILQ_FOREACH(pg, &sc->ram_backing, pageq) {
+ pmap_kenter_pa(sc->sys_image + iter, VM_PAGE_TO_PHYS(pg),
+ VM_PROT_READ | VM_PROT_WRITE);
+ iter += PAGE_SIZE;
+ }
+ KASSERT(iter == 65536);
+
+ for (iter = 640 * 1024; iter < 1024 * 1024; iter += PAGE_SIZE)
+ pmap_kenter_pa(sc->sys_image + iter, iter,
+ VM_PROT_READ | VM_PROT_WRITE);
+ pmap_update(pmap_kernel());
+
+ memset(&sc->emu, 0, sizeof(sc->emu));
+ X86EMU_init_default(&sc->emu);
+ sc->emu.emu_inb = vm86_emu_inb;
+ sc->emu.emu_inw = vm86_emu_inw;
+ sc->emu.emu_inl = vm86_emu_inl;
+ sc->emu.emu_outb = vm86_emu_outb;
+ sc->emu.emu_outw = vm86_emu_outw;
+ sc->emu.emu_outl = vm86_emu_outl;
+
+ sc->emu.mem_base = (char *)sc->sys_image;
+ sc->emu.mem_size = 1024 * 1024;
+
+ sc->initial_eax = bus * 256 + device * 8 + function;
+#ifdef DDB
+ ddb_vgapostp = sc;
+#endif
+ return sc;
+}
+
+void
+vga_post_call(struct vga_post *sc)
+{
+ sc->emu.x86.R_EAX = sc->initial_eax;
+ sc->emu.x86.R_EDX = 0x00000080;
+ sc->emu.x86.R_DS = 0x0040;
+ sc->emu.x86.register_flags = 0x3200;
+
+ memcpy((void *)sc->sys_image, sc->bios_data, PAGE_SIZE);
+
+ /* stack is at the end of the first 64KB */
+ sc->emu.x86.R_SS = 0;
+ sc->emu.x86.R_ESP = 0;
+
+ /* Jump straight into the VGA BIOS POST code */
+ X86EMU_exec_call(&sc->emu, 0xc000, 0x0003);
+}
+
+void
+vga_post_free(struct vga_post *sc)
+{
+ uvm_pglistfree(&sc->ram_backing);
+ pmap_kremove(sc->sys_image, 1024 * 1024);
+ uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
+ pmap_update(pmap_kernel());
+ free(sc, M_DEVBUF);
+}
+
+#ifdef DDB
+void
+ddb_vgapost(void)
+{
+
+ if (ddb_vgapostp)
+ vga_post_call(ddb_vgapostp);
+ else
+ printf("ddb_vgapost: vga_post not initialized\n");
+}
+#endif
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 58c27ebc64b..8d2c87edc0b 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.662 2009/06/03 07:13:48 pirofti Exp $
+# $OpenBSD: GENERIC,v 1.663 2009/06/06 00:35:00 pirofti Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -340,6 +340,7 @@ pckbd* at pckbc? # PC keyboard
pms* at pckbc? # PS/2 mouse for wsmouse
pmsi* at pckbc? # PS/2 "Intelli"mouse for wsmouse
vga0 at isa?
+option VGA_POST # we can re-POST video cards
vga* at pci?
pcdisplay0 at isa? # CGA, MDA, EGA, HGA
wsdisplay* at vga?
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 354a4f0083c..ffe4ccef9e1 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.190 2009/05/12 19:49:36 mglocker Exp $
+# $OpenBSD: files.i386,v 1.191 2009/06/06 00:35:00 pirofti Exp $
#
# new style config file for i386 architecture
#
@@ -103,6 +103,7 @@ include "../../../dev/pci/files.pci"
file arch/i386/pci/pci_machdep.c pci
file arch/i386/pci/pciide_machdep.c pciide
file arch/i386/pci/pcic_pci_machdep.c pcic_pci
+file arch/i386/pci/vga_post.c vga_pci & vga_post
# PCI-Host bridge chipsets
device pchb: pcibus, agpbus
diff --git a/sys/arch/i386/include/vga_post.h b/sys/arch/i386/include/vga_post.h
new file mode 100644
index 00000000000..36a9a2d4680
--- /dev/null
+++ b/sys/arch/i386/include/vga_post.h
@@ -0,0 +1,43 @@
+/* $NetBSD: vga_post.h,v 1.2 2008/03/29 17:40:22 jmcneill Exp $ */
+/* $OpenBSD: vga_post.h,v 1.1 2009/06/06 00:35:00 pirofti Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef _X86_VGA_POST_H_
+#define _X86_VGA_POST_H_
+
+#ifdef _KERNEL
+struct vga_post;
+
+struct vga_post *vga_post_init(int, int, int);
+void vga_post_free(struct vga_post *);
+void vga_post_call(struct vga_post *);
+#endif
+#endif
diff --git a/sys/arch/i386/pci/vga_post.c b/sys/arch/i386/pci/vga_post.c
new file mode 100644
index 00000000000..43f0a86cf47
--- /dev/null
+++ b/sys/arch/i386/pci/vga_post.c
@@ -0,0 +1,231 @@
+/* $NetBSD: vga_post.c,v 1.12 2009/03/15 21:32:36 cegger Exp $ */
+/* $OpenBSD: vga_post.c,v 1.1 2009/06/06 00:35:00 pirofti Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <uvm/uvm_extern.h>
+#include <uvm/uvm_page.h>
+
+#include <machine/pio.h>
+
+#include <machine/vga_post.h>
+
+#include <lib/libkern/x86emu.h>
+#include <lib/libkern/x86emu_regs.h>
+
+#define BASE_MEMORY 65536 /* How much memory to allocate in Real Mode */
+
+struct vga_post {
+ struct X86EMU emu;
+ vaddr_t sys_image;
+ uint32_t initial_eax;
+ uint8_t bios_data[PAGE_SIZE];
+ struct pglist ram_backing;
+};
+
+#ifdef DDB
+struct vga_post *ddb_vgapostp;
+void ddb_vgapost(void);
+#endif
+
+static uint8_t
+vm86_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
+vm86_emu_inw(struct X86EMU *emu, uint16_t port)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return 0;
+
+ return inw(port);
+}
+
+static uint32_t
+vm86_emu_inl(struct X86EMU *emu, uint16_t port)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return 0;
+
+ return inl(port);
+}
+
+static void
+vm86_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
+vm86_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
+vm86_emu_outl(struct X86EMU *emu, uint16_t port, uint32_t val)
+{
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return;
+
+ outl(port, val);
+}
+
+struct vga_post *
+vga_post_init(int bus, int device, int function)
+{
+ struct vga_post *sc;
+ vaddr_t iter;
+ struct vm_page *pg;
+ vaddr_t sys_image, sys_bios_data;
+ int err;
+
+ sys_bios_data = uvm_km_valloc(kernel_map, PAGE_SIZE);
+ if (sys_bios_data == 0)
+ return NULL;
+
+ sys_image = uvm_km_valloc(kernel_map, 1024 * 1024);
+ if (sys_image == 0) {
+ uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
+ return NULL;
+ }
+ sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
+
+ err = uvm_pglistalloc(BASE_MEMORY, 0, (paddr_t)-1, 0, 0,
+ &sc->ram_backing, BASE_MEMORY/PAGE_SIZE, UVM_PLA_WAITOK);
+ if (err) {
+ uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
+ free(sc, M_DEVBUF);
+ return NULL;
+ }
+
+ sc->sys_image = sys_image;
+ sc->emu.sys_private = sc;
+
+ pmap_kenter_pa(sys_bios_data, 0, VM_PROT_READ);
+ pmap_update(pmap_kernel());
+ memcpy((void *)sc->bios_data, (void *)sys_bios_data, PAGE_SIZE);
+ pmap_kremove(sys_bios_data, PAGE_SIZE);
+ uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE);
+
+ iter = 0;
+ TAILQ_FOREACH(pg, &sc->ram_backing, pageq) {
+ pmap_kenter_pa(sc->sys_image + iter, VM_PAGE_TO_PHYS(pg),
+ VM_PROT_READ | VM_PROT_WRITE);
+ iter += PAGE_SIZE;
+ }
+ KASSERT(iter == 65536);
+
+ for (iter = 640 * 1024; iter < 1024 * 1024; iter += PAGE_SIZE)
+ pmap_kenter_pa(sc->sys_image + iter, iter,
+ VM_PROT_READ | VM_PROT_WRITE);
+ pmap_update(pmap_kernel());
+
+ memset(&sc->emu, 0, sizeof(sc->emu));
+ X86EMU_init_default(&sc->emu);
+ sc->emu.emu_inb = vm86_emu_inb;
+ sc->emu.emu_inw = vm86_emu_inw;
+ sc->emu.emu_inl = vm86_emu_inl;
+ sc->emu.emu_outb = vm86_emu_outb;
+ sc->emu.emu_outw = vm86_emu_outw;
+ sc->emu.emu_outl = vm86_emu_outl;
+
+ sc->emu.mem_base = (char *)sc->sys_image;
+ sc->emu.mem_size = 1024 * 1024;
+
+ sc->initial_eax = bus * 256 + device * 8 + function;
+#ifdef DDB
+ ddb_vgapostp = sc;
+#endif
+ return sc;
+}
+
+void
+vga_post_call(struct vga_post *sc)
+{
+ sc->emu.x86.R_EAX = sc->initial_eax;
+ sc->emu.x86.R_EDX = 0x00000080;
+ sc->emu.x86.R_DS = 0x0040;
+ sc->emu.x86.register_flags = 0x3200;
+
+ memcpy((void *)sc->sys_image, sc->bios_data, PAGE_SIZE);
+
+ /* stack is at the end of the first 64KB */
+ sc->emu.x86.R_SS = 0;
+ sc->emu.x86.R_ESP = 0;
+
+ /* Jump straight into the VGA BIOS POST code */
+ X86EMU_exec_call(&sc->emu, 0xc000, 0x0003);
+}
+
+void
+vga_post_free(struct vga_post *sc)
+{
+ uvm_pglistfree(&sc->ram_backing);
+ pmap_kremove(sc->sys_image, 1024 * 1024);
+
+ uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024);
+ pmap_update(pmap_kernel());
+ free(sc, M_DEVBUF);
+}
+
+#ifdef DDB
+void
+ddb_vgapost(void)
+{
+
+ if (ddb_vgapostp)
+ vga_post_call(ddb_vgapostp);
+ else
+ printf("ddb_vgapost: vga_post not initialized\n");
+}
+#endif
diff --git a/sys/conf/files b/sys/conf/files
index 8c679141e34..3578de71592 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.459 2009/06/04 22:08:52 chl Exp $
+# $OpenBSD: files,v 1.460 2009/06/06 00:35:00 pirofti Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -1078,3 +1078,6 @@ file lib/libkern/arch/${MACHINE_ARCH}/skpc.S | lib/libkern/skpc.c
file lib/libkern/arch/${MACHINE_ARCH}/htonl.S | lib/libkern/htonl.c
file lib/libkern/arch/${MACHINE_ARCH}/htons.S | lib/libkern/htons.c
file lib/libkern/arch/${MACHINE_ARCH}/strncasecmp.S | lib/libkern/strncasecmp.c
+# libx86emu
+file lib/libkern/x86emu.c !small_kernel
+file lib/libkern/x86emu_util.c !small_kernel
diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c
index 9016c46f7ad..7c34674d7fa 100644
--- a/sys/dev/pci/vga_pci.c
+++ b/sys/dev/pci/vga_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vga_pci.c,v 1.42 2009/06/03 23:33:01 miod Exp $ */
+/* $OpenBSD: vga_pci.c,v 1.43 2009/06/06 00:35:00 pirofti Exp $ */
/* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */
/*
@@ -91,6 +91,10 @@
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
+#ifdef VGA_POST
+#include <machine/vga_post.h>
+#endif
+
#ifdef VESAFB
#include <dev/vesa/vesabiosvar.h>
#endif
@@ -187,6 +191,12 @@ vga_pci_attach(struct device *parent, struct device *self, void *aux)
vga_pci_bar_init(sc, pa);
+#ifdef VGA_POST
+ if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device,
+ pa->pa_function)) == NULL)
+ printf("couldn't set up vga POST handler\n");
+#endif
+
#if NINTAGP > 0
/*
* attach intagp here instead of pchb so it can share mappings
diff --git a/sys/dev/pci/vga_pcivar.h b/sys/dev/pci/vga_pcivar.h
index aaeed358cdb..3d93764e9b5 100644
--- a/sys/dev/pci/vga_pcivar.h
+++ b/sys/dev/pci/vga_pcivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vga_pcivar.h,v 1.11 2008/06/12 00:54:38 oga Exp $ */
+/* $OpenBSD: vga_pcivar.h,v 1.12 2009/06/06 00:35:00 pirofti Exp $ */
/* $NetBSD: vga_pcivar.h,v 1.1 1998/03/22 15:16:19 drochner Exp $ */
/*
@@ -57,6 +57,9 @@ struct vga_pci_softc {
struct pci_attach_args pa;
struct vga_pci_bar *bars[VGA_PCI_MAX_BARS];
+#ifdef VGA_POST
+ struct vga_post *sc_posth;
+#endif
#ifdef VESAFB
int sc_width;
int sc_height;
diff --git a/sys/dev/x86emu/x86emu.c b/sys/dev/x86emu/x86emu.c
new file mode 100644
index 00000000000..4fd0438bec4
--- /dev/null
+++ b/sys/dev/x86emu/x86emu.c
@@ -0,0 +1,8102 @@
+/* $NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $ */
+/* $OpenBSD */
+
+/****************************************************************************
+*
+* 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.
+*
+****************************************************************************/
+
+#include <lib/libkern/x86emu.h>
+#include <lib/libkern/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 *, uint 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;
+
+#ifdef _KERNEL
+ if (setjmp(&emu->exec_state))
+ return;
+#else
+ if (setjmp(emu->exec_state))
+ return;
+#endif
+
+ 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)
+{
+#ifdef _KERNEL
+ longjmp(&emu->exec_state);
+#else
+ longjmp(emu->exec_state, 1);
+#endif
+}
+/****************************************************************************
+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
+****************************************************************************/
+/****************************************************************************
+REMARKS:
+Handles opcode 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/dev/x86emu/x86emu.h b/sys/dev/x86emu/x86emu.h
new file mode 100644
index 00000000000..7322c2775dc
--- /dev/null
+++ b/sys/dev/x86emu/x86emu.h
@@ -0,0 +1,186 @@
+/* $NetBSD: x86emu.h,v 1.1 2007/12/01 20:14:10 joerg Exp $ */
+/* $OpenBSD */
+
+/****************************************************************************
+*
+* 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>
+#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;
+
+#ifdef _KERNEL
+ label_t exec_state;
+#else
+ jmp_buf exec_state;
+#endif
+
+ 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 *) __dead;
+
+__END_DECLS
+
+#endif /* __X86EMU_X86EMU_H */
diff --git a/sys/dev/x86emu/x86emu_regs.h b/sys/dev/x86emu/x86emu_regs.h
new file mode 100644
index 00000000000..36b131ea3e4
--- /dev/null
+++ b/sys/dev/x86emu/x86emu_regs.h
@@ -0,0 +1,170 @@
+/* $NetBSD: x86emu_regs.h,v 1.1 2007/12/01 20:14:10 joerg Exp $ */
+/* $OpenBSD */
+
+/****************************************************************************
+*
+* 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 */
diff --git a/sys/dev/x86emu/x86emu_util.c b/sys/dev/x86emu/x86emu_util.c
new file mode 100644
index 00000000000..f9d5761a46f
--- /dev/null
+++ b/sys/dev/x86emu/x86emu_util.c
@@ -0,0 +1,158 @@
+/* $NetBSD: x86emu_util.c,v 1.2 2007/12/04 17:32:22 joerg Exp $ */
+/* $OpenBSD */
+
+/****************************************************************************
+*
+* 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.
+*
+****************************************************************************/
+
+#include <sys/param.h>
+#include <sys/endian.h>
+
+#include <lib/libkern/x86emu.h>
+#include <lib/libkern/x86emu_regs.h>
+
+
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Byte value read from emulator memory.
+
+REMARKS:
+Reads a byte value from the emulator memory.
+****************************************************************************/
+static uint8_t
+rdb(struct X86EMU *emu, uint32_t addr)
+{
+ if (addr > emu->mem_size - 1)
+ X86EMU_halt_sys(emu);
+ return emu->mem_base[addr];
+}
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Word value read from emulator memory.
+
+REMARKS:
+Reads a word value from the emulator memory.
+****************************************************************************/
+static uint16_t
+rdw(struct X86EMU *emu, uint32_t addr)
+{
+ if (addr > emu->mem_size - 2)
+ X86EMU_halt_sys(emu);
+ /* XXX alignment *sigh* */
+ return *(u_int16_t *)(emu->mem_base + addr);
+}
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+
+RETURNS:
+Long value read from emulator memory.
+REMARKS:
+Reads a long value from the emulator memory.
+****************************************************************************/
+static uint32_t
+rdl(struct X86EMU *emu, uint32_t addr)
+{
+ if (addr > emu->mem_size - 4)
+ X86EMU_halt_sys(emu);
+ /* XXX alignment *sigh* */
+ return *(u_int32_t *)(emu->mem_base + addr);
+}
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a byte value to emulator memory.
+****************************************************************************/
+static void
+wrb(struct X86EMU *emu, uint32_t addr, uint8_t val)
+{
+ if (addr > emu->mem_size - 1)
+ X86EMU_halt_sys(emu);
+ emu->mem_base[addr] = val;
+}
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a word value to emulator memory.
+****************************************************************************/
+static void
+wrw(struct X86EMU *emu, uint32_t addr, uint16_t val)
+{
+ if (addr > emu->mem_size - 2)
+ X86EMU_halt_sys(emu);
+ /* XXX alignment */
+ *((u_int16_t *)(emu->mem_base + addr)) = val;
+}
+/****************************************************************************
+PARAMETERS:
+addr - Emulator memory address to read
+val - Value to store
+
+REMARKS:
+Writes a long value to emulator memory.
+****************************************************************************/
+static void
+wrl(struct X86EMU *emu, uint32_t addr, uint32_t val)
+{
+ if (addr > emu->mem_size - 4)
+ X86EMU_halt_sys(emu);
+ /* XXX alignment *sigh* */
+ *((u_int32_t *)(emu->mem_base + addr)) = val;
+}
+
+/*----------------------------- Setup -------------------------------------*/
+
+void
+X86EMU_init_default(struct X86EMU *emu)
+{
+ int i;
+
+ emu->emu_rdb = rdb;
+ emu->emu_rdw = rdw;
+ emu->emu_rdl = rdl;
+ emu->emu_wrb = wrb;
+ emu->emu_wrw = wrw;
+ emu->emu_wrl = wrl;
+
+ for (i = 0; i < 256; i++)
+ emu->_X86EMU_intrTab[i] = NULL;
+}