binutils-gdb/gdb/d10v-tdep.c
Martin Hunt e05bda9f12 Tue Sep 17 18:46:57 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
* d10v-tdep.c, config/d10v/tm-d10v.h: Snapshot.
1996-09-18 01:49:50 +00:00

404 lines
9.8 KiB
C

/* Target-dependent code for MItsubishi D10V, for GDB.
Copyright (C) 1996 Free Software Foundation, Inc.
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. */
/* Contributed by Martin Hunt, hunt@cygnus.com */
#include "defs.h"
#include "frame.h"
#include "obstack.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "value.h"
#include "inferior.h"
#include "dis-asm.h"
void d10v_frame_find_saved_regs PARAMS ((struct frame_info *fi, struct frame_saved_regs *fsr));
/* Discard from the stack the innermost frame,
restoring all saved registers. */
void
d10v_pop_frame ()
{
struct frame_info *frame = get_current_frame ();
CORE_ADDR fp, r13;
int regnum;
struct frame_saved_regs fsr;
char raw_buffer[8];
fp = FRAME_FP (frame);
/* printf("pop_frame 0x%x\n",fp); */
/* fill out fsr with the address of where each */
/* register was stored in the frame */
get_frame_saved_regs (frame, &fsr);
/* r13 contains the old PC. save it. */
r13 = read_register (13);
/* now update the current registers with the old values */
for (regnum = A0_REGNUM; regnum < A0_REGNUM+2 ; regnum++)
{
if (fsr.regs[regnum])
{
read_memory (fsr.regs[regnum] & 0xFFFF, raw_buffer, 8);
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 8);
}
}
for (regnum = 0; regnum < SP_REGNUM; regnum++)
{
if (fsr.regs[regnum])
{
write_register (regnum, read_memory_integer (fsr.regs[regnum] & 0xFFFF, 2));
}
}
if (fsr.regs[PSW_REGNUM])
{
write_register (PSW_REGNUM, read_memory_integer (fsr.regs[PSW_REGNUM] & 0xFFFF, 2));
}
/* PC is set to r13 */
write_register (PC_REGNUM, r13);
/* printf("setting stack to %x\n",fp - frame->size); */
write_register (SP_REGNUM, fp - frame->size);
flush_cached_frames ();
}
static int
check_prologue (op)
unsigned short op;
{
/* st rn, @-sp */
if ((op & 0x7E1F) == 0x6C1F)
return 1;
/* st2w rn, @-sp */
if ((op & 0x7E3F) == 0x6E1F)
return 1;
/* subi sp, n */
if ((op & 0x7FE1) == 0x01E1)
return 1;
/* mv r11, sp */
if (op == 0x417E)
return 1;
/* nop */
if (op == 0x5E00)
return 1;
/* st rn, @sp */
if ((op & 0x7E1F) == 0x681E)
return 1;
/* st2w rn, @sp */
if ((op & 0x7E3F) == 0x3A1E)
return 1;
return 0;
}
CORE_ADDR
d10v_skip_prologue (pc)
CORE_ADDR pc;
{
unsigned long op;
unsigned short op1, op2;
if (target_read_memory (pc, (char *)&op, 4))
return pc; /* Can't access it -- assume no prologue. */
while (1)
{
op = read_memory_integer (pc, 4);
if ((op & 0xC0000000) == 0xC0000000)
{
/* long instruction */
if ( ((op & 0x3FFF0000) != 0x01FF0000) && /* add3 sp,sp,n */
((op & 0x3F0F0000) != 0x340F0000) && /* st rn, @(offset,sp) */
((op & 0x3F1F0000) != 0x350F0000)) /* st2w rn, @(offset,sp) */
break;
}
else
{
/* short instructions */
op1 = (op & 0x3FFF8000) >> 15;
op2 = op & 0x7FFF;
if (!check_prologue(op1) || !check_prologue(op2))
break;
}
pc += 4;
}
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.
For us, the frame address is its stack pointer value, so we look up
the function prologue to determine the caller's sp value, and return it. */
CORE_ADDR
d10v_frame_chain (frame)
struct frame_info *frame;
{
struct frame_saved_regs fsr;
/* printf("frame_chain %x\n",frame->frame); */
d10v_frame_find_saved_regs (frame, &fsr);
/* printf("pc=%x\n",fsr.regs[PC_REGNUM]);
printf("fp=%x (%x)\n",fsr.regs[FP_REGNUM],read_memory_integer(fsr.regs[FP_REGNUM],2) & 0xffff); */
return read_memory_integer(fsr.regs[FP_REGNUM],2) & 0xffff;
}
static int next_addr;
static int
prologue_find_regs (op, fsr, addr)
unsigned short op;
struct frame_saved_regs *fsr;
CORE_ADDR addr;
{
int n;
/* st rn, @-sp */
if ((op & 0x7E1F) == 0x6C1F)
{
n = (op & 0x1E0) >> 5;
next_addr -= 2;
fsr->regs[n] = next_addr;
return 1;
}
/* st2w rn, @-sp */
else if ((op & 0x7E3F) == 0x6E1F)
{
n = (op & 0x1E0) >> 5;
next_addr -= 4;
fsr->regs[n] = next_addr;
fsr->regs[n+1] = next_addr+2;
return 1;
}
/* subi sp, n */
if ((op & 0x7FE1) == 0x01E1)
{
n = (op & 0x1E) >> 1;
if (n == 0)
n = 16;
next_addr -= n;
return 1;
}
/* mv r11, sp */
if (op == 0x417E)
return 1;
/* nop */
if (op == 0x5E00)
return 1;
/* st rn, @sp */
if ((op & 0x7E1F) == 0x681E)
{
n = (op & 0x1E0) >> 5;
fsr->regs[n] = next_addr;
return 1;
}
/* st2w rn, @sp */
if ((op & 0x7E3F) == 0x3A1E)
{
n = (op & 0x1E0) >> 5;
fsr->regs[n] = next_addr;
fsr->regs[n+1] = next_addr+2;
return 1;
}
return 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. */
void
d10v_frame_find_saved_regs (fi, fsr)
struct frame_info *fi;
struct frame_saved_regs *fsr;
{
CORE_ADDR fp, pc;
unsigned long op;
unsigned short op1, op2;
int i;
fp = fi->frame;
memset (fsr, 0, sizeof (*fsr));
next_addr = 0;
pc = get_pc_function_start (fi->pc);
while (1)
{
op = read_memory_integer (pc, 4);
if ((op & 0xC0000000) == 0xC0000000)
{
/* long instruction */
if ((op & 0x3FFF0000) == 0x01FF0000)
{
/* add3 sp,sp,n */
short n = op & 0xFFFF;
next_addr += n;
}
else if ((op & 0x3F0F0000) == 0x340F0000)
{
/* st rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
fsr->regs[n] = next_addr + offset;
}
else if ((op & 0x3F1F0000) == 0x350F0000)
{
/* st2w rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
fsr->regs[n] = next_addr + offset;
fsr->regs[n+1] = next_addr + offset + 2;
}
else
break;
}
else
{
/* short instructions */
op1 = (op & 0x3FFF8000) >> 15;
op2 = op & 0x7FFF;
if (!prologue_find_regs(op1,fsr,pc) || !prologue_find_regs(op2,fsr,pc))
break;
}
pc += 4;
}
fi->size = -next_addr;
fi->return_pc = read_register (13);
for (i=0; i<NUM_REGS; i++)
if (fsr->regs[i])
{
fsr->regs[i] = fp - (next_addr - fsr->regs[i]);
/* printf("register %d = *(%x) = %x\n",i,fsr->regs[i],read_memory_integer((fsr->regs[i]) & 0xffff, 2)); */
}
}
void
d10v_init_extra_frame_info (fromleaf, fi)
int fromleaf;
struct frame_info *fi;
{
struct frame_saved_regs dummy;
/* printf("extra init %x next=%x pc=%x\n",fi->frame,fi->next,fi->pc); */
/* fi->pc = fi->next->return_pc; */
d10v_frame_find_saved_regs (fi, &dummy);
/* printf(" %x next=%x pc=%x\n",fi->frame,fi->next,fi->pc); */
}
static void
show_regs (args, from_tty)
char *args;
int from_tty;
{
long long num1, num2;
printf_filtered ("PC=%04x (0x%x) PSW=%04x RPT_S=%04x RPT_E=%04x RPT_C=%04x\n",
read_register (PC_REGNUM), read_register (PC_REGNUM) << 2,
read_register (PSW_REGNUM),
read_register (24),
read_register (25),
read_register (23));
printf_filtered ("R0-R7 %04x %04x %04x %04x %04x %04x %04x %04x\n",
read_register (0),
read_register (1),
read_register (2),
read_register (3),
read_register (4),
read_register (5),
read_register (6),
read_register (7));
printf_filtered ("R8-R15 %04x %04x %04x %04x %04x %04x %04x %04x\n",
read_register (8),
read_register (9),
read_register (10),
read_register (11),
read_register (12),
read_register (13),
read_register (14),
read_register (15));
read_register_gen (A0_REGNUM, (char *)&num1);
read_register_gen (A0_REGNUM+1, (char *)&num2);
printf_filtered ("A0-A1 %010llx %010llx\n",num1, num2);
}
void
_initialize_d10v_tdep ()
{
struct cmd_list_element *c;
tm_print_insn = print_insn_d10v;
add_com ("regs", class_vars, show_regs, "Print all registers");
}
CORE_ADDR
d10v_read_register_pid (regno, pid)
int regno, pid;
{
int save_pid;
CORE_ADDR retval;
if (pid == inferior_pid)
return (read_register(regno)) << 2;
save_pid = inferior_pid;
inferior_pid = pid;
retval = read_register (regno);
inferior_pid = save_pid;
return (retval << 2);
}
void
d10v_write_register_pid (regno, val, pid)
int regno;
LONGEST val;
int pid;
{
int save_pid;
val >>= 2;
if (pid == inferior_pid)
{
write_register (regno, val);
return;
}
save_pid = inferior_pid;
inferior_pid = pid;
write_register (regno, val);
inferior_pid = save_pid;
}