#define UNSIGNED_SHORT(X) ((X) & 0xffff)
-/* an easy to debug H8 stack frame looks like:
-0x6df6 push r6
-0x0d76 mov.w r7,r6
-0x6dfn push reg
-0x7905 nnnn mov.w #n,r5 or 0x1b87 subs #2,sp
-0x1957 sub.w r5,sp
-
- */
-
-#define IS_PUSH(x) ((x & 0xff00)==0x6d00)
+#define IS_PUSH(x) ((x & 0xfff0)==0x6df0)
#define IS_PUSH_FP(x) (x == 0x6df6)
-#define IS_MOVE_FP(x) (x == 0x0d76)
-#define IS_MOV_SP_FP(x) (x == 0x0d76)
+#define IS_MOVE_FP(x) (x == 0x0d76 || x == 0x0ff6)
+#define IS_MOV_SP_FP(x) (x == 0x0d76 || x == 0x0ff6)
#define IS_SUB2_SP(x) (x==0x1b87)
+#define IS_SUB4_SP(x) (x==0x1b97)
+#define IS_SUBL_SP(x) (x==0x7a37)
#define IS_MOVK_R5(x) (x==0x7905)
#define IS_SUB_R5SP(x) (x==0x1957)
CORE_ADDR start_pc;
{
short int w;
+ int adjust = 0;
- w = read_memory_unsigned_integer (start_pc, 2);
- /* Skip past all push insns */
- while (IS_PUSH_FP (w))
+ /* Skip past all push and stm insns. */
+ while (1)
{
- start_pc += 2;
w = read_memory_unsigned_integer (start_pc, 2);
+ /* First look for push insns. */
+ if (w == 0x0100 || w == 0x0110 || w == 0x0120 || w == 0x0130)
+ {
+ w = read_memory_unsigned_integer (start_pc + 2, 2);
+ adjust = 2;
+ }
+
+ if (IS_PUSH (w))
+ {
+ start_pc += 2 + adjust;
+ w = read_memory_unsigned_integer (start_pc, 2);
+ continue;
+ }
+ adjust = 0;
+ break;
+ }
+
+ /* Skip past a move to FP, either word or long sized */
+ w = read_memory_unsigned_integer (start_pc, 2);
+ if (w == 0x0100)
+ {
+ w = read_memory_unsigned_integer (start_pc + 2, 2);
+ adjust += 2;
}
- /* Skip past a move to FP */
if (IS_MOVE_FP (w))
{
- start_pc += 2;
+ start_pc += 2 + adjust;
w = read_memory_unsigned_integer (start_pc, 2);
}
- /* Skip the stack adjust */
-
+ /* Check for loading either a word constant into r5;
+ long versions are handled by the SUBL_SP below. */
if (IS_MOVK_R5 (w))
{
start_pc += 2;
w = read_memory_unsigned_integer (start_pc, 2);
}
+
+ /* Now check for subtracting r5 from sp, word sized only. */
if (IS_SUB_R5SP (w))
{
- start_pc += 2;
+ start_pc += 2 + adjust;
w = read_memory_unsigned_integer (start_pc, 2);
}
- while (IS_SUB2_SP (w))
+
+ /* Check for subs #2 and subs #4. */
+ while (IS_SUB2_SP (w) || IS_SUB4_SP (w))
{
- start_pc += 2;
+ start_pc += 2 + adjust;
w = read_memory_unsigned_integer (start_pc, 2);
}
+ /* Check for a 32bit subtract. */
+ if (IS_SUBL_SP (w))
+ start_pc += 6 + adjust;
+
return start_pc;
}
bfd_vma memaddr;
disassemble_info *info;
{
- if (h8300hmode)
+ if (h8300smode)
+ return print_insn_h8300s (memaddr, info);
+ else if (h8300hmode)
return print_insn_h8300h (memaddr, info);
else
return print_insn_h8300 (memaddr, info);
char in_frame[11]; /* One for each reg */
+ int adjust = 0;
+
memset (in_frame, 1, 11);
for (r = 0; r < 8; r++)
{
{
after_prolog_fp = read_register (SP_REGNUM);
}
- if (ip == 0 || ip & (h8300hmode ? ~0xffff : ~0xffff))
+
+ /* If the PC isn't valid, quit now. */
+ if (ip == 0 || ip & (h8300hmode ? ~0xffffff : ~0xffff))
return 0;
next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
+ if (insn_word == 0x0100)
+ {
+ insn_word = read_memory_unsigned_integer (ip + 2, 2);
+ adjust = 2;
+ }
+
/* Skip over any fp push instructions */
fsr->regs[6] = after_prolog_fp;
while (next_ip && IS_PUSH_FP (insn_word))
{
- ip = next_ip;
+ ip = next_ip + adjust;
in_frame[insn_word & 0x7] = reg_save_depth;
next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- reg_save_depth += 2;
+ reg_save_depth += 2 + adjust;
}
/* Is this a move into the fp */
/* Skip over any stack adjustment, happens either with a number of
sub#2,sp or a mov #x,r5 sub r5,sp */
- if (next_ip && IS_SUB2_SP (insn_word))
+ if (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
{
- while (next_ip && IS_SUB2_SP (insn_word))
+ while (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
{
- auto_depth += 2;
+ auto_depth += IS_SUB2_SP (insn_word) ? 2 : 4;
ip = next_ip;
next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
}
next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn_word);
auto_depth += insn_word;
}
+ if (next_ip && IS_SUBL_SP (insn_word))
+ {
+ ip = next_ip;
+ auto_depth += read_memory_unsigned_integer (ip, 4);
+ ip += 4;
+
+ next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
+ }
}
- /* Work out which regs are stored where */
- while (next_ip && IS_PUSH (insn_word))
+
+ /* Now examine the push insns to determine where everything lives
+ on the stack. */
+ while (1)
{
- ip = next_ip;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- fsr->regs[r] = after_prolog_fp + auto_depth;
- auto_depth += 2;
+ adjust = 0;
+ if (!next_ip)
+ break;
+
+ if (insn_word == 0x0100)
+ {
+ ip = next_ip;
+ next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
+ adjust = 2;
+ }
+
+ if (IS_PUSH (insn_word))
+ {
+ ip = next_ip;
+ next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
+ fsr->regs[r] = after_prolog_fp + auto_depth;
+ auto_depth += 2 + adjust;
+ continue;
+ }
+
+ /* Now check for push multiple insns. */
+ if (insn_word == 0x0110 || insn_word == 0x0120 || insn_word == 0x0130)
+ {
+ int count = ((insn_word >> 4) & 0xf) + 1;
+ int start, i;
+
+ ip = next_ip;
+ next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
+ start = insn_word & 0x7;
+
+ for (i = start; i <= start + count; i++)
+ {
+ fsr->regs[i] = after_prolog_fp + auto_depth;
+ auto_depth += 4;
+ }
+ }
+ break;
}
/* The args are always reffed based from the stack pointer */
/* Locals are always reffed based from the fp */
fi->locals_pointer = after_prolog_fp;
/* The PC is at a known place */
- fi->from_pc = read_memory_unsigned_integer (after_prolog_fp + 2, BINWORD);
+ fi->from_pc = read_memory_unsigned_integer (after_prolog_fp + BINWORD, BINWORD);
/* Rememeber any others too */
in_frame[PC_REGNUM] = 0;
{
extern int h8300hmode;
h8300hmode = 0;
+ h8300smode = 0;
}
static void
{
extern int h8300hmode;
h8300hmode = 1;
+ h8300smode = 0;
+}
+static void
+h8300s_command(args, from_tty)
+{
+ extern int h8300smode;
+ extern int h8300hmode;
+ h8300smode = 1;
+ h8300hmode = 1;
}
+
static void
set_machine (args, from_tty)
char *args;
int from_tty;
{
- printf_unfiltered ("\"set machine\" must be followed by h8300 or h8300h.\n");
+ printf_unfiltered ("\"set machine\" must be followed by h8300, h8300h");
+ printf_unfiltered ("or h8300s");
help_list (setmemorylist, "set memory ", -1, gdb_stdout);
}
set_machine_hook (filename)
char *filename;
{
- h8300hmode = (bfd_get_mach (exec_bfd) == bfd_mach_h8300h);
+ if (bfd_get_mach (exec_bfd) == bfd_mach_h8300s)
+ {
+ h8300smode = 1;
+ h8300hmode = 1;
+ }
+ else
+ if (bfd_get_mach (exec_bfd) == bfd_mach_h8300h)
+ {
+ h8300smode = 0;
+ h8300hmode = 1;
+ }
+ else
+ {
+ h8300smode = 0;
+ h8300hmode = 0;
+ }
}
void
add_cmd ("h8300h", class_support, h8300h_command,
"Set machine to be H8/300H.", &setmemorylist);
+ add_cmd ("h8300s", class_support, h8300s_command,
+ "Set machine to be H8/300S.", &setmemorylist);
+
/* Add a hook to set the machine type when we're loading a file. */
specify_exec_file_hook(set_machine_hook);