Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / bios_emulator / x86emu / decode.c
diff --git a/qemu/roms/u-boot/drivers/bios_emulator/x86emu/decode.c b/qemu/roms/u-boot/drivers/bios_emulator/x86emu/decode.c
new file mode 100644 (file)
index 0000000..a782b81
--- /dev/null
@@ -0,0 +1,1144 @@
+/****************************************************************************
+*
+*                      Realmode X86 Emulator Library
+*
+*              Copyright (C) 1991-2004 SciTech Software, Inc.
+*                   Copyright (C) David Mosberger-Tang
+*                     Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  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.
+*
+*  ========================================================================
+*
+* Language:    ANSI C
+* Environment: Any
+* Developer:   Kendall Bennett
+*
+* Description: This file includes subroutines which are related to
+*              instruction decoding and accessess of immediate data via IP.  etc.
+*
+****************************************************************************/
+#include <common.h>
+#include "x86emu/x86emui.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Handles any pending asychronous interrupts.
+****************************************************************************/
+static void x86emu_intr_handle(void)
+{
+    u8 intno;
+
+    if (M.x86.intr & INTR_SYNCH) {
+       intno = M.x86.intno;
+       if (_X86EMU_intrTab[intno]) {
+           (*_X86EMU_intrTab[intno])(intno);
+       } else {
+           push_word((u16)M.x86.R_FLG);
+           CLEAR_FLAG(F_IF);
+           CLEAR_FLAG(F_TF);
+           push_word(M.x86.R_CS);
+           M.x86.R_CS = mem_access_word(intno * 4 + 2);
+           push_word(M.x86.R_IP);
+           M.x86.R_IP = mem_access_word(intno * 4);
+           M.x86.intr = 0;
+       }
+    }
+}
+
+/****************************************************************************
+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(
+    u8 intrnum)
+{
+    M.x86.intno = intrnum;
+    M.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(void)
+{
+    u8 op1;
+
+    M.x86.intr = 0;
+    DB(x86emu_end_instr();)
+
+    for (;;) {
+DB(    if (CHECK_IP_FETCH())
+           x86emu_check_ip_access();)
+       /* If debugging, save the IP and CS values. */
+       SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
+       INC_DECODED_INST_LEN(1);
+       if (M.x86.intr) {
+           if (M.x86.intr & INTR_HALTED) {
+DB(            if (M.x86.R_SP != 0) {
+                   printk("halted\n");
+                   X86EMU_trace_regs();
+                   }
+               else {
+                   if (M.x86.debug)
+                       printk("Service completed successfully\n");
+                   })
+               return;
+           }
+           if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
+               !ACCESS_FLAG(F_IF)) {
+               x86emu_intr_handle();
+           }
+       }
+       op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+       (*x86emu_optab[op1])(op1);
+       if (M.x86.debug & DEBUG_EXIT) {
+           M.x86.debug &= ~DEBUG_EXIT;
+           return;
+       }
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Halts the system by setting the halted system flag.
+****************************************************************************/
+void X86EMU_halt_sys(void)
+{
+    M.x86.intr |= INTR_HALTED;
+}
+
+/****************************************************************************
+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 (*sys_rdb) is already inline!
+****************************************************************************/
+void fetch_decode_modrm(
+    int *mod,
+    int *regh,
+    int *regl)
+{
+    int fetched;
+
+DB( if (CHECK_IP_FETCH())
+       x86emu_check_ip_access();)
+    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+    INC_DECODED_INST_LEN(1);
+    *mod  = (fetched >> 6) & 0x03;
+    *regh = (fetched >> 3) & 0x07;
+    *regl = (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 (*sys_rdb) is already inline!
+****************************************************************************/
+u8 fetch_byte_imm(void)
+{
+    u8 fetched;
+
+DB( if (CHECK_IP_FETCH())
+       x86emu_check_ip_access();)
+    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+    INC_DECODED_INST_LEN(1);
+    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 (*sys_rdw) is already inline!
+****************************************************************************/
+u16 fetch_word_imm(void)
+{
+    u16 fetched;
+
+DB( if (CHECK_IP_FETCH())
+       x86emu_check_ip_access();)
+    fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+    M.x86.R_IP += 2;
+    INC_DECODED_INST_LEN(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 (*sys_rdw) is already inline!
+****************************************************************************/
+u32 fetch_long_imm(void)
+{
+    u32 fetched;
+
+DB( if (CHECK_IP_FETCH())
+       x86emu_check_ip_access();)
+    fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+    M.x86.R_IP += 4;
+    INC_DECODED_INST_LEN(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 M.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.
+****************************************************************************/
+_INLINE u32 get_data_segment(void)
+{
+#define GET_SEGMENT(segment)
+    switch (M.x86.mode & SYSMODE_SEGMASK) {
+      case 0:                  /* default case: use ds register */
+      case SYSMODE_SEGOVR_DS:
+      case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_DS;
+      case SYSMODE_SEG_DS_SS:  /* non-overridden, use ss register */
+       return  M.x86.R_SS;
+      case SYSMODE_SEGOVR_CS:
+      case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_CS;
+      case SYSMODE_SEGOVR_ES:
+      case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_ES;
+      case SYSMODE_SEGOVR_FS:
+      case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_FS;
+      case SYSMODE_SEGOVR_GS:
+      case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_GS;
+      case SYSMODE_SEGOVR_SS:
+      case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
+       return  M.x86.R_SS;
+      default:
+#ifdef DEBUG
+       printk("error: should not happen:  multiple overrides.\n");
+#endif
+       HALT_SYS();
+       return 0;
+    }
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Byte value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdb)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Word value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdw)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset - Offset to load data from
+
+RETURNS:
+Long value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdl)((get_data_segment() << 4) + 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 (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdb)(((u32)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 (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdw)(((u32)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 (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdl)(((u32)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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte(
+    uint offset,
+    u8 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrb)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word(
+    uint offset,
+    u16 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrw)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long(
+    uint offset,
+    u32 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrl)((get_data_segment() << 4) + 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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte_abs(
+    uint segment,
+    uint offset,
+    u8 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrb)(((u32)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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word_abs(
+    uint segment,
+    uint offset,
+    u16 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrw)(((u32)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 (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long_abs(
+    uint segment,
+    uint offset,
+    u32 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+       x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrl)(((u32)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.
+****************************************************************************/
+u8* decode_rm_byte_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+       DECODE_PRINTF("AL");
+       return &M.x86.R_AL;
+      case 1:
+       DECODE_PRINTF("CL");
+       return &M.x86.R_CL;
+      case 2:
+       DECODE_PRINTF("DL");
+       return &M.x86.R_DL;
+      case 3:
+       DECODE_PRINTF("BL");
+       return &M.x86.R_BL;
+      case 4:
+       DECODE_PRINTF("AH");
+       return &M.x86.R_AH;
+      case 5:
+       DECODE_PRINTF("CH");
+       return &M.x86.R_CH;
+      case 6:
+       DECODE_PRINTF("DH");
+       return &M.x86.R_DH;
+      case 7:
+       DECODE_PRINTF("BH");
+       return &M.x86.R_BH;
+    }
+    HALT_SYS();
+    return NULL;               /* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+u16* decode_rm_word_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+       DECODE_PRINTF("AX");
+       return &M.x86.R_AX;
+      case 1:
+       DECODE_PRINTF("CX");
+       return &M.x86.R_CX;
+      case 2:
+       DECODE_PRINTF("DX");
+       return &M.x86.R_DX;
+      case 3:
+       DECODE_PRINTF("BX");
+       return &M.x86.R_BX;
+      case 4:
+       DECODE_PRINTF("SP");
+       return &M.x86.R_SP;
+      case 5:
+       DECODE_PRINTF("BP");
+       return &M.x86.R_BP;
+      case 6:
+       DECODE_PRINTF("SI");
+       return &M.x86.R_SI;
+      case 7:
+       DECODE_PRINTF("DI");
+       return &M.x86.R_DI;
+    }
+    HALT_SYS();
+    return NULL;               /* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+u32* decode_rm_long_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+       DECODE_PRINTF("EAX");
+       return &M.x86.R_EAX;
+      case 1:
+       DECODE_PRINTF("ECX");
+       return &M.x86.R_ECX;
+      case 2:
+       DECODE_PRINTF("EDX");
+       return &M.x86.R_EDX;
+      case 3:
+       DECODE_PRINTF("EBX");
+       return &M.x86.R_EBX;
+      case 4:
+       DECODE_PRINTF("ESP");
+       return &M.x86.R_ESP;
+      case 5:
+       DECODE_PRINTF("EBP");
+       return &M.x86.R_EBP;
+      case 6:
+       DECODE_PRINTF("ESI");
+       return &M.x86.R_ESI;
+      case 7:
+       DECODE_PRINTF("EDI");
+       return &M.x86.R_EDI;
+    }
+    HALT_SYS();
+    return NULL;               /* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+u16* decode_rm_seg_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+       DECODE_PRINTF("ES");
+       return &M.x86.R_ES;
+      case 1:
+       DECODE_PRINTF("CS");
+       return &M.x86.R_CS;
+      case 2:
+       DECODE_PRINTF("SS");
+       return &M.x86.R_SS;
+      case 3:
+       DECODE_PRINTF("DS");
+       return &M.x86.R_DS;
+      case 4:
+       DECODE_PRINTF("FS");
+       return &M.x86.R_FS;
+      case 5:
+       DECODE_PRINTF("GS");
+       return &M.x86.R_GS;
+      case 6:
+      case 7:
+       DECODE_PRINTF("ILLEGAL SEGREG");
+       break;
+    }
+    HALT_SYS();
+    return NULL;               /* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+scale - scale value of SIB byte
+index - index value of SIB byte
+
+RETURNS:
+Value of scale * index
+
+REMARKS:
+Decodes scale/index of SIB byte and returns relevant offset part of
+effective address.
+****************************************************************************/
+unsigned decode_sib_si(
+    int scale,
+    int index)
+{
+    scale = 1 << scale;
+    if (scale > 1) {
+       DECODE_PRINTF2("[%d*", scale);
+    } else {
+       DECODE_PRINTF("[");
+    }
+    switch (index) {
+      case 0:
+       DECODE_PRINTF("EAX]");
+       return M.x86.R_EAX * index;
+      case 1:
+       DECODE_PRINTF("ECX]");
+       return M.x86.R_ECX * index;
+      case 2:
+       DECODE_PRINTF("EDX]");
+       return M.x86.R_EDX * index;
+      case 3:
+       DECODE_PRINTF("EBX]");
+       return M.x86.R_EBX * index;
+      case 4:
+       DECODE_PRINTF("0]");
+       return 0;
+      case 5:
+       DECODE_PRINTF("EBP]");
+       return M.x86.R_EBP * index;
+      case 6:
+       DECODE_PRINTF("ESI]");
+       return M.x86.R_ESI * index;
+      case 7:
+       DECODE_PRINTF("EDI]");
+       return M.x86.R_EDI * index;
+    }
+    HALT_SYS();
+    return 0;                  /* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+mod - MOD value of preceding ModR/M byte
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Decodes SIB addressing byte and returns calculated effective address.
+****************************************************************************/
+unsigned decode_sib_address(
+    int mod)
+{
+    int sib   = fetch_byte_imm();
+    int ss    = (sib >> 6) & 0x03;
+    int index = (sib >> 3) & 0x07;
+    int base  = sib & 0x07;
+    int offset = 0;
+    int displacement;
+
+    switch (base) {
+      case 0:
+       DECODE_PRINTF("[EAX]");
+       offset = M.x86.R_EAX;
+       break;
+      case 1:
+       DECODE_PRINTF("[ECX]");
+       offset = M.x86.R_ECX;
+       break;
+      case 2:
+       DECODE_PRINTF("[EDX]");
+       offset = M.x86.R_EDX;
+       break;
+      case 3:
+       DECODE_PRINTF("[EBX]");
+       offset = M.x86.R_EBX;
+       break;
+      case 4:
+       DECODE_PRINTF("[ESP]");
+       offset = M.x86.R_ESP;
+       break;
+      case 5:
+       switch (mod) {
+         case 0:
+           displacement = (s32)fetch_long_imm();
+           DECODE_PRINTF2("[%d]", displacement);
+           offset = displacement;
+           break;
+         case 1:
+           displacement = (s8)fetch_byte_imm();
+           DECODE_PRINTF2("[%d][EBP]", displacement);
+           offset = M.x86.R_EBP + displacement;
+           break;
+         case 2:
+           displacement = (s32)fetch_long_imm();
+           DECODE_PRINTF2("[%d][EBP]", displacement);
+           offset = M.x86.R_EBP + displacement;
+           break;
+         default:
+           HALT_SYS();
+       }
+       DECODE_PRINTF("[EAX]");
+       offset = M.x86.R_EAX;
+       break;
+      case 6:
+       DECODE_PRINTF("[ESI]");
+       offset = M.x86.R_ESI;
+       break;
+      case 7:
+       DECODE_PRINTF("[EDI]");
+       offset = M.x86.R_EDI;
+       break;
+      default:
+       HALT_SYS();
+    }
+    offset += decode_sib_si(ss, index);
+    return offset;
+
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=00 addressing.  Also enables the
+decoding of instructions.
+
+NOTE:  The code which specifies the corresponding segment (ds vs ss)
+       below in the case of [BP+..].  The assumption here is that at the
+       point that this subroutine is called, the bit corresponding to
+       SYSMODE_SEG_DS_SS will be zero.  After every instruction
+       except the segment override instructions, this bit (as well
+       as any bits indicating segment overrides) will be clear.  So
+       if a SS access is needed, set this bit.  Otherwise, DS access
+       occurs (unless any of the segment override bits are set).
+****************************************************************************/
+unsigned decode_rm00_address(
+    int rm)
+{
+    unsigned offset;
+
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+       /* 32-bit addressing */
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF("[EAX]");
+           return M.x86.R_EAX;
+         case 1:
+           DECODE_PRINTF("[ECX]");
+           return M.x86.R_ECX;
+         case 2:
+           DECODE_PRINTF("[EDX]");
+           return M.x86.R_EDX;
+         case 3:
+           DECODE_PRINTF("[EBX]");
+           return M.x86.R_EBX;
+         case 4:
+           return decode_sib_address(0);
+         case 5:
+           offset = fetch_long_imm();
+           DECODE_PRINTF2("[%08x]", offset);
+           return offset;
+         case 6:
+           DECODE_PRINTF("[ESI]");
+           return M.x86.R_ESI;
+         case 7:
+           DECODE_PRINTF("[EDI]");
+           return M.x86.R_EDI;
+       }
+    } else {
+       /* 16-bit addressing */
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF("[BX+SI]");
+           return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
+         case 1:
+           DECODE_PRINTF("[BX+DI]");
+           return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
+         case 2:
+           DECODE_PRINTF("[BP+SI]");
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
+         case 3:
+           DECODE_PRINTF("[BP+DI]");
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
+         case 4:
+           DECODE_PRINTF("[SI]");
+           return M.x86.R_SI;
+         case 5:
+           DECODE_PRINTF("[DI]");
+           return M.x86.R_DI;
+         case 6:
+           offset = fetch_word_imm();
+           DECODE_PRINTF2("[%04x]", offset);
+           return offset;
+         case 7:
+           DECODE_PRINTF("[BX]");
+           return M.x86.R_BX;
+       }
+    }
+    HALT_SYS();
+    return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=01 addressing.  Also enables the
+decoding of instructions.
+****************************************************************************/
+unsigned decode_rm01_address(
+    int rm)
+{
+    int displacement;
+
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+       /* 32-bit addressing */
+       if (rm != 4)
+           displacement = (s8)fetch_byte_imm();
+       else
+           displacement = 0;
+
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF2("%d[EAX]", displacement);
+           return M.x86.R_EAX + displacement;
+         case 1:
+           DECODE_PRINTF2("%d[ECX]", displacement);
+           return M.x86.R_ECX + displacement;
+         case 2:
+           DECODE_PRINTF2("%d[EDX]", displacement);
+           return M.x86.R_EDX + displacement;
+         case 3:
+           DECODE_PRINTF2("%d[EBX]", displacement);
+           return M.x86.R_EBX + displacement;
+         case 4: {
+           int offset = decode_sib_address(1);
+           displacement = (s8)fetch_byte_imm();
+           DECODE_PRINTF2("[%d]", displacement);
+           return offset + displacement;
+         }
+         case 5:
+           DECODE_PRINTF2("%d[EBP]", displacement);
+           return M.x86.R_EBP + displacement;
+         case 6:
+           DECODE_PRINTF2("%d[ESI]", displacement);
+           return M.x86.R_ESI + displacement;
+         case 7:
+           DECODE_PRINTF2("%d[EDI]", displacement);
+           return M.x86.R_EDI + displacement;
+       }
+    } else {
+       /* 16-bit addressing */
+       displacement = (s8)fetch_byte_imm();
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF2("%d[BX+SI]", displacement);
+           return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+         case 1:
+           DECODE_PRINTF2("%d[BX+DI]", displacement);
+           return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+         case 2:
+           DECODE_PRINTF2("%d[BP+SI]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+         case 3:
+           DECODE_PRINTF2("%d[BP+DI]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+         case 4:
+           DECODE_PRINTF2("%d[SI]", displacement);
+           return (M.x86.R_SI + displacement) & 0xffff;
+         case 5:
+           DECODE_PRINTF2("%d[DI]", displacement);
+           return (M.x86.R_DI + displacement) & 0xffff;
+         case 6:
+           DECODE_PRINTF2("%d[BP]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + displacement) & 0xffff;
+         case 7:
+           DECODE_PRINTF2("%d[BX]", displacement);
+           return (M.x86.R_BX + displacement) & 0xffff;
+       }
+    }
+    HALT_SYS();
+    return 0;                  /* SHOULD NOT HAPPEN */
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=10 addressing.  Also enables the
+decoding of instructions.
+****************************************************************************/
+unsigned decode_rm10_address(
+    int rm)
+{
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+       int displacement;
+
+       /* 32-bit addressing */
+       if (rm != 4)
+           displacement = (s32)fetch_long_imm();
+       else
+           displacement = 0;
+
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF2("%d[EAX]", displacement);
+           return M.x86.R_EAX + displacement;
+         case 1:
+           DECODE_PRINTF2("%d[ECX]", displacement);
+           return M.x86.R_ECX + displacement;
+         case 2:
+           DECODE_PRINTF2("%d[EDX]", displacement);
+           return M.x86.R_EDX + displacement;
+         case 3:
+           DECODE_PRINTF2("%d[EBX]", displacement);
+           return M.x86.R_EBX + displacement;
+         case 4: {
+           int offset = decode_sib_address(2);
+           displacement = (s32)fetch_long_imm();
+           DECODE_PRINTF2("[%d]", displacement);
+           return offset + displacement;
+         }
+         case 5:
+           DECODE_PRINTF2("%d[EBP]", displacement);
+           return M.x86.R_EBP + displacement;
+         case 6:
+           DECODE_PRINTF2("%d[ESI]", displacement);
+           return M.x86.R_ESI + displacement;
+         case 7:
+           DECODE_PRINTF2("%d[EDI]", displacement);
+           return M.x86.R_EDI + displacement;
+       }
+    } else {
+       int displacement = (s16)fetch_word_imm();
+
+       /* 16-bit addressing */
+       switch (rm) {
+         case 0:
+           DECODE_PRINTF2("%d[BX+SI]", displacement);
+           return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+         case 1:
+           DECODE_PRINTF2("%d[BX+DI]", displacement);
+           return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+         case 2:
+           DECODE_PRINTF2("%d[BP+SI]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+         case 3:
+           DECODE_PRINTF2("%d[BP+DI]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+         case 4:
+           DECODE_PRINTF2("%d[SI]", displacement);
+           return (M.x86.R_SI + displacement) & 0xffff;
+         case 5:
+           DECODE_PRINTF2("%d[DI]", displacement);
+           return (M.x86.R_DI + displacement) & 0xffff;
+         case 6:
+           DECODE_PRINTF2("%d[BP]", displacement);
+           M.x86.mode |= SYSMODE_SEG_DS_SS;
+           return (M.x86.R_BP + displacement) & 0xffff;
+         case 7:
+           DECODE_PRINTF2("%d[BX]", displacement);
+           return (M.x86.R_BX + displacement) & 0xffff;
+       }
+    }
+    HALT_SYS();
+    return 0;                  /* SHOULD NOT HAPPEN */
+}
+
+/****************************************************************************
+PARAMETERS:
+mod - modifier
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding, multiplexing calls to
+the decode_rmXX_address functions
+
+REMARKS:
+Return the offset given by "mod" addressing.
+****************************************************************************/
+
+unsigned decode_rmXX_address(int mod, int rm)
+{
+  if(mod == 0)
+    return decode_rm00_address(rm);
+  if(mod == 1)
+    return decode_rm01_address(rm);
+  return decode_rm10_address(rm);
+}