754 lines
21 KiB
C
754 lines
21 KiB
C
/* Target-dependent code for Motorola 68HC11
|
||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||
Contributed by Stephane Carrez, stcarrez@worldnet.fr
|
||
|
||
This file is part of GDB.
|
||
|
||
This program 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.
|
||
|
||
This program 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. */
|
||
|
||
#if 0
|
||
/* FIXME: This is from tm-m68hc1.h */
|
||
|
||
#define GDB_TARGET_IS_M6811
|
||
|
||
/* Define the bit, byte, and word ordering of the machine. */
|
||
|
||
#define TARGET_BYTE_ORDER BIG_ENDIAN
|
||
|
||
/* Offset from address of function to start of its code.
|
||
Zero on most machines. */
|
||
|
||
#define FUNCTION_START_OFFSET 0
|
||
|
||
#ifdef __STDC__ /* Forward decls for prototypes */
|
||
struct frame_info;
|
||
struct frame_saved_regs;
|
||
struct type;
|
||
struct value;
|
||
#endif
|
||
|
||
/* Advance PC across any function entry prologue instructions
|
||
to reach some "real" code. */
|
||
|
||
extern CORE_ADDR m68hc11_skip_prologue ();
|
||
#define SKIP_PROLOGUE(ip) \
|
||
m68hc11_skip_prologue (ip)
|
||
|
||
|
||
/* Stack grows downward. */
|
||
|
||
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs))
|
||
|
||
/* For a breakpoint, use "test". This is also the breakpoint
|
||
instruction on the 68HC12. */
|
||
#define BREAKPOINT {0x0}
|
||
|
||
/* If your kernel resets the pc after the trap happens you may need to
|
||
define this before including this file. */
|
||
#define DECR_PC_AFTER_BREAK 0
|
||
|
||
extern char *m68hc11_register_names[];
|
||
#define REGISTER_NAME(i) m68hc11_register_names[i]
|
||
|
||
#define REGISTER_SIZE 2
|
||
|
||
/* Register numbers of various important registers.
|
||
Note that some of these values are "real" register numbers,
|
||
and correspond to the general registers of the machine,
|
||
and some are "phony" register numbers which are too large
|
||
to be actual register numbers as far as the user is concerned
|
||
but do serve to get the desired values when passed to read_register. */
|
||
|
||
#define X_REGNUM 0
|
||
#define D_REGNUM 1
|
||
#define Y_REGNUM 2
|
||
#define SP_REGNUM 3
|
||
#define PC_REGNUM 4
|
||
#define A_REGNUM 5
|
||
#define B_REGNUM 6
|
||
#define PSW_REGNUM 7
|
||
#define Z_REGNUM 8
|
||
#define FP_REGNUM 9
|
||
#define TMP_REGNUM 10
|
||
#define ZS_REGNUM 11
|
||
#define XY_REGNUM 12
|
||
#define ZD1_REGNUM 13
|
||
#define ZD32_REGNUM (ZD1_REGNUM+31)
|
||
|
||
#define NUM_REGS (ZD32_REGNUM+1)
|
||
|
||
#include "opcode/m68hc11.h"
|
||
|
||
/* Say how much memory is needed to store a copy of the register set */
|
||
#define REGISTER_BYTES ((NUM_REGS)*2)
|
||
|
||
/* Index within `registers' of the first byte of the space for
|
||
register N. */
|
||
|
||
#define REGISTER_BYTE(N) ((N) * 2)
|
||
|
||
/* Number of bytes of storage in the actual machine representation
|
||
for register N. */
|
||
|
||
#define REGISTER_RAW_SIZE(N) (2)
|
||
|
||
/* Number of bytes of storage in the program's representation
|
||
for register N. */
|
||
|
||
#define REGISTER_VIRTUAL_SIZE(N) (2)
|
||
|
||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||
|
||
#define MAX_REGISTER_RAW_SIZE 8
|
||
|
||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||
|
||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||
|
||
/* Return the GDB type object for the "standard" data type
|
||
of data in register N. */
|
||
|
||
#define REGISTER_VIRTUAL_TYPE(N) builtin_type_uint16
|
||
|
||
/* Store the address of the place in which to copy the structure the
|
||
subroutine will return. This is called from call_function.
|
||
|
||
We store structs through a pointer passed in D */
|
||
|
||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||
{ write_register (D_REGNUM, (ADDR)); }
|
||
|
||
|
||
/* Write into appropriate registers a function return value
|
||
of type TYPE, given in virtual format.
|
||
|
||
Things always get returned in D/X */
|
||
|
||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||
write_register_bytes (REGISTER_BYTE (D_REGNUM), VALBUF, TYPE_LENGTH (TYPE))
|
||
|
||
|
||
/* Extract from an array REGBUF containing the (raw) register state
|
||
the address in which a function should return its structure value,
|
||
as a CORE_ADDR (or an expression that can be used as one). */
|
||
|
||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(CORE_ADDR *)(REGBUF))
|
||
|
||
|
||
/* Define other aspects of the stack frame.
|
||
we keep a copy of the worked out return pc lying around, since it
|
||
is a useful bit of info */
|
||
|
||
#define EXTRA_FRAME_INFO \
|
||
int frame_reg; \
|
||
CORE_ADDR return_pc; \
|
||
CORE_ADDR dummy; \
|
||
int frameless; \
|
||
int size;
|
||
|
||
/* There's a mess in stack frame creation. See comments in blockframe.c
|
||
near reference to INIT_FRAME_PC_FIRST. */
|
||
|
||
#define INIT_FRAME_PC(fromleaf, prev) /* nada */
|
||
|
||
#define INIT_FRAME_PC_FIRST(fromleaf, prev) \
|
||
(prev)->pc = ((fromleaf) ? SAVED_PC_AFTER_CALL ((prev)->next) : \
|
||
(prev)->next ? FRAME_SAVED_PC ((prev)->next) : read_pc ());
|
||
|
||
#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
|
||
m68hc11_init_extra_frame_info (fromleaf, fi)
|
||
|
||
extern void m68hc11_init_extra_frame_info (int fromleaf,
|
||
struct frame_info * fi);
|
||
|
||
/* A macro that tells us whether the function invocation represented
|
||
by FI does not have a frame on the stack associated with it. If it
|
||
does not, FRAMELESS is set to 1, else 0. */
|
||
|
||
#define FRAMELESS_FUNCTION_INVOCATION(FI) \
|
||
frameless_look_for_prologue (FI)
|
||
|
||
#define FRAME_CHAIN(FRAME) m68hc11_frame_chain (FRAME)
|
||
#define FRAME_CHAIN_VALID(chain,frame) \
|
||
((chain) != 0 && (frame) != 0)
|
||
#define FRAME_SAVED_PC(FRAME) ((FRAME)->return_pc)
|
||
#define FRAME_ARGS_ADDRESS(fi) (fi)->frame
|
||
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame
|
||
|
||
#define SAVED_PC_AFTER_CALL(frame) m68hc11_saved_pc_after_call (frame)
|
||
|
||
/* Set VAL to the number of args passed to frame described by FI.
|
||
Can set VAL to -1, meaning no way to tell. */
|
||
/* We can't tell how many args there are */
|
||
|
||
#define FRAME_NUM_ARGS(fi) (-1)
|
||
|
||
/* Return number of bytes at start of arglist that are not really args. */
|
||
|
||
#define FRAME_ARGS_SKIP 0
|
||
|
||
|
||
/* Put here the code to store, into a struct frame_saved_regs,
|
||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||
This includes special registers such as pc and fp saved in special
|
||
ways in the stack frame. sp is even more special:
|
||
the address we return for it IS the sp for the next frame. */
|
||
|
||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||
m68hc11_frame_find_saved_regs (frame_info, &(frame_saved_regs))
|
||
|
||
extern void m68hc11_frame_find_saved_regs (struct frame_info *,
|
||
struct frame_saved_regs *);
|
||
|
||
#define CALL_DUMMY { 0 }
|
||
#define PUSH_DUMMY_FRAME
|
||
#define CALL_DUMMY_START_OFFSET 0
|
||
#define CALL_DUMMY_BREAKPOINT_OFFSET (0)
|
||
|
||
extern CORE_ADDR m68hc11_call_dummy_address (void);
|
||
#define CALL_DUMMY_ADDRESS() m68hc11_call_dummy_address ()
|
||
|
||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \
|
||
sp = m68hc11_fix_call_dummy (dummyname, pc, fun, nargs, args, type, gcc_p)
|
||
|
||
extern CORE_ADDR m68hc11_fix_call_dummy (char *, CORE_ADDR, CORE_ADDR,
|
||
int, struct value **,
|
||
struct type *, int);
|
||
#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
|
||
sp = m68hc11_push_arguments ((nargs), (args), (sp), \
|
||
(struct_return), (struct_addr))
|
||
extern CORE_ADDR m68hc11_push_arguments (int, struct value **,
|
||
CORE_ADDR, int, CORE_ADDR);
|
||
|
||
|
||
/* Extract from an array REGBUF containing the (raw) register state
|
||
a function return value of type TYPE, and copy that, in virtual format,
|
||
into VALBUF. */
|
||
|
||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||
m68hc11_extract_return_value(TYPE, REGBUF, VALBUF)
|
||
extern void m68hc11_extract_return_value (struct type *, char *, char *);
|
||
|
||
|
||
/* Discard from the stack the innermost frame,
|
||
restoring all saved registers. */
|
||
#define POP_FRAME m68hc11_pop_frame();
|
||
extern void m68hc11_pop_frame (void);
|
||
|
||
|
||
/* Number of bits in the appropriate type. */
|
||
|
||
#define TARGET_INT_BIT (2 * TARGET_CHAR_BIT)
|
||
#define TARGET_PTR_BIT (2 * TARGET_CHAR_BIT)
|
||
#define TARGET_DOUBLE_BIT (4 * TARGET_CHAR_BIT)
|
||
#define TARGET_LONG_DOUBLE_BIT (8 * TARGET_CHAR_BIT)
|
||
|
||
#endif
|
||
|
||
#include "defs.h"
|
||
#include "frame.h"
|
||
#include "obstack.h"
|
||
#include "symtab.h"
|
||
#include "gdbtypes.h"
|
||
#include "gdbcmd.h"
|
||
#include "gdbcore.h"
|
||
#include "gdb_string.h"
|
||
#include "value.h"
|
||
#include "inferior.h"
|
||
#include "dis-asm.h"
|
||
#include "symfile.h"
|
||
#include "objfiles.h"
|
||
|
||
/* NOTE: This port is not finished. Several operations are not implemented
|
||
and will raise an error. Most of these functions concern the calling
|
||
of a function by GDB itself (command 'call') and retrieving data pushed
|
||
on the stack. */
|
||
|
||
void m68hc11_frame_find_saved_regs (struct frame_info *fi,
|
||
struct frame_saved_regs *fsr);
|
||
static void m68hc11_pop_dummy_frame (struct frame_info *fi);
|
||
|
||
/* Table of registers for 68HC11. This includes the hard registers
|
||
and the pseudo hard registers used by GCC. */
|
||
char*
|
||
m68hc11_register_names[] =
|
||
{
|
||
"x", "d", "y", "sp", "pc", "a", "b",
|
||
"ccr", "z", "frame","tmp", "zs", "xy",
|
||
"ZD1", "ZD2", "ZD3", "ZD4", "ZD5", "ZD6", "ZD7",
|
||
"ZD8", "ZD9", "ZD10", "ZD11", "ZD12", "ZD13", "ZD14",
|
||
"ZD15", "ZD16", "ZD17", "ZD18", "ZD19", "ZD20", "ZD21",
|
||
"ZD22", "ZD23", "ZD24", "ZD25", "ZD26", "ZD27", "ZD28",
|
||
"ZD29", "ZD30", "ZD31", "ZD32"
|
||
};
|
||
|
||
static int reg_last = 32 * 2 + 6;
|
||
static int frame_index = 6;
|
||
|
||
/* Raise an error for operations which are not yet provided. */
|
||
static void
|
||
m68hc11_not_yet (const char *operation)
|
||
{
|
||
error ("Operation '%s' is not yet implemented\n", operation);
|
||
}
|
||
|
||
/* Immediately after a function call, return the saved pc before the frame
|
||
is setup. For sun3's, we check for the common case of being inside of a
|
||
system call, and if so, we know that Sun pushes the call # on the stack
|
||
prior to doing the trap. */
|
||
|
||
CORE_ADDR
|
||
m68hc11_saved_pc_after_call (struct frame_info *frame)
|
||
{
|
||
unsigned addr = frame->frame + 1 + 2;
|
||
|
||
addr = read_register (SP_REGNUM) + 1;
|
||
addr &= 0x0ffff;
|
||
return read_memory_integer (addr, 2) & 0x0FFFF;
|
||
}
|
||
|
||
/* Discard from the stack the innermost frame, restoring all saved
|
||
registers. */
|
||
|
||
void
|
||
m68hc11_pop_frame (void)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_pop_frame");
|
||
}
|
||
|
||
/* Analyze the function prologue to find some information
|
||
about the function:
|
||
- the PC of the first line (for m68hc11_skip_prologue)
|
||
- the offset of the previous frame saved address (from current frame)
|
||
- the soft registers which are pushed. */
|
||
static void
|
||
m68hc11_guess_from_prologue (CORE_ADDR pc, CORE_ADDR* first_line,
|
||
int* frame_offset, int* pushed_regs)
|
||
{
|
||
CORE_ADDR func_end;
|
||
unsigned char op0, op1, op2;
|
||
int add_sp_mode;
|
||
int sp_adjust;
|
||
int size;
|
||
int found_frame_point;
|
||
int found_load;
|
||
CORE_ADDR first_pc;
|
||
int reg_saved;
|
||
|
||
first_pc = get_pc_function_start (pc);
|
||
size = 0;
|
||
|
||
if (first_pc == 0)
|
||
{
|
||
*frame_offset = 0;
|
||
*pushed_regs = 0;
|
||
*first_line = pc;
|
||
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)
|
||
|
||
/* The 68hc11 stack is as follows:
|
||
|
||
|
||
| |
|
||
+-----------+
|
||
| |
|
||
| args |
|
||
| |
|
||
+-----------+
|
||
| PC-return |
|
||
+-----------+
|
||
| Old frame |
|
||
+-----------+
|
||
| |
|
||
| Locals |
|
||
| |
|
||
+-----------+ <--- current frame
|
||
| |
|
||
|
||
With most processors (like 68K) the previous frame can be computed
|
||
easily because it is always at a fixed offset (see link/unlink).
|
||
That is, locals are accessed with negative offsets, arguments are
|
||
accessed with positive ones. Since 68hc11 only supports offsets
|
||
in the range [0..255], the frame is defined at the bottom of
|
||
locals (see picture).
|
||
|
||
The purpose of the analysis made here is to find out the size
|
||
of locals in this function. An alternative to this is to use
|
||
DWARF2 info. This would be better but I don't know how to
|
||
access dwarf2 debug from this function.
|
||
|
||
Walk from the function entry point to the point where we save
|
||
the frame. While walking instructions, compute the size of bytes
|
||
which are pushed. This gives us the index to access the previous
|
||
frame.
|
||
|
||
We limit the search to 128 bytes so that the algorithm is bounded
|
||
in case of random and wrong code. We also stop and abort if
|
||
we find an instruction which is not supposed to appear in the
|
||
prologue (as generated by gcc 2.95, 2.96).
|
||
*/
|
||
pc = first_pc;
|
||
func_end = pc + 128;
|
||
add_sp_mode = 0;
|
||
found_frame_point = 0;
|
||
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);
|
||
|
||
/* ldx *frame */
|
||
if (op0 == OP_LDX && op1 == frame_index)
|
||
{
|
||
pc += 2;
|
||
}
|
||
|
||
/* ldy *frame */
|
||
else if (op0 == OP_PAGE2 && op1 == OP_LDY && op2 == frame_index)
|
||
{
|
||
pc += 3;
|
||
}
|
||
|
||
/* pshx */
|
||
else if (op0 == OP_PSHX)
|
||
{
|
||
pc += 1;
|
||
size += 2;
|
||
}
|
||
|
||
/* pshy */
|
||
else if (op0 == OP_PAGE2 && op1 == OP_PSHX)
|
||
{
|
||
pc += 2;
|
||
size += 2;
|
||
}
|
||
|
||
/* sts *frame */
|
||
else if (op0 == OP_STS && op1 == frame_index)
|
||
{
|
||
found_frame_point = 1;
|
||
pc += 2;
|
||
break;
|
||
}
|
||
else if (op0 == OP_TSX && op1 == OP_XGDX)
|
||
{
|
||
add_sp_mode = 1;
|
||
pc += 2;
|
||
}
|
||
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. */
|
||
reg_saved = 0;
|
||
found_load = 0;
|
||
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 && op1 > frame_index && op1 <= reg_last)
|
||
{
|
||
found_load = 1;
|
||
pc += 2;
|
||
}
|
||
else if (op0 == OP_PAGE2 && op1 == OP_LDY
|
||
&& op2 > frame_index && op2 < reg_last)
|
||
{
|
||
found_load = 1;
|
||
pc += 3;
|
||
}
|
||
else if (op0 == OP_PSHX)
|
||
{
|
||
/* If there was no load, this is a push for a function call. */
|
||
if (found_load == 0)
|
||
break;
|
||
|
||
reg_saved += 2;
|
||
pc += 1;
|
||
found_load = 0;
|
||
}
|
||
else if (op0 == OP_PAGE2 && op1 == OP_PSHY)
|
||
{
|
||
if (found_load == 0)
|
||
break;
|
||
|
||
reg_saved += 2;
|
||
pc += 2;
|
||
found_load = 0;
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
*pushed_regs = reg_saved;
|
||
*first_line = pc;
|
||
}
|
||
|
||
|
||
CORE_ADDR
|
||
m68hc11_skip_prologue (CORE_ADDR pc)
|
||
{
|
||
CORE_ADDR func_addr, func_end;
|
||
struct symtab_and_line sal;
|
||
int frame_offset;
|
||
int pushed_args;
|
||
|
||
/* If we have line debugging information, then the end of the. */
|
||
/* prologue should be the first assembly instruction of the
|
||
first source line. */
|
||
if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
|
||
{
|
||
sal = find_pc_line (func_addr, 0);
|
||
if (sal.end && sal.end < func_end)
|
||
return sal.end;
|
||
}
|
||
|
||
m68hc11_guess_from_prologue (pc, &pc, &frame_offset, &pushed_args);
|
||
return pc;
|
||
}
|
||
|
||
/* Given a GDB frame, determine the address of the calling function's frame.
|
||
This will be used to create a new GDB frame struct, and then
|
||
INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
|
||
*/
|
||
|
||
CORE_ADDR
|
||
m68hc11_frame_chain (struct frame_info *frame)
|
||
{
|
||
unsigned addr;
|
||
|
||
if (frame->return_pc == 0 || inside_entry_file(frame->return_pc))
|
||
return (CORE_ADDR)0;
|
||
|
||
if (frame->frame == 0)
|
||
{
|
||
return (CORE_ADDR) 0;
|
||
}
|
||
|
||
addr = frame->frame + frame->size + 1 - 2;
|
||
addr = read_memory_unsigned_integer (addr, 2) & 0x0FFFF;
|
||
if (addr == 0)
|
||
{
|
||
return (CORE_ADDR)0;
|
||
}
|
||
|
||
return addr;
|
||
}
|
||
|
||
/* Put here the code to store, into a struct frame_saved_regs, the
|
||
addresses of the saved registers of frame described by FRAME_INFO.
|
||
This includes special registers such as pc and fp saved in special
|
||
ways in the stack frame. sp is even more special: the address we
|
||
return for it IS the sp for the next frame. */
|
||
void
|
||
m68hc11_frame_find_saved_regs (struct frame_info *fi,
|
||
struct frame_saved_regs *fsr)
|
||
{
|
||
CORE_ADDR pc;
|
||
int saved;
|
||
|
||
pc = fi->pc;
|
||
memset (fsr, 0, sizeof (*fsr));
|
||
m68hc11_guess_from_prologue (pc, &pc, &fi->size, &saved);
|
||
}
|
||
|
||
void
|
||
m68hc11_init_extra_frame_info (int fromleaf, struct frame_info *fi)
|
||
{
|
||
unsigned addr;
|
||
struct frame_saved_regs dummy;
|
||
|
||
m68hc11_frame_find_saved_regs (fi, &dummy);
|
||
|
||
if (fromleaf)
|
||
{
|
||
fi->return_pc = m68hc11_saved_pc_after_call (fi);
|
||
}
|
||
else
|
||
{
|
||
addr = fi->frame + fi->size + 1;
|
||
fi->return_pc = read_memory_unsigned_integer (addr, 2) & 0x0ffff;
|
||
|
||
#if 0
|
||
printf ("Pc@0x%04x, FR 0x%04x, size %d, read ret @0x%04x -> 0x%04x\n",
|
||
fi->pc,
|
||
fi->frame, fi->size,
|
||
addr & 0x0ffff,
|
||
fi->return_pc);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/* Same as 'info reg' but prints the registers in a different way. */
|
||
static void
|
||
show_regs (char *args, int from_tty)
|
||
{
|
||
int ccr = read_register (PSW_REGNUM);
|
||
int i;
|
||
|
||
printf_filtered ("PC=%04x SP=%04x FP=%04x CCR=%02x %c%c%c%c%c%c%c%c\n",
|
||
read_register (PC_REGNUM),
|
||
read_register (SP_REGNUM),
|
||
read_register (FP_REGNUM),
|
||
ccr,
|
||
ccr & M6811_S_BIT ? 'S' : '-',
|
||
ccr & M6811_X_BIT ? 'X' : '-',
|
||
ccr & M6811_H_BIT ? 'H' : '-',
|
||
ccr & M6811_I_BIT ? 'I' : '-',
|
||
ccr & M6811_N_BIT ? 'N' : '-',
|
||
ccr & M6811_Z_BIT ? 'Z' : '-',
|
||
ccr & M6811_V_BIT ? 'V' : '-',
|
||
ccr & M6811_C_BIT ? 'C' : '-');
|
||
|
||
printf_filtered ("D=%04x IX=%04x IY=%04x\n",
|
||
read_register (D_REGNUM),
|
||
read_register (X_REGNUM),
|
||
read_register (Y_REGNUM));
|
||
for (i = ZD1_REGNUM; i <= ZD32_REGNUM; i++)
|
||
{
|
||
printf_filtered ("ZD%d=%04x",
|
||
i - ZD1_REGNUM + 1,
|
||
read_register (i));
|
||
if (((i - ZD1_REGNUM) % 8) == 7)
|
||
printf_filtered ("\n");
|
||
else
|
||
printf_filtered (" ");
|
||
}
|
||
}
|
||
|
||
CORE_ADDR
|
||
m68hc11_fix_call_dummy (char *dummyname,
|
||
CORE_ADDR start_sp,
|
||
CORE_ADDR fun,
|
||
int nargs,
|
||
value_ptr *args,
|
||
struct type *type,
|
||
int gcc_p)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_fix_call_dummy");
|
||
return 0;
|
||
}
|
||
|
||
static void
|
||
m68hc11_pop_dummy_frame (struct frame_info *fi)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_pop_dummy_frame");
|
||
}
|
||
|
||
|
||
CORE_ADDR
|
||
m68hc11_push_arguments (int nargs,
|
||
value_ptr *args,
|
||
CORE_ADDR sp,
|
||
int struct_return,
|
||
CORE_ADDR struct_addr)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_push_arguments");
|
||
return 0;
|
||
}
|
||
|
||
|
||
CORE_ADDR
|
||
m68hc11_call_dummy_address (void)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_call_dummy_address");
|
||
return 0;
|
||
}
|
||
|
||
/* Given a return value in `regbuf' with a type `valtype',
|
||
extract and copy its value into `valbuf'. */
|
||
|
||
void
|
||
m68hc11_extract_return_value (struct type *valtype,
|
||
char *regbuf,
|
||
char *valbuf)
|
||
{
|
||
m68hc11_not_yet ("m68hc11_extract_return_value");
|
||
}
|
||
|
||
void
|
||
_initialize_m68hc11_tdep (void)
|
||
{
|
||
tm_print_insn = print_insn_m68hc11;
|
||
|
||
add_com ("regs", class_vars, show_regs, "Print all registers");
|
||
}
|
||
|