Subject: pkg/34899: TME sun3 emulator fails M68K instruction cmpmw (sp)+,(sp)+
To: None <pkg-manager@netbsd.org, gnats-admin@netbsd.org,>
From: None <sigmfsk@aol.com>
List: pkgsrc-bugs
Date: 10/24/2006 16:50:00
>Number:         34899
>Category:       pkg
>Synopsis:       TME sun3 emulator fails M68K instruction cmpmw (sp)+,(sp)+
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 24 16:50:00 +0000 2006
>Originator:     arthur townsend
>Release:        3.0
>Organization:
>Environment:
3.0 for i386
>Description:
The cmpm8/cmpm16/cmpm32 routines read DEST, followed by SRC.  This works, unless the address register is the same (such as with the SP in which case the values are poppped off the stack in the reverse order and SRC has the DEST value and vice versa).
>How-To-Repeat:
The following code aborts inside TME, but runs fine on a real sun3.

#NO_APP
        .data
        .even
        .text
        .even
        .globl  _main
_main:
        link a6,#0
        jbsr ___main

        movew #8,sp@-
        movew #6,sp@-
        cmpmw sp@+,sp@+
        bgt  good
        jbsr _abort

good:
        unlk a6
        rts

>Fix:
Simply modify the cmpm8/cmpm16/cmpm32 routines to read SRC, then DEST.  The following patch includes this change.  It also includes the patch for pkg/34690 TME sun3 emulator incorrectly performs: movel sp,-(sp), updated with more verified-ok test cases, and a log for test cases yet to be checked.


--- m68k-insns-auto.c.orig      2006-10-24 05:36:52.000000000 -0400
+++ m68k-insns-auto.c   2006-10-24 05:37:04.000000000 -0400
@@ -2,6 +2,88 @@
 _TME_RCSID("$Id: m68k-insns-auto.sh,v 1.23 2005/03/10 13:26:23 fredette Exp $");
 
 #include "m68k-impl.h"
+#include <stdio.h>
+
+
+/* following are to fix the movel sp,-(sp) problem (of the value being pushed
+   on the stack being off by four) and to warn if there are other possible
+   problems that haven't been tested */
+
+#define PREDEC_POSTINC_CONCERN \
+\
+/* if source and destination register are the same number */ \
+   ( \
+    (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,0,3) == \
+     TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,9,3)) &&  \
+ \
+/* and both are address registers */ \
+    ( \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) >= 1) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) <= 6) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) >= 1) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) <= 6) \
+    ) && \
+ \
+/* and there is a predec or postinc in the src, or a predec in dest */ \
+    ( \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 3) || \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 4) || \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) == 4) \
+    ) \
+   )
+
+
+#define DEST_IS_PREDEC_SRC_IS_REG_BOTH_SP \
+    ( \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) == 4) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 1) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,0,3) == 7) && \
+     (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,9,3) == 7) \
+    ) \
+
+/* following modes test ok */
+#define MODE35_MODE24_OR_MODE54 \
+     ( \
+ \
+/* src/dest mode 3,5 : this is move.l (a5)+,(028,a5) */ \
+      ( \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 3) && \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) == 5) \
+      ) || \
+ \
+/* or src/dest mode 2,4 : this is move.l (a5),-(a5) */ \
+      ( \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 2) && \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) == 4) \
+      ) || \
+\
+/* or src/dest mode 5,4 : this is move.l (028,a5),-(a5) */ \
+      ( \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3) == 5) && \
+       (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3) == 4) \
+      )  \
+    ) 
+
+
+#define PRINT_WEIRD_SRC_DST_REG_MODE \
+printf ("src reg: %x src mode: %x dest reg: %x dest mode %x at pc:%x\n", \
+        TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,0,3), \
+        TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,3), \
+        TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,9,3), \
+        TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,6,3), \
+        ic->tme_m68k_ireg_pc);
+
+
+char hitreturn;
+#define HITRETURN \
+printf(", pc:%x, please:",ic->tme_m68k_ireg_pc); \
+printf("  analyze M68K instruction.\n"); \
+printf("  generate test case.\n"); \
+printf("  if TME emulation is incorrect, correct problem.\n"); \
+printf("  modify source to avoid this message in the future.\n"); \
+printf("press return to continue:"); \
+scanf("%c",&hitreturn); \
+printf("continuing\n");
 
 
 /* this does a 8-bit "add SRC, DST": */
@@ -237,6 +319,16 @@
   /* perform the operation: */
   res = op1;
 
+  if PREDEC_POSTINC_CONCERN {
+    if DEST_IS_PREDEC_SRC_IS_REG_BOTH_SP {
+      printf("ERROR: move8: how can addr/addr be 8 bits? at pc:%x\n",ic->tme_m68k_ireg_pc);
+    } else if (!(MODE35_MODE24_OR_MODE54)) {
+      printf("WEIRD: move8");
+      PRINT_WEIRD_SRC_DST_REG_MODE
+    }
+  }
+
+
   /* store the result: */
   *((tme_uint8_t *) _op0) = res;
 
@@ -307,6 +399,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird addx8");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint8_t) + ((ireg_src + 1) >> 3);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint8_t) + ((ireg_dst + 1) >> 3);
   tme_uint16_t memory;
@@ -370,6 +469,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird subx8");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint8_t) + ((ireg_src + 1) >> 3);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint8_t) + ((ireg_dst + 1) >> 3);
   tme_uint16_t memory;
@@ -433,6 +539,7 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint8_t) + ((ireg_src + 1) >> 3);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint8_t) + ((ireg_dst + 1) >> 3);
 
@@ -440,16 +547,16 @@
 
   if (!TME_M68K_SEQUENCE_RESTARTING) {
     ic->_tme_m68k_ea_function_code = function_code;
-    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
-    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
-  }
-  tme_m68k_read_memx8(ic);
-  if (!TME_M68K_SEQUENCE_RESTARTING) {
-    ic->_tme_m68k_ea_function_code = function_code;
     ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);
     ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;
   }
   tme_m68k_read_mem8(ic, TME_M68K_IREG_MEMY8);
+  if (!TME_M68K_SEQUENCE_RESTARTING) {
+    ic->_tme_m68k_ea_function_code = function_code;
+    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
+    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
+  }
+  tme_m68k_read_memx8(ic);
   op1 = ic->tme_m68k_ireg_memx8;
   op0 = ic->tme_m68k_ireg_memy8;
 
@@ -1281,6 +1388,19 @@
   /* perform the operation: */
   res = op1;
 
+  if PREDEC_POSTINC_CONCERN {
+    if DEST_IS_PREDEC_SRC_IS_REG_BOTH_SP {
+/*
+      printf("move16: chg predec dest res from:%x to %x for register %d at pc %x\n", res, res+2, TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,0,3), ic->tme_m68k_ireg_pc);
+*/
+      res = res + 2;
+    } else if (!(MODE35_MODE24_OR_MODE54)) {
+      printf("WEIRD: move16");
+      PRINT_WEIRD_SRC_DST_REG_MODE
+    }
+  }
+
+
   /* store the result: */
   *((tme_uint16_t *) _op0) = res;
 
@@ -1322,6 +1442,11 @@
   tme_uint32_t res, op0, op1;
   tme_uint8_t flags;
 
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird cmpa16");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   /* load the operand(s): */
   op0 = (tme_uint32_t) ((tme_int32_t) *((tme_int16_t *) _op0));
   op1 = *((tme_uint32_t *) _op1);
@@ -1375,6 +1500,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird addx16");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint16_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint16_t);
   tme_uint16_t memory;
@@ -1438,6 +1570,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird subx16");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint16_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint16_t);
   tme_uint16_t memory;
@@ -1501,6 +1640,7 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint16_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint16_t);
 
@@ -1508,16 +1648,16 @@
 
   if (!TME_M68K_SEQUENCE_RESTARTING) {
     ic->_tme_m68k_ea_function_code = function_code;
-    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
-    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
-  }
-  tme_m68k_read_memx16(ic);
-  if (!TME_M68K_SEQUENCE_RESTARTING) {
-    ic->_tme_m68k_ea_function_code = function_code;
     ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);
     ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;
   }
   tme_m68k_read_mem16(ic, TME_M68K_IREG_MEMY16);
+  if (!TME_M68K_SEQUENCE_RESTARTING) {
+    ic->_tme_m68k_ea_function_code = function_code;
+    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
+    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
+  }
+  tme_m68k_read_memx16(ic);
   op1 = ic->tme_m68k_ireg_memx16;
   op0 = ic->tme_m68k_ireg_memy16;
 
@@ -1538,6 +1678,11 @@
 /* the suba function on a 16-byte EA: */
 TME_M68K_INSN(tme_m68k_suba16)
 {
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird suba16");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op1) -= *((tme_int16_t *) _op0);
   TME_M68K_INSN_OK;
 }
@@ -1545,6 +1690,11 @@
 /* the adda function on a 16-byte EA: */
 TME_M68K_INSN(tme_m68k_adda16)
 {
+  if PREDEC_POSTINC_CONCERN {
+   printf("weird adda16");
+   PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op1) += *((tme_int16_t *) _op0);
   TME_M68K_INSN_OK;
 }
@@ -1552,6 +1702,11 @@
 /* the movea function on a 16-byte EA: */
 TME_M68K_INSN(tme_m68k_movea16)
 {
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird movea16");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op0) = *((tme_int16_t *) _op1);
   TME_M68K_INSN_OK;
 }
@@ -2578,6 +2733,19 @@
   /* perform the operation: */
   res = op1;
 
+  if PREDEC_POSTINC_CONCERN {
+    if DEST_IS_PREDEC_SRC_IS_REG_BOTH_SP {
+/*
+      printf("move32: chg predec dest res from:%x to %x for register %d at pc %x\n", res, res+4, TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,0,3), ic->tme_m68k_ireg_pc);
+*/
+      res = res + 4;
+    } else if (!(MODE35_MODE24_OR_MODE54)) {
+      printf("WEIRD: move32");
+      PRINT_WEIRD_SRC_DST_REG_MODE
+    }
+  }
+
+
   /* store the result: */
   *((tme_uint32_t *) _op0) = res;
 
@@ -2671,6 +2839,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird addx32");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint32_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint32_t);
   tme_uint16_t memory;
@@ -2734,6 +2909,13 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
+  if ((ireg_src == ireg_dst) &&
+         (TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE,3,1) == 1)) {
+    printf("weird subx32");
+    HITRETURN
+  }
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint32_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint32_t);
   tme_uint16_t memory;
@@ -2797,6 +2979,7 @@
   unsigned int function_code = TME_M68K_FUNCTION_CODE_DATA(ic);
   int ireg_src = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 0, 3);
   int ireg_dst = TME_FIELD_EXTRACTU(TME_M68K_INSN_OPCODE, 9, 3);
+
   tme_uint32_t ireg_src_adjust = sizeof(tme_uint32_t);
   tme_uint32_t ireg_dst_adjust = sizeof(tme_uint32_t);
 
@@ -2804,16 +2987,16 @@
 
   if (!TME_M68K_SEQUENCE_RESTARTING) {
     ic->_tme_m68k_ea_function_code = function_code;
-    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
-    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
-  }
-  tme_m68k_read_memx32(ic);
-  if (!TME_M68K_SEQUENCE_RESTARTING) {
-    ic->_tme_m68k_ea_function_code = function_code;
     ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src);
     ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_src) += ireg_src_adjust;
   }
   tme_m68k_read_mem32(ic, TME_M68K_IREG_MEMY32);
+  if (!TME_M68K_SEQUENCE_RESTARTING) {
+    ic->_tme_m68k_ea_function_code = function_code;
+    ic->_tme_m68k_ea_address = ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst);
+    ic->tme_m68k_ireg_uint32(TME_M68K_IREG_A0 + ireg_dst) += ireg_dst_adjust;
+  }
+  tme_m68k_read_memx32(ic);
   op1 = ic->tme_m68k_ireg_memx32;
   op0 = ic->tme_m68k_ireg_memy32;
 
@@ -2834,6 +3017,11 @@
 /* the suba function on a 32-byte EA: */
 TME_M68K_INSN(tme_m68k_suba32)
 {
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird suba32");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op1) -= *((tme_int32_t *) _op0);
   TME_M68K_INSN_OK;
 }
@@ -2841,6 +3029,11 @@
 /* the adda function on a 32-byte EA: */
 TME_M68K_INSN(tme_m68k_adda32)
 {
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird adda32");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op1) += *((tme_int32_t *) _op0);
   TME_M68K_INSN_OK;
 }
@@ -2848,6 +3041,11 @@
 /* the movea function on a 32-byte EA: */
 TME_M68K_INSN(tme_m68k_movea32)
 {
+  if PREDEC_POSTINC_CONCERN {
+    printf("weird movea32");
+    PRINT_WEIRD_SRC_DST_REG_MODE
+  }
+
   *((tme_int32_t *) _op0) = *((tme_int32_t *) _op1);
   TME_M68K_INSN_OK;
 }