2000-12-03 Stephane Carrez <Stephane.Carrez@worldnet.fr>
[deliverable/binutils-gdb.git] / gdb / m68hc11-tdep.c
index 197c4a42f21fe487200cb30a669c0b2af1ee5c7f..92b738cd37a458a326ad62fae06dc2e3c01b39fb 100644 (file)
@@ -1,4 +1,4 @@
-/* Target-dependent code for Motorola 68HC11
+/* Target-dependent code for Motorola 68HC11 & 68HC12
    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
    Contributed by Stephane Carrez, stcarrez@worldnet.fr
 
@@ -77,6 +77,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define M68HC11_REG_SIZE    (2)
 
+struct insn_sequence;
 struct gdbarch_tdep
   {
     /* from the elf header */
@@ -87,6 +88,9 @@ struct gdbarch_tdep
        the address where the last value is saved.  For 68hc12, the stack
        pointer points to the last value pushed.  No offset is necessary.  */
     int stack_correction;
+
+    /* Description of instructions in the prologue.  */
+    struct insn_sequence *prologue;
   };
 
 #define M6811_TDEP gdbarch_tdep (current_gdbarch)
@@ -298,7 +302,7 @@ m68hc11_frame_saved_pc (struct frame_info *frame)
 static CORE_ADDR
 m68hc11_frame_args_address (struct frame_info *frame)
 {
-  return frame->frame;
+  return frame->frame + frame->extra_info->size + STACK_CORRECTION + 2;
 }
 
 static CORE_ADDR
@@ -337,6 +341,176 @@ m68hc11_pop_frame (void)
   flush_cached_frames ();
 }
 
+\f
+/* 68HC11 & 68HC12 prologue analysis.
+
+ */
+#define MAX_CODES 12
+
+/* 68HC11 opcodes.  */
+#undef M6811_OP_PAGE2
+#define M6811_OP_PAGE2 (0x18)
+#define M6811_OP_LDX   (0xde)
+#define M6811_OP_PSHX  (0x3c)
+#define M6811_OP_STS   (0x9f)
+#define M6811_OP_TSX   (0x30)
+#define M6811_OP_XGDX  (0x8f)
+#define M6811_OP_ADDD  (0xc3)
+#define M6811_OP_TXS   (0x35)
+#define M6811_OP_DES   (0x34)
+
+/* 68HC12 opcodes.  */
+#define M6812_OP_PAGE2 (0x18)
+#define M6812_OP_MOVW  (0x01)
+#define M6812_PB_PSHW  (0xae)
+#define M6812_OP_STS   (0x7f)
+#define M6812_OP_LEAS  (0x1b)
+
+/* Operand extraction.  */
+#define OP_DIRECT      (0x100) /* 8-byte direct addressing.  */
+#define OP_IMM_LOW     (0x200) /* Low part of 16-bit constant/address.  */
+#define OP_IMM_HIGH    (0x300) /* High part of 16-bit constant/address.  */
+#define OP_PBYTE       (0x400) /* 68HC12 indexed operand.  */
+
+/* Identification of the sequence.  */
+enum m6811_seq_type
+{
+  P_LAST = 0,
+  P_SAVE_REG,  /* Save a register on the stack.  */
+  P_SET_FRAME, /* Setup the frame pointer.  */
+  P_LOCAL_1,   /* Allocate 1 byte for locals.  */
+  P_LOCAL_2,   /* Allocate 2 bytes for locals.  */
+  P_LOCAL_N    /* Allocate N bytes for locals.  */
+};
+
+struct insn_sequence {
+  enum m6811_seq_type type;
+  unsigned length;
+  unsigned short code[MAX_CODES];
+};
+
+/* Sequence of instructions in the 68HC11 function prologue.  */
+static struct insn_sequence m6811_prologue[] = {
+  /* Sequences to save a soft-register.  */
+  { P_SAVE_REG, 3, { M6811_OP_LDX, OP_DIRECT,
+                     M6811_OP_PSHX } },
+  { P_SAVE_REG, 5, { M6811_OP_PAGE2, M6811_OP_LDX, OP_DIRECT,
+                     M6811_OP_PAGE2, M6811_OP_PSHX } },
+
+  /* Sequences to allocate local variables.  */
+  { P_LOCAL_N,  7, { M6811_OP_TSX,
+                     M6811_OP_XGDX,
+                     M6811_OP_ADDD, OP_IMM_HIGH, OP_IMM_LOW,
+                     M6811_OP_XGDX,
+                     M6811_OP_TXS } },
+  { P_LOCAL_N, 11, { M6811_OP_PAGE2, M6811_OP_TSX,
+                     M6811_OP_PAGE2, M6811_OP_XGDX,
+                     M6811_OP_ADDD, OP_IMM_HIGH, OP_IMM_LOW,
+                     M6811_OP_PAGE2, M6811_OP_XGDX,
+                     M6811_OP_PAGE2, M6811_OP_TXS } },
+  { P_LOCAL_1,  1, { M6811_OP_DES } },
+  { P_LOCAL_2,  1, { M6811_OP_PSHX } },
+  { P_LOCAL_2,  2, { M6811_OP_PAGE2, M6811_OP_PSHX } },
+
+  /* Initialize the frame pointer.  */
+  { P_SET_FRAME, 2, { M6811_OP_STS, OP_DIRECT } },
+  { P_LAST, 0, { 0 } }
+};
+
+
+/* Sequence of instructions in the 68HC12 function prologue.  */
+static struct insn_sequence m6812_prologue[] = {  
+  { P_SAVE_REG,  5, { M6812_OP_PAGE2, M6812_OP_MOVW, M6812_PB_PSHW,
+                      OP_IMM_HIGH, OP_IMM_LOW } },
+  { P_SET_FRAME, 3, { M6812_OP_STS, OP_IMM_HIGH, OP_IMM_LOW } },
+  { P_LOCAL_N,   2, { M6812_OP_LEAS, OP_PBYTE } },
+  { P_LAST, 0 }
+};
+
+
+/* Analyze the sequence of instructions starting at the given address.
+   Returns a pointer to the sequence when it is recognized and
+   the optional value (constant/address) associated with it.
+   Advance the pc for the next sequence.  */
+static struct insn_sequence *
+m68hc11_analyze_instruction (struct insn_sequence *seq, CORE_ADDR *pc,
+                             CORE_ADDR *val)
+{
+  unsigned char buffer[MAX_CODES];
+  unsigned bufsize;
+  unsigned j;
+  CORE_ADDR cur_val;
+  short v = 0;
+
+  bufsize = 0;
+  for (; seq->type != P_LAST; seq++)
+    {
+      cur_val = 0;
+      for (j = 0; j < seq->length; j++)
+        {
+          if (bufsize < j + 1)
+            {
+              buffer[bufsize] = read_memory_unsigned_integer (*pc + bufsize,
+                                                              1);
+              bufsize++;
+            }
+          /* Continue while we match the opcode.  */
+          if (seq->code[j] == buffer[j])
+            continue;
+          
+          if ((seq->code[j] & 0xf00) == 0)
+            break;
+          
+          /* Extract a sequence parameter (address or constant).  */
+          switch (seq->code[j])
+            {
+            case OP_DIRECT:
+              cur_val = (CORE_ADDR) buffer[j];
+              break;
+
+            case OP_IMM_HIGH:
+              cur_val = cur_val & 0x0ff;
+              cur_val |= (buffer[j] << 8);
+              break;
+
+            case OP_IMM_LOW:
+              cur_val &= 0x0ff00;
+              cur_val |= buffer[j];
+              break;
+
+            case OP_PBYTE:
+              if ((buffer[j] & 0xE0) == 0x80)
+                {
+                  v = buffer[j] & 0x1f;
+                  if (v & 0x10)
+                    v |= 0xfff0;
+                }
+              else if ((buffer[j] & 0xfe) == 0xf0)
+                {
+                  v = read_memory_unsigned_integer (*pc + j + 1, 1);
+                  if (buffer[j] & 1)
+                    v |= 0xff00;
+                }
+              else if (buffer[j] == 0xf2)
+                {
+                  v = read_memory_unsigned_integer (*pc + j + 1, 2);
+                }
+              cur_val = v;
+              break;
+            }
+        }
+
+      /* We have a full match.  */
+      if (j == seq->length)
+        {
+          *val = cur_val;
+          *pc = *pc + j;
+          return seq;
+        }
+    }
+  return 0;
+}
+
 /* Analyze the function prologue to find some information
    about the function:
     - the PC of the first line (for m68hc11_skip_prologue)
@@ -349,13 +523,12 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp,
 {
   CORE_ADDR save_addr;
   CORE_ADDR func_end;
-  unsigned char op0, op1, op2;
-  int add_sp_mode;
-  int sp_adjust = 0;
   int size;
   int found_frame_point;
   int saved_reg;
   CORE_ADDR first_pc;
+  int done = 0;
+  struct insn_sequence *seq_table;
   
   first_pc = get_pc_function_start (pc);
   size = 0;
@@ -368,21 +541,8 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp,
       return;
     }
 
-#define OP_PAGE2 (0x18)
-#define OP_LDX  (0xde)
-#define OP_LDY  (0xde)
-#define OP_PSHX (0x3c)
-#define OP_PSHY (0x3c)
-#define OP_STS  (0x9f)
-#define OP_TSX  (0x30)
-#define OP_TSY  (0x30)
-#define OP_XGDX (0x8f)
-#define OP_XGDY (0x8f)
-#define OP_ADDD (0xc3)
-#define OP_TXS  (0x35)
-#define OP_TYS  (0x35)
-#define OP_DES  (0x34)
-
+  seq_table = gdbarch_tdep (current_gdbarch)->prologue;
+  
   /* The 68hc11 stack is as follows:
 
 
@@ -426,169 +586,55 @@ m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR fp,
   */
   pc = first_pc;
   func_end = pc + 128;
-  add_sp_mode = 0;
   found_frame_point = 0;
-  while (pc + 2 < func_end)
+  *frame_offset = 0;
+  save_addr = fp;
+  while (!done && pc + 2 < func_end)
     {
-      op0 = read_memory_unsigned_integer (pc, 1);
-      op1 = read_memory_unsigned_integer (pc + 1, 1);
-      op2 = read_memory_unsigned_integer (pc + 2, 1);
+      struct insn_sequence *seq;
+      CORE_ADDR val;
       
-      /* ldx *frame */
-      if (op0 == OP_LDX && op1 == M68HC11_FP_ADDR)
-        {
-          pc += 2;
-        }
+      seq = m68hc11_analyze_instruction (seq_table, &pc, &val);
+      if (seq == 0)
+        break;
 
-      /* ldy *frame */
-      else if (op0 == OP_PAGE2 && op1 == OP_LDY
-               && op2 == M68HC11_FP_ADDR)
+      if (seq->type == P_SAVE_REG)
         {
-          pc += 3;
-        }
-
-      /* pshx */
-      else if (op0 == OP_PSHX)
-        {
-          pc += 1;
-          size += 2;
-        }
+          if (found_frame_point)
+            {
+              saved_reg = m68hc11_which_soft_register (val);
+              if (saved_reg < 0)
+                break;
 
-      /* pshy */
-      else if (op0 == OP_PAGE2 && op1 == OP_PSHX)
-        {
-          pc += 2;
-          size += 2;
+              save_addr -= 2;
+              if (pushed_regs)
+                pushed_regs[saved_reg] = save_addr;
+            }
+          else
+            {
+              size += 2;
+            }
         }
-
-      /* sts *frame */
-      else if (op0 == OP_STS && op1 == M68HC11_FP_ADDR)
+      else if (seq->type == P_SET_FRAME)
         {
           found_frame_point = 1;
-          pc += 2;
-          break;
+          *frame_offset = size;
         }
-      else if (op0 == OP_TSX && op1 == OP_XGDX)
+      else if (seq->type == P_LOCAL_1)
         {
-          add_sp_mode  = 1;
-          pc += 2;
-        }
-      /* des to allocate 1 byte on the stack */
-      else if (op0 == OP_DES)
-        {
-          pc += 1;
           size += 1;
         }
-      else if (op0 == OP_PAGE2 && op1 == OP_TSY && op2 == OP_PAGE2)
-        {
-          op0 = read_memory_unsigned_integer (pc + 3, 1);
-          if (op0 != OP_XGDY)
-            break;
-          
-          add_sp_mode  = 2;
-          pc += 4;
-        }
-      else if (add_sp_mode && op0 == OP_ADDD)
-        {
-          sp_adjust = read_memory_unsigned_integer (pc + 1, 2);
-          if (sp_adjust & 0x8000)
-            sp_adjust |= 0xffff0000L;
-
-          sp_adjust = -sp_adjust;
-          add_sp_mode |= 4;
-          pc += 3;
-        }
-      else if (add_sp_mode == (1 | 4) && op0 == OP_XGDX
-               && op1 == OP_TXS)
-        {
-          size += sp_adjust;
-          pc += 2;
-          add_sp_mode = 0;
-        }
-      else if (add_sp_mode == (2 | 4) && op0 == OP_PAGE2
-               && op1 == OP_XGDY && op2 == OP_PAGE2)
-        {
-          op0 = read_memory_unsigned_integer (pc + 3, 1);
-          if (op0 != OP_TYS)
-            break;
-
-          size += sp_adjust;
-          pc += 4;
-          add_sp_mode = 0;
-        }
-      else
-        {
-          break;
-        }
-    }
-
-  if (found_frame_point == 0)
-    {
-      *frame_offset = 0;
-    }
-  else
-    {
-      *frame_offset = size;
-    }
-
-  /* Now, look forward to see how many registers are pushed on the stack.
-     We look only for soft registers so there must be a first LDX *REG
-     before a PSHX.  */
-  saved_reg = -1;
-  save_addr = fp;
-  while (pc + 2 < func_end)
-    {
-      op0 = read_memory_unsigned_integer (pc, 1);
-      op1 = read_memory_unsigned_integer (pc + 1, 1);
-      op2 = read_memory_unsigned_integer (pc + 2, 1);
-      if (op0 == OP_LDX)
-        {
-          saved_reg = m68hc11_which_soft_register (op1);
-          if (saved_reg < 0 || saved_reg == SOFT_FP_REGNUM)
-            break;
-          
-          pc += 2;
-        }
-      else if (op0 == OP_PAGE2 && op1 == OP_LDY)
+      else if (seq->type == P_LOCAL_2)
         {
-          saved_reg = m68hc11_which_soft_register (op2);
-          if (saved_reg < 0 || saved_reg == SOFT_FP_REGNUM)
-            break;
-          
-          pc += 3;
-        }
-      else if (op0 == OP_PSHX)
-        {
-          /* If there was no load, this is a push for a function call.  */
-          if (saved_reg < 0 || saved_reg >= M68HC11_ALL_REGS)
-            break;
-
-          /* Keep track of the address where that register is saved
-             on the stack.  */
-          save_addr -= 2;
-          if (pushed_regs)
-            pushed_regs[saved_reg] = save_addr;
-
-          pc += 1;
-          saved_reg = -1;
-        }
-      else if (op0 == OP_PAGE2 && op1 == OP_PSHY)
-        {
-          if (saved_reg < 0 || saved_reg >= M68HC11_ALL_REGS)
-            break;
-          
-          /* Keep track of the address where that register is saved
-             on the stack.  */
-          save_addr -= 2;
-          if (pushed_regs)
-            pushed_regs[saved_reg] = save_addr;
-
-          pc += 2;
-          saved_reg = -1;
+          size += 2;
         }
-      else
+      else if (seq->type == P_LOCAL_N)
         {
-          break;
+          /* Stack pointer is decremented for the allocation.  */
+          if (val & 0x8000)
+            size -= (int) (val) | 0xffff0000;
+          else
+            size -= val;
         }
     }
   *first_line  = pc;
@@ -668,7 +714,8 @@ m68hc11_frame_init_saved_regs (struct frame_info *fi)
                                fi->saved_regs);
 
   addr = fi->frame + fi->extra_info->size + STACK_CORRECTION;
-  fi->saved_regs[SOFT_FP_REGNUM] = addr - 2;
+  if (soft_regs[SOFT_FP_REGNUM].name)
+    fi->saved_regs[SOFT_FP_REGNUM] = addr - 2;
   fi->saved_regs[HARD_SP_REGNUM] = addr;
   fi->saved_regs[HARD_PC_REGNUM] = fi->saved_regs[HARD_SP_REGNUM];
 }
@@ -1009,10 +1056,12 @@ m68hc11_gdbarch_init (struct gdbarch_info info,
     {
     case bfd_arch_m68hc11:
       tdep->stack_correction = 1;
+      tdep->prologue = m6811_prologue;
       break;
 
     case bfd_arch_m68hc12:
       tdep->stack_correction = 0;
+      tdep->prologue = m6812_prologue;
       break;
 
     default:
This page took 0.027308 seconds and 4 git commands to generate.