#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "gdbcore.h"
#include "target.h"
#include "floatformat.h"
#include "symtab.h"
#include "gdbcmd.h"
#include "regcache.h"
static int arc_set_cpu_type (char *str);
static int arc_bfd_mach_type;
char *arc_cpu_type;
char *tmp_arc_cpu_type;
struct
{
char *name;
int value;
}
arc_cpu_type_table[] =
{
{ "arc5", bfd_mach_arc_5 },
{ "arc6", bfd_mach_arc_6 },
{ "arc7", bfd_mach_arc_7 },
{ "arc8", bfd_mach_arc_8 },
{ NULL, 0 }
};
int display_pipeline_p;
int cpu_timer;
int debug_pipeline_p;
#define ARC_CALL_SAVED_REG(r) ((r) >= 16 && (r) < 24)
#define OPMASK 0xf8000000
#define X_OP(i) (((i) >> 27) & 0x1f)
#define X_A(i) (((i) >> 21) & 0x3f)
#define X_B(i) (((i) >> 15) & 0x3f)
#define X_C(i) (((i) >> 9) & 0x3f)
#define X_D(i) ((((i) & 0x1ff) ^ 0x100) - 0x100)
#define X_L(i) (((((i) >> 5) & 0x3ffffc) ^ 0x200000) - 0x200000)
#define X_N(i) (((i) >> 5) & 3)
#define X_Q(i) ((i) & 0x1f)
#define SHIMM_P(x) ((x) == 61 || (x) == 63)
#define LIMM_P(x) ((x) == 62)
#define BUILD_INSN(op, a, b, c, d) \
((((op) & 31) << 27) \
| (((a) & 63) << 21) \
| (((b) & 63) << 15) \
| (((c) & 63) << 9) \
| ((d) & 511))
static void codestream_read (unsigned int *, int);
static void codestream_seek (CORE_ADDR);
static unsigned int codestream_fill (int);
#define CODESTREAM_BUFSIZ 16
static CORE_ADDR codestream_next_addr;
static CORE_ADDR codestream_addr;
static unsigned int codestream_buf[CODESTREAM_BUFSIZ];
static int codestream_off;
static int codestream_cnt;
#define codestream_tell() \
(codestream_addr + codestream_off * sizeof (codestream_buf[0]))
#define codestream_peek() \
(codestream_cnt == 0 \
? codestream_fill (1) \
: codestream_buf[codestream_off])
#define codestream_get() \
(codestream_cnt-- == 0 \
? codestream_fill (0) \
: codestream_buf[codestream_off++])
static unsigned int
codestream_fill (int peek_flag)
{
codestream_addr = codestream_next_addr;
codestream_next_addr += CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]);
codestream_off = 0;
codestream_cnt = CODESTREAM_BUFSIZ;
read_memory (codestream_addr, (char *) codestream_buf,
CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]));
{
int i;
for (i = 0; i < CODESTREAM_BUFSIZ; i++)
codestream_buf[i] =
extract_unsigned_integer (&codestream_buf[i],
sizeof (codestream_buf[i]));
}
if (peek_flag)
return codestream_peek ();
else
return codestream_get ();
}
static void
codestream_seek (CORE_ADDR place)
{
codestream_next_addr = place / CODESTREAM_BUFSIZ;
codestream_next_addr *= CODESTREAM_BUFSIZ;
codestream_cnt = 0;
codestream_fill (1);
while (codestream_tell () != place)
codestream_get ();
}
static void
codestream_read (unsigned int *buf, int count)
{
unsigned int *p;
int i;
p = buf;
for (i = 0; i < count; i++)
*p++ = codestream_get ();
}
static unsigned int
setup_prologue_scan (CORE_ADDR pc)
{
unsigned int insn;
codestream_seek (pc);
insn = codestream_get ();
return insn;
}
static long
arc_get_frame_setup (CORE_ADDR pc)
{
unsigned int insn;
int frame_size = -1;
int maybe_stdarg_decr = -1;
insn = setup_prologue_scan (pc);
if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
== BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 0))
{
maybe_stdarg_decr = X_D (insn);
insn = codestream_get ();
}
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))
== BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
{
insn = codestream_get ();
frame_size = 0;
}
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))
== BUILD_INSN (2, 0, SP_REGNUM, FP_REGNUM, 0))
{
insn = codestream_get ();
if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
!= BUILD_INSN (12, FP_REGNUM, SP_REGNUM, SP_REGNUM, 0))
return -1;
insn = codestream_peek ();
if ((insn & BUILD_INSN (-1, -1, -1, 0, 0))
== BUILD_INSN (10, SP_REGNUM, SP_REGNUM, 0, 0))
{
if (LIMM_P (X_C (insn)))
frame_size = codestream_get ();
else if (SHIMM_P (X_C (insn)))
frame_size = X_D (insn);
else
return -1;
if (frame_size < 0)
return -1;
codestream_get ();
insn = codestream_peek ();
if ((insn & OPMASK) == 0x60000000)
codestream_get ();
}
else
{
frame_size = 0;
}
}
if (frame_size < 0 && maybe_stdarg_decr > 0)
return maybe_stdarg_decr;
return frame_size;
}
CORE_ADDR
arc_skip_prologue (CORE_ADDR pc, int frameless_p)
{
unsigned int insn;
int i, frame_size;
if ((frame_size = arc_get_frame_setup (pc)) < 0)
return (pc);
if (frameless_p)
return frame_size == 0 ? pc : codestream_tell ();
for (i = 0; i < 8; i++)
{
insn = codestream_peek ();
if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
!= BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
break;
if (!ARC_CALL_SAVED_REG (X_C (insn)))
break;
codestream_get ();
}
return codestream_tell ();
}
CORE_ADDR
arc_frame_saved_pc (struct frame_info *frame)
{
CORE_ADDR func_start;
unsigned int insn;
func_start = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
if (func_start == 0)
{
return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
}
insn = setup_prologue_scan (func_start);
if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
== BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 0))
insn = codestream_get ();
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))
!= BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
return ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM));
else
return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
}
void
frame_find_saved_regs (struct frame_info *fip, struct frame_saved_regs *fsrp)
{
long locals;
unsigned int insn;
CORE_ADDR dummy_bottom;
CORE_ADDR adr;
int i, regnum, offset;
memset (fsrp, 0, sizeof *fsrp);
dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
{
adr = fip->frame;
for (i = 0; i < NUM_REGS; i++)
{
adr -= REGISTER_RAW_SIZE (i);
fsrp->regs[i] = adr;
}
return;
}
locals = arc_get_frame_setup (get_pc_function_start (fip->pc));
if (locals >= 0)
{
adr = fip->frame - locals;
for (i = 0; i < 8; i++)
{
insn = codestream_get ();
if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
!= BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
break;
regnum = X_C (insn);
offset = X_D (insn);
fsrp->regs[regnum] = adr + offset;
}
}
fsrp->regs[PC_REGNUM] = fip->frame + 4;
fsrp->regs[FP_REGNUM] = fip->frame;
}
void
arc_push_dummy_frame (void)
{
CORE_ADDR sp = read_register (SP_REGNUM);
int regnum;
char regbuf[MAX_REGISTER_RAW_SIZE];
read_register_gen (PC_REGNUM, regbuf);
write_memory (sp + 4, regbuf, REGISTER_SIZE);
read_register_gen (FP_REGNUM, regbuf);
write_memory (sp, regbuf, REGISTER_SIZE);
write_register (FP_REGNUM, sp);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
read_register_gen (regnum, regbuf);
sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
}
sp += (2 * REGISTER_SIZE);
write_register (SP_REGNUM, sp);
}
void
arc_pop_frame (void)
{
struct frame_info *frame = get_current_frame ();
CORE_ADDR fp;
int regnum;
struct frame_saved_regs fsr;
char regbuf[MAX_REGISTER_RAW_SIZE];
fp = FRAME_FP (frame);
get_frame_saved_regs (frame, &fsr);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
CORE_ADDR adr;
adr = fsr.regs[regnum];
if (adr)
{
read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
write_register_bytes (REGISTER_BYTE (regnum), regbuf,
REGISTER_RAW_SIZE (regnum));
}
}
write_register (FP_REGNUM, read_memory_integer (fp, 4));
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
write_register (SP_REGNUM, fp + 8);
flush_cached_frames ();
}
typedef enum
{
NORMAL4,
NORMAL8,
BRANCH4,
BRANCH8,
}
insn_type;
static insn_type
get_insn_type (unsigned long insn, CORE_ADDR pc, CORE_ADDR *target)
{
unsigned long limm;
switch (insn >> 27)
{
case 0:
case 1:
case 2:
if (LIMM_P (X_A (insn))
|| LIMM_P (X_B (insn))
|| LIMM_P (X_C (insn)))
return NORMAL8;
return NORMAL4;
case 4:
case 5:
case 6:
*target = pc + 4 + X_L (insn);
if (X_N (insn) == 0)
return BRANCH4;
return BRANCH8;
case 7:
if (LIMM_P (X_B (insn)))
{
limm = read_memory_integer (pc + 4, 4);
*target = ARC_PC_TO_REAL_ADDRESS (limm);
return BRANCH8;
}
if (SHIMM_P (X_B (insn)))
*target = ARC_PC_TO_REAL_ADDRESS (X_D (insn));
else
*target = ARC_PC_TO_REAL_ADDRESS (read_register (X_B (insn)));
if (X_Q (insn) == 0 && X_N (insn) == 0)
return BRANCH4;
return BRANCH8;
default:
if (LIMM_P (X_A (insn))
|| LIMM_P (X_B (insn))
|| LIMM_P (X_C (insn)))
return NORMAL8;
return NORMAL4;
}
}
void
arc_software_single_step (enum target_signal ignore,
int insert_breakpoints_p)
{
static CORE_ADDR next_pc, target;
static int brktrg_p;
typedef char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem[2];
if (insert_breakpoints_p)
{
insn_type type;
CORE_ADDR pc;
unsigned long insn;
pc = read_register (PC_REGNUM);
insn = read_memory_integer (pc, 4);
type = get_insn_type (insn, pc, &target);
next_pc = pc + ((type == NORMAL8 || type == BRANCH8) ? 8 : 4);
target_insert_breakpoint (next_pc, break_mem[0]);
brktrg_p = 0;
if ((type == BRANCH4 || type == BRANCH8)
&& target != next_pc)
{
brktrg_p = 1;
target_insert_breakpoint (target, break_mem[1]);
}
}
else
{
target_remove_breakpoint (next_pc, break_mem[0]);
if (brktrg_p)
target_remove_breakpoint (target, break_mem[1]);
stop_pc -= DECR_PC_AFTER_BREAK;
write_pc (stop_pc);
}
}
#ifdef JB_PC
int
get_longjmp_target (CORE_ADDR *pc)
{
char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
CORE_ADDR sp, jb_addr;
sp = read_register (SP_REGNUM);
if (target_read_memory (sp + SP_ARG0,
buf,
TARGET_PTR_BIT / TARGET_CHAR_BIT))
return 0;
jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
TARGET_PTR_BIT / TARGET_CHAR_BIT))
return 0;
*pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
return 1;
}
#endif
static int
arc_print_insn (bfd_vma vma, disassemble_info *info)
{
static int current_mach;
static int current_endian;
static disassembler_ftype current_disasm;
if (current_disasm == NULL
|| arc_bfd_mach_type != current_mach
|| TARGET_BYTE_ORDER != current_endian)
{
current_mach = arc_bfd_mach_type;
current_endian = TARGET_BYTE_ORDER;
current_disasm = arc_get_disassembler (NULL);
}
return (*current_disasm) (vma, info);
}
void
arc_set_cpu_type_command (char *args, int from_tty)
{
int i;
if (tmp_arc_cpu_type == NULL || *tmp_arc_cpu_type == '\0')
{
printf_unfiltered ("The known ARC cpu types are as follows:\n");
for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
printf_unfiltered ("%s\n", arc_cpu_type_table[i].name);
tmp_arc_cpu_type = xstrdup (arc_cpu_type);
return;
}
if (!arc_set_cpu_type (tmp_arc_cpu_type))
{
error ("Unknown cpu type `%s'.", tmp_arc_cpu_type);
tmp_arc_cpu_type = xstrdup (arc_cpu_type);
}
}
static void
arc_show_cpu_type_command (char *args, int from_tty)
{
}
static int
arc_set_cpu_type (char *str)
{
int i, j;
if (str == NULL)
return 0;
for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
{
if (strcasecmp (str, arc_cpu_type_table[i].name) == 0)
{
arc_cpu_type = str;
arc_bfd_mach_type = arc_cpu_type_table[i].value;
return 1;
}
}
return 0;
}
void
_initialize_arc_tdep (void)
{
struct cmd_list_element *c;
c = add_set_cmd ("cpu", class_support, var_string_noescape,
(char *) &tmp_arc_cpu_type,
"Set the type of ARC cpu in use.\n\
This command has two purposes. In a multi-cpu system it lets one\n\
change the cpu being debugged. It also gives one access to\n\
cpu-type-specific registers and recognize cpu-type-specific instructions.\
",
&setlist);
set_cmd_cfunc (c, arc_set_cpu_type_command);
c = add_show_from_set (c, &showlist);
set_cmd_cfunc (c, arc_show_cpu_type_command);
tmp_arc_cpu_type = xstrdup (DEFAULT_ARC_CPU_TYPE);
arc_set_cpu_type (tmp_arc_cpu_type);
c = add_set_cmd ("displaypipeline", class_support, var_zinteger,
(char *) &display_pipeline_p,
"Set pipeline display (simulator only).\n\
When enabled, the state of the pipeline after each cycle is displayed.",
&setlist);
c = add_show_from_set (c, &showlist);
c = add_set_cmd ("debugpipeline", class_support, var_zinteger,
(char *) &debug_pipeline_p,
"Set pipeline debug display (simulator only).\n\
When enabled, debugging information about the pipeline is displayed.",
&setlist);
c = add_show_from_set (c, &showlist);
c = add_set_cmd ("cputimer", class_support, var_zinteger,
(char *) &cpu_timer,
"Set maximum cycle count (simulator only).\n\
Control will return to gdb if the timer expires.\n\
A negative value disables the timer.",
&setlist);
c = add_show_from_set (c, &showlist);
tm_print_insn = arc_print_insn;
}