]> granicus.if.org Git - yasm/commitdiff
Add memory expressions tests (checkea).
authorPeter Johnson <peter@tortall.net>
Thu, 1 Nov 2001 02:36:22 +0000 (02:36 -0000)
committerPeter Johnson <peter@tortall.net>
Thu, 1 Nov 2001 02:36:22 +0000 (02:36 -0000)
Split off errwarn functions so that they can be overridden in test cases.

svn path=/trunk/yasm/; revision=309

libyasm/tests/Makefile.am
libyasm/tests/memexpr_test.c [new file with mode: 0644]
src/Makefile.am
src/tests/Makefile.am
src/tests/memexpr_test.c [new file with mode: 0644]

index 51edfab3a472575a8cb2533e16da43802aba440c..9c7d99200da54de01e6c42ca009190c3dd24aeb1 100644 (file)
@@ -6,34 +6,53 @@ if CHECK
 TESTS = \
        bitvect_test    \
        bytecode_test   \
-       floatnum_test
+       floatnum_test   \
+       memexpr_test
 
 noinst_PROGRAMS = \
        bitvect_test    \
        bytecode_test   \
-       floatnum_test
+       floatnum_test   \
+       memexpr_test
+
 else
 TESTS =
 noinst_PROGRAMS =
 endif
 
+LDADD = \
+       $(top_builddir)/check/libcheck.a                        \
+       $(top_builddir)/src/parsers/nasm/libparser.a            \
+       $(top_builddir)/src/preprocs/raw/libpreproc.a           \
+       $(top_builddir)/src/optimizers/dbg/liboptimizer.a       \
+       $(top_builddir)/src/objfmts/dbg/libobjfmt.a             \
+       $(top_builddir)/src/libyasm.a                           \
+       $(INTLLIBS)
+
 bitvect_test_SOURCES = \
        bitvect_test.c
 
+bitvect_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
 bytecode_test_SOURCES = \
        bytecode_test.c
 
+bytecode_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
 floatnum_test_SOURCES = \
        floatnum_test.c
 
+floatnum_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
+memexpr_test_SOURCES = \
+       memexpr_test.c
+
 INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check \
        -I$(top_builddir)/intl
-LDADD = \
-       $(top_builddir)/check/libcheck.a                        \
-       $(top_builddir)/src/parsers/nasm/libparser.a            \
-       $(top_builddir)/src/preprocs/raw/libpreproc.a           \
-       $(top_builddir)/src/optimizers/dbg/liboptimizer.a       \
-       $(top_builddir)/src/objfmts/dbg/libobjfmt.a             \
-       $(top_builddir)/src/libyasm.a                           \
-       $(INTLLIBS)
 
diff --git a/libyasm/tests/memexpr_test.c b/libyasm/tests/memexpr_test.c
new file mode 100644 (file)
index 0000000..6e0ae89
--- /dev/null
@@ -0,0 +1,422 @@
+/* $IdPath$
+ *
+ *  Copyright (C) 2001  Peter Johnson
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "errwarn.h"
+
+#include "expr.h"
+#include "intnum.h"
+#include "floatnum.h"
+
+typedef enum {
+    REG_AX = 0,
+    REG_CX = 1,
+    REG_DX = 2,
+    REG_BX = 3,
+    REG_SP = 4,
+    REG_BP = 5,
+    REG_SI = 6,
+    REG_DI = 7
+} reg16type;
+
+/* Memory expression building functions.
+ * These try to exactly match how a parser will build up the expr for _in,
+ * and exactly what the output expr should be for _out.
+ */
+
+/* [5] */
+static expr *
+gen_5_in(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(5)));
+}
+#define gen_5_out      gen_5_in
+/* [1.2] */
+static expr *
+gen_1pt2_in(void)
+{
+    return expr_new_ident(ExprFloat(floatnum_new("1.2")));
+}
+/* No _out, it's invalid */
+/* [ecx] */
+static expr *
+gen_ecx_in(void)
+{
+    return expr_new_ident(ExprReg(REG_CX, 32));
+}
+#define gen_ecx_out    NULL
+/* [di] */
+static expr *
+gen_di_in(void)
+{
+    return expr_new_ident(ExprReg(REG_DI, 16));
+}
+#define gen_di_out     NULL
+/* [di-si+si+126] */
+static expr *
+gen_dimsipsip126_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_tree(
+               expr_new_ident(ExprReg(REG_DI, 16)),
+               EXPR_SUB,
+               expr_new_ident(ExprReg(REG_SI, 16))),
+           EXPR_ADD,
+           expr_new_ident(ExprReg(REG_SI, 16))),
+       EXPR_ADD,
+       expr_new_ident(ExprInt(intnum_new_int(126))));
+}
+#define gen_dimsipsip126_out   NULL
+/* [bx-(bx-di)+bx-2] */
+static expr *
+gen_bxmqbxmdiqpbxm2_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_tree(
+               expr_new_ident(ExprReg(REG_BX, 16)),
+               EXPR_SUB,
+               expr_new_tree(
+                   expr_new_ident(ExprReg(REG_BX, 16)),
+                   EXPR_SUB,
+                   expr_new_ident(ExprReg(REG_DI, 16)))),
+           EXPR_ADD,
+           expr_new_ident(ExprReg(REG_BX, 16))),
+       EXPR_SUB,
+       expr_new_ident(ExprInt(intnum_new_int(2))));
+}
+static expr *
+gen_bxmqbxmdiqpbxm2_out(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(-2)));
+}
+/* [bp] */
+static expr *
+gen_bp_in(void)
+{
+    return expr_new_ident(ExprReg(REG_BP, 16));
+}
+#define gen_bp_out             NULL
+/* [bp*1+500] */
+static expr *
+gen_bpx1p500_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_ident(ExprReg(REG_BP, 16)),
+           EXPR_MUL,
+           expr_new_ident(ExprInt(intnum_new_int(1)))),
+       EXPR_ADD,
+       expr_new_ident(ExprInt(intnum_new_int(500))));
+}
+static expr *
+gen_bpx1p500_out(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(500)));
+}
+
+typedef struct CheckEA_InOut {
+    /* Function to generate input/output expr. */
+    expr *(*expr_gen)(void);
+    unsigned char addrsize;
+    unsigned char bits;
+    unsigned char nosplit;
+    unsigned char displen;
+    unsigned char modrm;
+    unsigned char v_modrm;
+    unsigned char n_modrm;
+    unsigned char sib;
+    unsigned char v_sib;
+    unsigned char n_sib;
+} CheckEA_InOut;
+
+typedef struct CheckEA_Entry {
+    const char *ascii;     /* Text description of input */
+    CheckEA_InOut in;      /* Input Parameter Values */
+    int retval;                    /* Return value */
+    CheckEA_InOut out;     /* Correct output Parameter Values
+                              (N/A if retval=0) */
+} CheckEA_Entry;
+
+/* Values used for tests */
+static CheckEA_Entry bits16_vals[] = {
+    {
+       "[5]",
+       {gen_5_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "a16 [5]",
+       {gen_5_in , 16, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "a32 [5]",
+       {gen_5_in , 32, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1,    1}
+    },
+    {
+       "[word 5]",
+       {gen_5_in ,  0, 16, 0, 2,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "[dword 5]",
+       {gen_5_in ,  0, 16, 0, 4,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1,    1}
+    },
+    {
+       "a16 [dword 5]",
+       {gen_5_in, 16, 16, 0, 4,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL    ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    /* should error */
+    {
+       "[di+1.2]",
+       {gen_1pt2_in,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL       ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    {
+       "[ecx]",
+       {gen_ecx_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_ecx_out, 32, 16, 0, 0, 0x01, 1, 1,    0, 0,    0}
+    },
+    /* should error */
+    {
+       "a16 [ecx]",
+       {gen_ecx_in, 16, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL      ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    {
+       "[di]",
+       {gen_di_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_di_out, 16, 16, 0, 0, 0x05, 1, 1,    0, 0,    0}
+    },
+    {
+       "[di-si+si+126]",
+       {gen_dimsipsip126_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_dimsipsip126_out, 16, 16, 0, 1, 0x45, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bx-(bx-di)+bx-2]",
+       {gen_bxmqbxmdiqpbxm2_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bxmqbxmdiqpbxm2_out, 16, 16, 0, 1, 0x41, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bp]",
+       {gen_bp_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bp_out, 16, 16, 0, 1, 0x46, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bp*1+500]",
+       {gen_bpx1p500_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bpx1p500_out, 16, 16, 0, 2, 0x86, 1, 1,    0, 0,    0}
+    },
+};
+
+/* input expression */
+expr *expn;
+
+/* failure messages */
+static char result_msg[1024];
+
+int error_triggered;
+
+/* Replace errwarn functions */
+void InternalError_(const char *file, unsigned int line, const char *msg)
+{
+    exit(EXIT_FAILURE);
+}
+
+void
+Fatal(fatal_num num)
+{
+    exit(EXIT_FAILURE);
+}
+
+void
+Error(const char *msg, ...)
+{
+    error_triggered = 1;
+}
+
+void
+Warning(const char *msg, ...)
+{
+}
+
+void
+ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+    error_triggered = 1;
+}
+
+void
+WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+}
+
+static int
+checkea_check(CheckEA_Entry *val)
+{
+    CheckEA_InOut chk = val->in;    /* local structure copy of inputs */
+    int retval;
+
+    error_triggered = 0;
+
+    /* execute function and check return value */
+    retval = expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit,
+                         &chk.displen, &chk.modrm, &chk.v_modrm, &chk.n_modrm,
+                         &chk.sib, &chk.v_sib, &chk.n_sib);
+    if (retval != val->retval) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "return value", val->retval, retval);
+       return 1;
+    }
+
+    /* If returned 0 (failure), check to see if ErrorAt() was called */
+    if (retval == 0) {
+       if (error_triggered == 0) {
+           sprintf(result_msg, "%s: didn't call ErrorAt() and returned 0",
+                   val->ascii);
+           return 1;
+       }
+
+       return 0;       /* don't check other return values */
+    }
+
+    /* check expr result */
+    /* TODO */
+
+    /* Check other outputs */
+    if (chk.addrsize != val->out.addrsize) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "addrsize", (int)val->out.addrsize,
+               (int)chk.addrsize);
+       return 1;
+    }
+    if (chk.displen != val->out.displen) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "displen", (int)val->out.displen,
+               (int)chk.displen);
+       return 1;
+    }
+    if (chk.modrm != val->out.modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+               val->ascii, "modrm", (int)val->out.modrm, (int)chk.modrm);
+       return 1;
+    }
+    if (chk.v_modrm != val->out.v_modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "v_modrm", (int)val->out.v_modrm,
+               (int)chk.v_modrm);
+       return 1;
+    }
+    if (chk.n_modrm != val->out.n_modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "n_modrm", (int)val->out.n_modrm,
+               (int)chk.n_modrm);
+       return 1;
+    }
+    if (chk.sib != val->out.sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+               val->ascii, "sib", (int)val->out.sib, (int)chk.sib);
+       return 1;
+    }
+    if (chk.v_sib != val->out.v_sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "v_sib", (int)val->out.v_sib, (int)chk.v_sib);
+       return 1;
+    }
+    if (chk.n_sib != val->out.n_sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %x, got %x)",
+               val->ascii, "n_sib", (int)val->out.n_sib, (int)chk.n_sib);
+       return 1;
+    }
+    return 0;
+}
+
+START_TEST(test_checkea_bits16)
+{
+    CheckEA_Entry *vals = bits16_vals;
+    int i, num = sizeof(bits16_vals)/sizeof(CheckEA_Entry);
+
+    for (i=0; i<num; i++) {
+       expn = vals[i].in.expr_gen();
+       fail_unless(checkea_check(&vals[i]) == 0, result_msg);
+       expr_delete(expn);
+    }
+}
+END_TEST
+
+static Suite *
+memexpr_suite(void)
+{
+    Suite *s = suite_create("memexpr");
+    TCase *tc_checkea = tcase_create("checkea");
+
+    suite_add_tcase(s, tc_checkea);
+    tcase_add_test(tc_checkea, test_checkea_bits16);
+
+    return s;
+}
+
+int
+main(void)
+{
+    int nf;
+    Suite *s = memexpr_suite();
+    SRunner *sr = srunner_create(s);
+    BitVector_Boot();
+    srunner_run_all(sr, CRNORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    suite_free(s);
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index 16dc899847dcfa808ed188e028ade041892069a8..30d5aa31958f751cf1d5563c2e0c4a22a196ba04 100644 (file)
@@ -6,7 +6,10 @@ INCLUDES = -I$(top_builddir)/intl
 
 bin_PROGRAMS = yasm
 
-yasm_SOURCES = main.c
+yasm_SOURCES = \
+       main.c                  \
+       errwarn.c               \
+       errwarn.h
 
 yasm_LDADD = \
        parsers/nasm/libparser.a        \
@@ -21,8 +24,6 @@ noinst_LIBRARIES = libyasm.a
 libyasm_a_SOURCES = \
        bytecode.c              \
        bytecode.h              \
-       errwarn.c               \
-       errwarn.h               \
        expr.c                  \
        expr.h                  \
        symrec.c                \
index 51edfab3a472575a8cb2533e16da43802aba440c..9c7d99200da54de01e6c42ca009190c3dd24aeb1 100644 (file)
@@ -6,34 +6,53 @@ if CHECK
 TESTS = \
        bitvect_test    \
        bytecode_test   \
-       floatnum_test
+       floatnum_test   \
+       memexpr_test
 
 noinst_PROGRAMS = \
        bitvect_test    \
        bytecode_test   \
-       floatnum_test
+       floatnum_test   \
+       memexpr_test
+
 else
 TESTS =
 noinst_PROGRAMS =
 endif
 
+LDADD = \
+       $(top_builddir)/check/libcheck.a                        \
+       $(top_builddir)/src/parsers/nasm/libparser.a            \
+       $(top_builddir)/src/preprocs/raw/libpreproc.a           \
+       $(top_builddir)/src/optimizers/dbg/liboptimizer.a       \
+       $(top_builddir)/src/objfmts/dbg/libobjfmt.a             \
+       $(top_builddir)/src/libyasm.a                           \
+       $(INTLLIBS)
+
 bitvect_test_SOURCES = \
        bitvect_test.c
 
+bitvect_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
 bytecode_test_SOURCES = \
        bytecode_test.c
 
+bytecode_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
 floatnum_test_SOURCES = \
        floatnum_test.c
 
+floatnum_test_LDADD = \
+       $(top_builddir)/src/errwarn.o   \
+       $(LDADD)
+
+memexpr_test_SOURCES = \
+       memexpr_test.c
+
 INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check \
        -I$(top_builddir)/intl
-LDADD = \
-       $(top_builddir)/check/libcheck.a                        \
-       $(top_builddir)/src/parsers/nasm/libparser.a            \
-       $(top_builddir)/src/preprocs/raw/libpreproc.a           \
-       $(top_builddir)/src/optimizers/dbg/liboptimizer.a       \
-       $(top_builddir)/src/objfmts/dbg/libobjfmt.a             \
-       $(top_builddir)/src/libyasm.a                           \
-       $(INTLLIBS)
 
diff --git a/src/tests/memexpr_test.c b/src/tests/memexpr_test.c
new file mode 100644 (file)
index 0000000..6e0ae89
--- /dev/null
@@ -0,0 +1,422 @@
+/* $IdPath$
+ *
+ *  Copyright (C) 2001  Peter Johnson
+ *
+ *  This file is part of YASM.
+ *
+ *  YASM is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  YASM is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "errwarn.h"
+
+#include "expr.h"
+#include "intnum.h"
+#include "floatnum.h"
+
+typedef enum {
+    REG_AX = 0,
+    REG_CX = 1,
+    REG_DX = 2,
+    REG_BX = 3,
+    REG_SP = 4,
+    REG_BP = 5,
+    REG_SI = 6,
+    REG_DI = 7
+} reg16type;
+
+/* Memory expression building functions.
+ * These try to exactly match how a parser will build up the expr for _in,
+ * and exactly what the output expr should be for _out.
+ */
+
+/* [5] */
+static expr *
+gen_5_in(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(5)));
+}
+#define gen_5_out      gen_5_in
+/* [1.2] */
+static expr *
+gen_1pt2_in(void)
+{
+    return expr_new_ident(ExprFloat(floatnum_new("1.2")));
+}
+/* No _out, it's invalid */
+/* [ecx] */
+static expr *
+gen_ecx_in(void)
+{
+    return expr_new_ident(ExprReg(REG_CX, 32));
+}
+#define gen_ecx_out    NULL
+/* [di] */
+static expr *
+gen_di_in(void)
+{
+    return expr_new_ident(ExprReg(REG_DI, 16));
+}
+#define gen_di_out     NULL
+/* [di-si+si+126] */
+static expr *
+gen_dimsipsip126_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_tree(
+               expr_new_ident(ExprReg(REG_DI, 16)),
+               EXPR_SUB,
+               expr_new_ident(ExprReg(REG_SI, 16))),
+           EXPR_ADD,
+           expr_new_ident(ExprReg(REG_SI, 16))),
+       EXPR_ADD,
+       expr_new_ident(ExprInt(intnum_new_int(126))));
+}
+#define gen_dimsipsip126_out   NULL
+/* [bx-(bx-di)+bx-2] */
+static expr *
+gen_bxmqbxmdiqpbxm2_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_tree(
+               expr_new_ident(ExprReg(REG_BX, 16)),
+               EXPR_SUB,
+               expr_new_tree(
+                   expr_new_ident(ExprReg(REG_BX, 16)),
+                   EXPR_SUB,
+                   expr_new_ident(ExprReg(REG_DI, 16)))),
+           EXPR_ADD,
+           expr_new_ident(ExprReg(REG_BX, 16))),
+       EXPR_SUB,
+       expr_new_ident(ExprInt(intnum_new_int(2))));
+}
+static expr *
+gen_bxmqbxmdiqpbxm2_out(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(-2)));
+}
+/* [bp] */
+static expr *
+gen_bp_in(void)
+{
+    return expr_new_ident(ExprReg(REG_BP, 16));
+}
+#define gen_bp_out             NULL
+/* [bp*1+500] */
+static expr *
+gen_bpx1p500_in(void)
+{
+    return expr_new_tree(
+       expr_new_tree(
+           expr_new_ident(ExprReg(REG_BP, 16)),
+           EXPR_MUL,
+           expr_new_ident(ExprInt(intnum_new_int(1)))),
+       EXPR_ADD,
+       expr_new_ident(ExprInt(intnum_new_int(500))));
+}
+static expr *
+gen_bpx1p500_out(void)
+{
+    return expr_new_ident(ExprInt(intnum_new_int(500)));
+}
+
+typedef struct CheckEA_InOut {
+    /* Function to generate input/output expr. */
+    expr *(*expr_gen)(void);
+    unsigned char addrsize;
+    unsigned char bits;
+    unsigned char nosplit;
+    unsigned char displen;
+    unsigned char modrm;
+    unsigned char v_modrm;
+    unsigned char n_modrm;
+    unsigned char sib;
+    unsigned char v_sib;
+    unsigned char n_sib;
+} CheckEA_InOut;
+
+typedef struct CheckEA_Entry {
+    const char *ascii;     /* Text description of input */
+    CheckEA_InOut in;      /* Input Parameter Values */
+    int retval;                    /* Return value */
+    CheckEA_InOut out;     /* Correct output Parameter Values
+                              (N/A if retval=0) */
+} CheckEA_Entry;
+
+/* Values used for tests */
+static CheckEA_Entry bits16_vals[] = {
+    {
+       "[5]",
+       {gen_5_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "a16 [5]",
+       {gen_5_in , 16, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "a32 [5]",
+       {gen_5_in , 32, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1,    1}
+    },
+    {
+       "[word 5]",
+       {gen_5_in ,  0, 16, 0, 2,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1,    0, 0,    0}
+    },
+    {
+       "[dword 5]",
+       {gen_5_in ,  0, 16, 0, 4,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1,    1}
+    },
+    {
+       "a16 [dword 5]",
+       {gen_5_in, 16, 16, 0, 4,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL    ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    /* should error */
+    {
+       "[di+1.2]",
+       {gen_1pt2_in,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL       ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    {
+       "[ecx]",
+       {gen_ecx_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_ecx_out, 32, 16, 0, 0, 0x01, 1, 1,    0, 0,    0}
+    },
+    /* should error */
+    {
+       "a16 [ecx]",
+       {gen_ecx_in, 16, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       0,
+       {NULL      ,  0,  0, 0, 0,    0, 0, 0,    0, 0,    0}
+    },
+    {
+       "[di]",
+       {gen_di_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_di_out, 16, 16, 0, 0, 0x05, 1, 1,    0, 0,    0}
+    },
+    {
+       "[di-si+si+126]",
+       {gen_dimsipsip126_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_dimsipsip126_out, 16, 16, 0, 1, 0x45, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bx-(bx-di)+bx-2]",
+       {gen_bxmqbxmdiqpbxm2_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bxmqbxmdiqpbxm2_out, 16, 16, 0, 1, 0x41, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bp]",
+       {gen_bp_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bp_out, 16, 16, 0, 1, 0x46, 1, 1,    0, 0,    0}
+    },
+    {
+       "[bp*1+500]",
+       {gen_bpx1p500_in ,  0, 16, 0, 0,    0, 0, 1,    0, 0, 0xff},
+       1,
+       {gen_bpx1p500_out, 16, 16, 0, 2, 0x86, 1, 1,    0, 0,    0}
+    },
+};
+
+/* input expression */
+expr *expn;
+
+/* failure messages */
+static char result_msg[1024];
+
+int error_triggered;
+
+/* Replace errwarn functions */
+void InternalError_(const char *file, unsigned int line, const char *msg)
+{
+    exit(EXIT_FAILURE);
+}
+
+void
+Fatal(fatal_num num)
+{
+    exit(EXIT_FAILURE);
+}
+
+void
+Error(const char *msg, ...)
+{
+    error_triggered = 1;
+}
+
+void
+Warning(const char *msg, ...)
+{
+}
+
+void
+ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+    error_triggered = 1;
+}
+
+void
+WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+}
+
+static int
+checkea_check(CheckEA_Entry *val)
+{
+    CheckEA_InOut chk = val->in;    /* local structure copy of inputs */
+    int retval;
+
+    error_triggered = 0;
+
+    /* execute function and check return value */
+    retval = expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit,
+                         &chk.displen, &chk.modrm, &chk.v_modrm, &chk.n_modrm,
+                         &chk.sib, &chk.v_sib, &chk.n_sib);
+    if (retval != val->retval) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "return value", val->retval, retval);
+       return 1;
+    }
+
+    /* If returned 0 (failure), check to see if ErrorAt() was called */
+    if (retval == 0) {
+       if (error_triggered == 0) {
+           sprintf(result_msg, "%s: didn't call ErrorAt() and returned 0",
+                   val->ascii);
+           return 1;
+       }
+
+       return 0;       /* don't check other return values */
+    }
+
+    /* check expr result */
+    /* TODO */
+
+    /* Check other outputs */
+    if (chk.addrsize != val->out.addrsize) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "addrsize", (int)val->out.addrsize,
+               (int)chk.addrsize);
+       return 1;
+    }
+    if (chk.displen != val->out.displen) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "displen", (int)val->out.displen,
+               (int)chk.displen);
+       return 1;
+    }
+    if (chk.modrm != val->out.modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+               val->ascii, "modrm", (int)val->out.modrm, (int)chk.modrm);
+       return 1;
+    }
+    if (chk.v_modrm != val->out.v_modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "v_modrm", (int)val->out.v_modrm,
+               (int)chk.v_modrm);
+       return 1;
+    }
+    if (chk.n_modrm != val->out.n_modrm) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "n_modrm", (int)val->out.n_modrm,
+               (int)chk.n_modrm);
+       return 1;
+    }
+    if (chk.sib != val->out.sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+               val->ascii, "sib", (int)val->out.sib, (int)chk.sib);
+       return 1;
+    }
+    if (chk.v_sib != val->out.v_sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+               val->ascii, "v_sib", (int)val->out.v_sib, (int)chk.v_sib);
+       return 1;
+    }
+    if (chk.n_sib != val->out.n_sib) {
+       sprintf(result_msg, "%s: incorrect %s (expected %x, got %x)",
+               val->ascii, "n_sib", (int)val->out.n_sib, (int)chk.n_sib);
+       return 1;
+    }
+    return 0;
+}
+
+START_TEST(test_checkea_bits16)
+{
+    CheckEA_Entry *vals = bits16_vals;
+    int i, num = sizeof(bits16_vals)/sizeof(CheckEA_Entry);
+
+    for (i=0; i<num; i++) {
+       expn = vals[i].in.expr_gen();
+       fail_unless(checkea_check(&vals[i]) == 0, result_msg);
+       expr_delete(expn);
+    }
+}
+END_TEST
+
+static Suite *
+memexpr_suite(void)
+{
+    Suite *s = suite_create("memexpr");
+    TCase *tc_checkea = tcase_create("checkea");
+
+    suite_add_tcase(s, tc_checkea);
+    tcase_add_test(tc_checkea, test_checkea_bits16);
+
+    return s;
+}
+
+int
+main(void)
+{
+    int nf;
+    Suite *s = memexpr_suite();
+    SRunner *sr = srunner_create(s);
+    BitVector_Boot();
+    srunner_run_all(sr, CRNORMAL);
+    nf = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    suite_free(s);
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}