Line 1... |
Line 1... |
/* Remote debugging interface for various or1k debugging protocols.
|
/* Remote debugging interface for various or1k debugging protocols.
|
|
Currently supported or1k targets are: simulator, jtag, dummy.
|
|
|
Copyright 1993-1995, 2000 Free Software Foundation, Inc.
|
Copyright 1993-1995, 2000 Free Software Foundation, Inc.
|
Contributed by Cygnus Support. Written by Marko Mlinar
|
Contributed by Cygnus Support. Written by Marko Mlinar
|
<markom@opencores.org>
|
<markom@opencores.org>
|
|
|
This file is part of GDB.
|
This file is part of GDB.
|
Line 36... |
Line 38... |
#include <sys/types.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <sys/stat.h>
|
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
|
|
|
/* JTAG or1k target ops. */
|
extern void jtag_init PARAMS ((char * args));
|
extern void jtag_init PARAMS ((char * args));
|
extern unsigned long long int jtag_read_reg PARAMS ((unsigned int regno));
|
extern unsigned long long int jtag_read_reg PARAMS ((unsigned int regno));
|
extern void jtag_write_reg PARAMS ((unsigned int regno, unsigned long long int data));
|
extern void jtag_write_reg PARAMS ((unsigned int regno, unsigned long long int data));
|
extern void jtag_done PARAMS ((void));
|
extern void jtag_done PARAMS ((void));
|
extern void jtag_set_chain PARAMS ((int chain));
|
extern void jtag_set_chain PARAMS ((int chain));
|
Line 55... |
Line 58... |
NULL,
|
NULL,
|
&or1k_jtag_ops,
|
&or1k_jtag_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
|
/* simulator or1k target ops. */
|
struct target_ops or1k_sim_ops;
|
struct target_ops or1k_sim_ops;
|
static struct or1k_target_ops or1k_target_sim =
|
static struct or1k_target_ops or1k_target_sim =
|
{
|
{
|
"simulator",
|
"simulator",
|
NULL,
|
NULL,
|
Line 69... |
Line 73... |
NULL,
|
NULL,
|
&or1k_sim_ops,
|
&or1k_sim_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
|
/* dummy or1k target ops. */
|
struct target_ops or1k_dummy_ops;
|
struct target_ops or1k_dummy_ops;
|
static struct or1k_target_ops or1k_target_dummy =
|
static struct or1k_target_ops or1k_target_dummy =
|
{
|
{
|
"dummy",
|
"dummy",
|
NULL,
|
NULL,
|
Line 128... |
Line 133... |
|
|
/* Set to 1 if the target is open. */
|
/* Set to 1 if the target is open. */
|
static int or1k_is_open = 0;
|
static int or1k_is_open = 0;
|
|
|
/* Error last occured, zero = ok. */
|
/* Error last occured, zero = ok. */
|
static int err = 0;
|
int err = 0;
|
|
|
|
/* Nonzero, if we changed something. */
|
|
int debug_regs_changed;
|
|
|
/* Number of interrupts while waiting for process. */
|
/* Number of interrupts while waiting for process. */
|
static int interrupt_count = 0;
|
static int interrupt_count = 0;
|
|
|
/* Reason of last stop. */
|
/* Reason of last stop. */
|
static int hit_watchpoint = 0;
|
static int hit_watchpoint = 0;
|
|
|
/* Current register values. */
|
/* Current register values. */
|
static unsigned int dmr1 = 0;
|
unsigned int dmr1 = 0;
|
static unsigned int dmr2 = 0;
|
unsigned int dmr2 = 0;
|
static unsigned int dsr = 0;
|
unsigned int dsr = 0;
|
static unsigned int drr = 0;
|
unsigned int drr = 0;
|
|
|
/* Current watchpoints. */
|
/* Current matchpoints. */
|
static int dvr[8];
|
unsigned int dvr[MAX_MATCHPOINTS];
|
static struct dcr_struct dcr[8];
|
struct dcr_struct dcr[MAX_MATCHPOINTS];
|
|
|
|
int matchpoint_user_count[MAX_MATCHPOINTS] = {0};
|
|
|
/* Handle low-level error that we can't recover from. Note that just
|
/* Handle low-level error that we can't recover from. Note that just
|
error()ing out from target_wait or some such low-level place will cause
|
error()ing out from target_wait or some such low-level place will cause
|
all hell to break loose--the rest of GDB will tend to get left in an
|
all hell to break loose--the rest of GDB will tend to get left in an
|
inconsistent state. */
|
inconsistent state. */
|
Line 284... |
Line 294... |
{
|
{
|
int val;
|
int val;
|
or1k_set_chain (SC_REGISTER);
|
or1k_set_chain (SC_REGISTER);
|
val = or1k_read_reg (JTAG_RISCOP);
|
val = or1k_read_reg (JTAG_RISCOP);
|
or1k_write_reg (JTAG_RISCOP, val | 1);
|
or1k_write_reg (JTAG_RISCOP, val | 1);
|
|
|
|
/* Be cautious - disable trace. */
|
|
val = or1k_read_reg (JTAG_MODER);
|
|
or1k_write_reg (JTAG_MODER, val & ~2);
|
or1k_flush_pipeline ();
|
or1k_flush_pipeline ();
|
}
|
}
|
|
|
/* Unstalls the CPU. */
|
/* Unstalls the CPU. */
|
|
|
Line 299... |
Line 313... |
val = or1k_read_reg (JTAG_RISCOP);
|
val = or1k_read_reg (JTAG_RISCOP);
|
or1k_write_reg (JTAG_RISCOP, val & ~1);
|
or1k_write_reg (JTAG_RISCOP, val & ~1);
|
}
|
}
|
|
|
/* Resets the CPU and stalls it. */
|
/* Resets the CPU and stalls it. */
|
|
|
static void
|
static void
|
or1k_reset ()
|
or1k_reset ()
|
{
|
{
|
unsigned int val;
|
unsigned int val;
|
or1k_set_chain (SC_REGISTER);
|
or1k_set_chain (SC_REGISTER);
|
|
|
|
/* Be cautious - disable trace. */
|
|
val = or1k_read_reg (JTAG_MODER);
|
|
or1k_write_reg (JTAG_MODER, val & ~2);
|
|
|
val = or1k_read_reg (JTAG_RISCOP);
|
val = or1k_read_reg (JTAG_RISCOP);
|
val &= ~3;
|
val &= ~3;
|
or1k_write_reg (JTAG_RISCOP, val | 3); /* Assert reset signal. */
|
/* Assert reset signal. */
|
usleep (1000); /* give it some time */
|
or1k_write_reg (JTAG_RISCOP, val | 3);
|
|
|
|
/* give it some time */
|
|
usleep (1000);
|
or1k_flush_pipeline ();
|
or1k_flush_pipeline ();
|
or1k_write_reg (JTAG_RISCOP, val | 1); /* Release reset signal, but keep in stall state. */
|
/* Release reset signal, but keep in stall state. */
|
|
or1k_write_reg (JTAG_RISCOP, val | 1);
|
or1k_flush_pipeline ();
|
or1k_flush_pipeline ();
|
}
|
}
|
|
|
|
/* Synchronizes debug registers in memory with those on target,
|
|
if there is any change. */
|
|
|
|
static void
|
|
or1k_commit_debug_registers ()
|
|
{
|
|
int i;
|
|
unsigned int u;
|
|
if (!debug_regs_changed)
|
|
return;
|
|
|
|
/* Matchpoints (breakpoints, watchpoints). */
|
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
|
{
|
|
unsigned int u;
|
|
or1k_write_spr_reg (DVR0_SPRNUM + i, dvr[i]);
|
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
}
|
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2);
|
|
|
|
/* Trace dependent. */
|
|
or1k_set_chain (SC_REGISTER);
|
|
memcpy (&u, &or1k_htrace.trig, sizeof(or1k_htrace.trig));
|
|
or1k_write_reg (JTAG_TSEL, u);
|
|
memcpy (&u, &or1k_htrace.qual, sizeof(or1k_htrace.qual));
|
|
or1k_write_reg (JTAG_QSEL, u);
|
|
memcpy (&u, &or1k_htrace.stop, sizeof(or1k_htrace.stop));
|
|
or1k_write_reg (JTAG_SSEL, u);
|
|
debug_regs_changed = 0;
|
|
for (i = 0; i < NUM_RECORDS; i++)
|
|
{
|
|
memcpy (&u, &or1k_htrace.recwp[i], sizeof(or1k_htrace.recwp[i]));
|
|
or1k_write_reg (JTAG_RECWP0 + i, u);
|
|
}
|
|
memcpy (&u, &or1k_htrace.recbp, sizeof(or1k_htrace.recbp));
|
|
or1k_write_reg (JTAG_RECBP0, u);
|
|
memcpy (&u, &or1k_htrace.moder, sizeof(or1k_htrace.moder));
|
|
or1k_write_reg (JTAG_MODER, u);
|
|
}
|
|
|
static void
|
static void
|
or1k_set_undefined_cleanups (arg)
|
or1k_set_undefined_cleanups (arg)
|
PTR arg;
|
PTR arg;
|
{
|
{
|
or1k_status = TARGET_UNDEFINED;
|
or1k_status = TARGET_UNDEFINED;
|
Line 330... |
Line 396... |
char *args;
|
char *args;
|
{
|
{
|
struct cleanup *old_cleanups = make_cleanup (or1k_set_undefined_cleanups, NULL);
|
struct cleanup *old_cleanups = make_cleanup (or1k_set_undefined_cleanups, NULL);
|
int i;
|
int i;
|
unsigned int tmp;
|
unsigned int tmp;
|
|
FILE *f;
|
|
|
/* What is this code doing here? I don't see any way it can happen, and
|
/* What is this code doing here? I don't see any way it can happen, and
|
it might mean or1k_initializing didn't get cleared properly.
|
it might mean or1k_initializing didn't get cleared properly.
|
So I'll make it a warning. */
|
So I'll make it a warning. */
|
|
|
Line 349... |
Line 416... |
current_or1k_target->to_init (args);
|
current_or1k_target->to_init (args);
|
|
|
/* Determine implementation configuration. */
|
/* Determine implementation configuration. */
|
or1k_implementation.VR = or1k_read_spr_reg (VR_SPRNUM);
|
or1k_implementation.VR = or1k_read_spr_reg (VR_SPRNUM);
|
or1k_implementation.UPR = or1k_read_spr_reg (UPR_SPRNUM);
|
or1k_implementation.UPR = or1k_read_spr_reg (UPR_SPRNUM);
|
|
|
/* Determine number of gpr_regs. */
|
/* Determine number of gpr_regs. */
|
tmp = or1k_read_spr_reg (CPUCFGR_SPRNUM);
|
tmp = or1k_read_spr_reg (CPUCFGR_SPRNUM);
|
or1k_implementation.num_gpr_regs = ((tmp >> 4) & 1)?(16):(32);
|
or1k_implementation.num_gpr_regs = ((tmp >> 4) & 1)?(16):(32);
|
|
|
/* Is any vector or floating point support present? */
|
/* Is any vector or floating point support present? */
|
or1k_implementation.vf_present = ((tmp >> 7) & 7) != 0;
|
or1k_implementation.vf_present = ((tmp >> 7) & 7) != 0;
|
or1k_implementation.num_vfpr_regs = (or1k_implementation.vf_present)?(32):(0);
|
or1k_implementation.num_vfpr_regs = (or1k_implementation.vf_present)?(32):(0);
|
|
|
/* Determine max number of supported matchpoints. */
|
/* Determine max number of supported matchpoints. */
|
Line 374... |
Line 443... |
if (or1k_implementation.has_counters)
|
if (or1k_implementation.has_counters)
|
warning ("Counters not supported.");
|
warning ("Counters not supported.");
|
|
|
/* Delete break, watch, catch points. */
|
/* Delete break, watch, catch points. */
|
for(i = 0; i < NUM_MATCHPOINTS; i++)
|
for(i = 0; i < NUM_MATCHPOINTS; i++)
|
or1k_write_spr_reg (DCR0_SPRNUM + i, 0);
|
{
|
|
memset (&dcr[i], 0, sizeof (dcr[i]));
|
|
matchpoint_user_count[i] = 0;
|
|
}
|
|
|
dmr1 = 0;
|
dmr1 = 0;
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
dmr2 = 0;
|
dmr2 = 0;
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2);
|
memset (&or1k_htrace, 0, sizeof (or1k_htrace));
|
|
|
|
/* RECSELDEPEND = 0 does not match our trace scheme. */
|
|
or1k_htrace.moder.rec_sel_dep = 1;
|
|
|
|
debug_regs_changed = 1;
|
|
or1k_commit_debug_registers ();
|
|
|
if (err != 0)
|
if (err != 0)
|
error ("Cannot connect.");
|
error ("Cannot connect.");
|
|
|
/* Stop when breakpoint occurs. */
|
/* Stop when breakpoint occurs. */
|
or1k_write_spr_reg (DSR_SPRNUM, 0x1000);
|
or1k_write_spr_reg (DSR_SPRNUM, 0x1000);
|
Line 393... |
Line 471... |
/* This should cause an error if not connected. */
|
/* This should cause an error if not connected. */
|
or1k_fetch_registers (-1);
|
or1k_fetch_registers (-1);
|
|
|
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
select_frame (get_current_frame (), 0);
|
select_frame (get_current_frame (), 0);
|
|
|
|
/* Just empty it. */
|
|
if ((f = fopen (TRACE_FILENAME, "wb+")) == NULL)
|
|
error ("Cannot open trace file.");
|
|
fclose (f);
|
|
trace_size = 0;
|
}
|
}
|
|
|
/* Kill the process running on the board. */
|
/* Kill the process running on the board. */
|
|
|
void
|
void
|
Line 472... |
Line 556... |
|
|
if (from_tty)
|
if (from_tty)
|
printf_unfiltered ("Ending remote or1k debugging.\n");
|
printf_unfiltered ("Ending remote or1k debugging.\n");
|
}
|
}
|
|
|
|
/* Appends trace data to the trace file. */
|
|
|
|
static void
|
|
or1k_read_trace ()
|
|
{
|
|
struct htrace_data_struct data;
|
|
long long int tmp;
|
|
int first = 1;
|
|
FILE *fd;
|
|
if ((fd = fopen (TRACE_FILENAME, "ab")) == NULL)
|
|
{
|
|
warning ("Cannot append to trace file.");
|
|
return;
|
|
}
|
|
|
|
or1k_set_chain (SC_TRACE);
|
|
while (1)
|
|
{
|
|
tmp = or1k_read_reg (0);
|
|
memcpy (&data, &tmp, sizeof (data));
|
|
|
|
/* Last record reached. */
|
|
if (!data.valid)
|
|
break;
|
|
data.valid = first;
|
|
first = 0;
|
|
if (!fwrite (&data, sizeof (data), 1, fd))
|
|
{
|
|
warning ("Cannot write trace data");
|
|
break;
|
|
}
|
|
}
|
|
fclose (fd);
|
|
}
|
|
|
/* Resume execution of the target process. STEP says whether to single-step
|
/* Resume execution of the target process. STEP says whether to single-step
|
or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
|
or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
|
to the target, or zero for no signal. */
|
to the target, or zero for no signal. */
|
|
|
static void
|
static void
|
Line 498... |
Line 617... |
dmr1 |= DMR1_ST;
|
dmr1 |= DMR1_ST;
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
dmr1 &= ~DMR1_ST;
|
dmr1 &= ~DMR1_ST;
|
}
|
}
|
|
|
|
or1k_commit_debug_registers ();
|
/* Run the target. */
|
/* Run the target. */
|
or1k_unstall ();
|
or1k_unstall ();
|
or1k_status = TARGET_RUNNING;
|
or1k_status = TARGET_RUNNING;
|
}
|
}
|
|
|
Line 536... |
Line 656... |
usleep (10);
|
usleep (10);
|
}
|
}
|
while (drr == 0);
|
while (drr == 0);
|
|
|
status->kind = TARGET_WAITKIND_STOPPED;
|
status->kind = TARGET_WAITKIND_STOPPED;
|
|
|
or1k_flush_pipeline ();
|
or1k_flush_pipeline ();
|
|
|
if (drr & DRR_RSTE)
|
if (drr & DRR_RSTE)
|
status->value.sig = TARGET_SIGNAL_REALTIME_33;
|
status->value.sig = TARGET_SIGNAL_REALTIME_33;
|
else if (drr & DRR_BUSEE)
|
else if (drr & DRR_BUSEE)
|
Line 582... |
Line 701... |
/* Search all active breakpoints for a match. */
|
/* Search all active breakpoints for a match. */
|
CORE_ADDR pc = read_pc ();
|
CORE_ADDR pc = read_pc ();
|
int breakpoint = 0;
|
int breakpoint = 0;
|
int i;
|
int i;
|
for (i = 0; i < or1k_implementation.num_used_matchpoints; i++)
|
for (i = 0; i < or1k_implementation.num_used_matchpoints; i++)
|
if (dvr[i] == pc && dcr[i].dp && dcr[i].cc == CC_EQUAL && !dcr[i].sc && dcr[i].ct == CT_FETCH)
|
if (dvr[i] == pc && dcr[i].dp && dcr[i].cc == CC_EQUAL
|
|
&& !dcr[i].sc && dcr[i].ct == CT_FETCH)
|
{
|
{
|
breakpoint = 1;
|
breakpoint = 1;
|
break;
|
break;
|
}
|
}
|
hit_watchpoint = !breakpoint;
|
hit_watchpoint = !breakpoint;
|
Line 605... |
Line 725... |
find_pc_partial_function (pc, &func_name, &func_start, NULL);
|
find_pc_partial_function (pc, &func_name, &func_start, NULL);
|
if (func_name != NULL && strcmp (func_name, "_exit") == 0
|
if (func_name != NULL && strcmp (func_name, "_exit") == 0
|
&& func_start == pc)
|
&& func_start == pc)
|
status->kind = TARGET_WAITKIND_EXITED;
|
status->kind = TARGET_WAITKIND_EXITED;
|
}
|
}
|
|
|
|
or1k_read_trace ();
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Fetch a word from the target board. All memory accesses to the
|
/* Fetch a word from the target board. All memory accesses to the
|
remote board are word aligned. */
|
remote board are word aligned. */
|
|
|
static unsigned int
|
unsigned int
|
or1k_fetch_word (addr)
|
or1k_fetch_word (addr)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
{
|
{
|
if (addr & 3)
|
if (addr & 3)
|
{
|
{
|
Line 637... |
Line 759... |
}
|
}
|
}
|
}
|
|
|
/* Store a word to the target board. Returns errno code or zero for
|
/* Store a word to the target board. Returns errno code or zero for
|
success. All memory accesses to the remote board are word aligned. */
|
success. All memory accesses to the remote board are word aligned. */
|
|
|
static int
|
static int
|
or1k_store_word (addr, val)
|
or1k_store_word (addr, val)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
unsigned int val;
|
unsigned int val;
|
{
|
{
|
Line 696... |
Line 819... |
value in the target byte ordering. */
|
value in the target byte ordering. */
|
store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val);
|
store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val);
|
supply_register (regno, buf);
|
supply_register (regno, buf);
|
}
|
}
|
if (err)
|
if (err)
|
or1k_error ("Can't read register %d(%i): %s", regno, REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_err_name (err));
|
or1k_error ("Can't read register %d(%i): %s", regno,
|
|
REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_err_name (err));
|
}
|
}
|
|
|
/* Fetch and return instruction from the specified location. */
|
/* Fetch and return instruction from the specified location. */
|
|
|
unsigned int
|
unsigned int
|
Line 788... |
Line 912... |
store_unsigned_integer (&buffer[(count - 1) * 4], 4,
|
store_unsigned_integer (&buffer[(count - 1) * 4], 4,
|
or1k_fetch_word (addr + (count - 1) * 4));
|
or1k_fetch_word (addr + (count - 1) * 4));
|
}
|
}
|
|
|
/* Copy data to be written over corresponding part of buffer */
|
/* Copy data to be written over corresponding part of buffer */
|
|
|
memcpy ((char *) buffer + (memaddr & 3), myaddr, len);
|
memcpy ((char *) buffer + (memaddr & 3), myaddr, len);
|
|
|
/* Write the entire buffer. */
|
/* Write the entire buffer. */
|
|
|
for (i = 0; i < count; i++, addr += 4)
|
for (i = 0; i < count; i++, addr += 4)
|
{
|
{
|
status = or1k_store_word (addr,
|
status = or1k_store_word (addr,
|
extract_unsigned_integer (&buffer[i * 4], 4));
|
extract_unsigned_integer (&buffer[i * 4], 4));
|
/* Report each kilobyte (we download 32-bit words at a time) */
|
/* Report each kilobyte (we download 32-bit words at a time) */
|
Line 867... |
Line 989... |
/* Print target info. */
|
/* Print target info. */
|
printf_filtered ("Status: %s\n", status_name[or1k_status]);
|
printf_filtered ("Status: %s\n", status_name[or1k_status]);
|
}
|
}
|
|
|
/* Tell whether we can support a hardware breakpoint. */
|
/* Tell whether we can support a hardware breakpoint. */
|
|
|
static int
|
static int
|
or1k_can_use_hardware_breakpoint ()
|
or1k_can_use_hardware_breakpoint ()
|
{
|
{
|
int i;
|
int i;
|
|
|
/* Search for unused breakpoint. */
|
/* Search for unused breakpoint. */
|
return or1k_implementation.num_used_matchpoints < or1k_implementation.num_matchpoints;
|
return or1k_implementation.num_used_matchpoints < or1k_implementation.num_matchpoints;
|
}
|
}
|
|
|
/* Insert a breakpoint. On targets that don't have built-in breakpoint
|
/* Insert a breakpoint. On targets that don't have built-in breakpoint
|
Line 921... |
Line 1045... |
/* Are there at least two matchpoints left for watch? - estimate lower bound */
|
/* Are there at least two matchpoints left for watch? - estimate lower bound */
|
return cnt + ((bp_type == bp_hardware_watchpoint)?(1):(0))
|
return cnt + ((bp_type == bp_hardware_watchpoint)?(1):(0))
|
<= or1k_implementation.num_matchpoints;
|
<= or1k_implementation.num_matchpoints;
|
}
|
}
|
|
|
|
/* Moves matchpoint. This is very tricky - we have to update
|
|
all references to matchpoint indexes. We assume here that
|
|
matchpoint with index to is unused! */
|
|
|
|
static void
|
|
move_matchpoint (int from, int to)
|
|
{
|
|
int i, j, tmp, chaining;
|
|
if (matchpoint_user_count[to] != 0)
|
|
error ("Internal: Destination matchpoint still has users");
|
|
matchpoint_user_count[to] = matchpoint_user_count[from];
|
|
matchpoint_user_count[from] = 0;
|
|
debug_regs_changed = 1;
|
|
|
|
dvr[to] = dvr[from];
|
|
dcr[to] = dcr[from];
|
|
dcr[from].dp = 0;
|
|
|
|
/* Copy chaining bits. */
|
|
chaining = dmr1 & (3 << (2 * from));
|
|
dmr1 &= ~(3 << (2 * to));
|
|
dmr1 |= chaining << (2 * to);
|
|
dmr1 &= ~(3 << (2 * from));
|
|
|
|
/* Copy watchpoint bits */
|
|
tmp = dmr2 & (1 << from);
|
|
dmr2 &= 1 << to;
|
|
dmr2 |= tmp << to;
|
|
dmr2 &= 1 << from;
|
|
|
|
/* Update hwatch table. Here we assume that matchpoint
|
|
group is connected (it cannot be implemented in HW
|
|
otherwise), so if we move first, we will have to move
|
|
others later. */
|
|
for (i = 0; i < num_hw_watches; i++)
|
|
if (or1k_hwatch[i].matchpoint_start == from)
|
|
or1k_hwatch[i].matchpoint_start = to;
|
|
|
|
/* Update htrace struct. */
|
|
tmp = or1k_htrace.trig.wp_trig & (1 << from);
|
|
or1k_htrace.trig.wp_trig &= 1 << to;
|
|
or1k_htrace.trig.wp_trig |= tmp << to;
|
|
or1k_htrace.trig.wp_trig &= 1 << from;
|
|
|
|
tmp = or1k_htrace.qual.wp_trig & (1 << from);
|
|
or1k_htrace.qual.wp_trig &= 1 << to;
|
|
or1k_htrace.qual.wp_trig |= tmp << to;
|
|
or1k_htrace.qual.wp_trig &= 1 << from;
|
|
|
|
tmp = or1k_htrace.stop.wp_trig & (1 << from);
|
|
or1k_htrace.stop.wp_trig &= 1 << to;
|
|
or1k_htrace.stop.wp_trig |= tmp << to;
|
|
or1k_htrace.stop.wp_trig &= 1 << from;
|
|
|
|
for (i = 0; i < MAX_MATCHPOINTS; i++)
|
|
{
|
|
tmp = or1k_htrace.wp_record_uses[i] & (1 << from);
|
|
or1k_htrace.wp_record_uses[i] &= 1 << to;
|
|
or1k_htrace.wp_record_uses[i] |= tmp << to;
|
|
or1k_htrace.wp_record_uses[i] &= 1 << from;
|
|
}
|
|
|
|
/* Do we need to move other references also? */
|
|
}
|
|
|
/* Sifts unused matchpoints to higher indexses. */
|
/* Sifts unused matchpoints to higher indexses. */
|
|
|
static void
|
void
|
sift_matchpoints ()
|
sift_matchpoints ()
|
{
|
{
|
int i, first_free = 0;
|
int i, first_free = 0;
|
unsigned int u;
|
|
for (i = 0; i < or1k_implementation.num_matchpoints; i++)
|
for (i = 0; i < or1k_implementation.num_matchpoints; i++)
|
if (dcr[i].dp)
|
if (dcr[i].dp)
|
{
|
{
|
int chaining;
|
/* Move references. */
|
dvr[first_free] = dvr[i];
|
move_matchpoint (i, first_free);
|
dcr[first_free] = dcr[i];
|
|
|
|
/* Copy chaining bits. */
|
|
chaining = dmr1 & (3 << (2 * i));
|
|
dmr1 &= ~(3 << (2 * first_free));
|
|
dmr1 |= chaining << (2 * first_free);
|
|
/* Copy watchpoint bits */
|
|
chaining = dmr2 & (1 << i);
|
|
dmr2 &= 1 << first_free;
|
|
dmr2 |= chaining << first_free;
|
|
/* !!! move references also */
|
|
|
|
or1k_write_spr_reg (DVR0_SPRNUM + first_free, dvr[first_free]);
|
|
memcpy (&u, &dcr[first_free], sizeof(dcr[first_free]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + first_free, u);
|
|
first_free++;
|
first_free++;
|
}
|
}
|
/* Disable unused. */
|
|
for (i = first_free; i < or1k_implementation.num_matchpoints; i++)
|
/* Unused matchpoints should be disabled by move_matchpoint,
|
{
|
so we are done here. */
|
dmr2 &= ~(1 << i);
|
|
dcr[i].dp = 0;
|
|
}
|
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2);
|
|
}
|
}
|
|
|
/* Translates gdb watchpoint type into one in DCR register. */
|
/* Translates gdb watchpoint type into one in DCR register. */
|
|
|
static int
|
static int
|
Line 990... |
Line 1159... |
CORE_ADDR addr;
|
CORE_ADDR addr;
|
int len;
|
int len;
|
int type;
|
int type;
|
{
|
{
|
int i;
|
int i;
|
unsigned int u;
|
|
if (len < 1)
|
if (len < 1)
|
return -1;
|
return -1;
|
|
|
type = translate_type (type);
|
type = translate_type (type);
|
|
|
/* Moves unused watchpoints to the top. */
|
/* Moves unused watchpoints to the top. */
|
sift_matchpoints ();
|
sift_matchpoints ();
|
|
|
/* Place at first free matchpoint. */
|
/* Place at first free matchpoint. */
|
i = or1k_implementation.num_used_matchpoints;
|
i = or1k_implementation.num_used_matchpoints;
|
dvr[i] = addr;
|
dvr[i] = addr;
|
dcr[i].dp = 1;
|
dcr[i].dp = 1;
|
dcr[i].cc = CC_GREATE;
|
dcr[i].cc = CC_GREATE;
|
dcr[i].sc = 0;
|
dcr[i].sc = 0;
|
dcr[i].ct = type;
|
dcr[i].ct = type;
|
or1k_write_spr_reg (DVR0_SPRNUM + i, dvr[i]);
|
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
|
|
/* Set && chaining here. */
|
/* Set && chaining here. */
|
dmr1 &= ~(3 << (2 * i));
|
dmr1 &= ~(3 << (2 * i));
|
dmr1 |= 2 << (2 * i);
|
dmr1 |= CHAINING_AND << (2 * i);
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
|
|
/* Set upper watchpoint bound. */
|
/* Set upper watchpoint bound. */
|
i++;
|
i++;
|
dvr[i] = addr + len - 1;
|
dvr[i] = addr + len - 1;
|
dcr[i].dp = 1;
|
dcr[i].dp = 1;
|
dcr[i].cc = CC_LESSE;
|
dcr[i].cc = CC_LESSE;
|
dcr[i].sc = 0;
|
dcr[i].sc = 0;
|
dcr[i].ct = type;
|
dcr[i].ct = type;
|
or1k_write_spr_reg (DVR0_SPRNUM + i, dvr[i]);
|
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
|
|
/* Matchpoints will cause breakpoints */
|
/* Matchpoints will cause breakpoints */
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 |= (1 << i));
|
dmr2 |= (1 << i);
|
or1k_implementation.num_used_matchpoints += 2;
|
or1k_implementation.num_used_matchpoints += 2;
|
|
debug_regs_changed = 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Removes a data watchpoint. ADDR and LEN should be obvious. TYPE is 0
|
/* Removes a data watchpoint. ADDR and LEN should be obvious. TYPE is 0
|
for a write watchpoint, 1 for a read watchpoint, or 2 for a read/write
|
for a write watchpoint, 1 for a read watchpoint, or 2 for a read/write
|
watchpoint. */
|
watchpoint. */
|
|
|
int
|
int
|
or1k_remove_watchpoint (addr, len, type)
|
or1k_remove_watchpoint (addr, len, type)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
int len;
|
int len;
|
int type;
|
int type;
|
{
|
{
|
int i, found = -1;
|
int i, found = -1;
|
unsigned int u;
|
|
if (len < 1)
|
if (len < 1)
|
return -1;
|
return -1;
|
|
|
type = translate_type (type);
|
type = translate_type (type);
|
|
|
Line 1061... |
Line 1226... |
|
|
if (found < 0)
|
if (found < 0)
|
return -1;
|
return -1;
|
|
|
dcr[found].dp = 0;
|
dcr[found].dp = 0;
|
memcpy (&u, &dcr[found], sizeof(dcr[found]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + found, u);
|
|
dcr[found + 1].dp = 0;
|
dcr[found + 1].dp = 0;
|
memcpy (&u, &dcr[found + 1], sizeof(dcr[found + 1]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + found + 1, u);
|
|
|
|
/* Matchpoints will not cause breakpoints anymore. */
|
/* Matchpoints will not cause breakpoints anymore. */
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 &= ~(1 << i));
|
dmr2 &= ~(1 << i);
|
or1k_implementation.num_used_matchpoints -= 2;
|
or1k_implementation.num_used_matchpoints -= 2;
|
|
debug_regs_changed = 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int
|
int
|
or1k_stopped_by_watchpoint (void)
|
or1k_stopped_by_watchpoint (void)
|
Line 1086... |
Line 1248... |
int
|
int
|
set_breakpoint (addr)
|
set_breakpoint (addr)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
{
|
{
|
int i;
|
int i;
|
unsigned int u;
|
|
/* Search for unused breakpoint. */
|
/* Search for unused breakpoint. */
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
if (dcr[i].dp == 0) break;
|
if (dcr[i].dp == 0) break;
|
if (i >= NUM_MATCHPOINTS) return 1;
|
if (i >= NUM_MATCHPOINTS) return 1;
|
dvr[i] = addr;
|
dvr[i] = addr;
|
dcr[i].dp = 1;
|
dcr[i].dp = 1;
|
dcr[i].cc = CC_EQUAL;
|
dcr[i].cc = CC_EQUAL;
|
dcr[i].sc = 0;
|
dcr[i].sc = 0;
|
dcr[i].ct = CT_FETCH;
|
dcr[i].ct = CT_FETCH;
|
or1k_write_spr_reg (DVR0_SPRNUM + i, dvr[i]);
|
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
or1k_implementation.num_used_matchpoints++;
|
or1k_implementation.num_used_matchpoints++;
|
|
|
/* No chaining here. */
|
/* No chaining here. */
|
dmr1 &= ~(3 << (2*i));
|
dmr1 &= ~(3 << (2*i));
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
/* Matchpoints will cause breakpoints */
|
/* Matchpoints will cause breakpoints */
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 |= (1 << i));
|
dmr2 |= (1 << i);
|
|
debug_regs_changed = 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Clear a breakpoint. */
|
/* Clear a breakpoint. */
|
|
|
int
|
int
|
clear_breakpoint (addr)
|
clear_breakpoint (addr)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
{
|
{
|
int i;
|
int i;
|
unsigned int u;
|
|
/* Search for matching breakpoint. */
|
/* Search for matching breakpoint. */
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
if ((dcr[i].dp == 1) && (dvr[i] == addr) && (dcr[i].cc == CC_EQUAL)
|
if ((dcr[i].dp == 1) && (dvr[i] == addr) && (dcr[i].cc == CC_EQUAL)
|
&& (dcr[i].sc == 0) && (dcr[i].ct == CT_FETCH)) break;
|
&& (dcr[i].sc == 0) && (dcr[i].ct == CT_FETCH)) break;
|
|
|
if (i >= NUM_MATCHPOINTS) return 1;
|
if (i >= NUM_MATCHPOINTS) return 1;
|
dcr[i].dp = 0;
|
dcr[i].dp = 0;
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
/* Matchpoints will cause breakpoints */
|
/* Matchpoints will cause breakpoints */
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 &= ~(1 << i));
|
dmr2 &= ~(1 << i);
|
or1k_implementation.num_used_matchpoints--;
|
or1k_implementation.num_used_matchpoints--;
|
|
debug_regs_changed = 1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Start running on the target board. */
|
/* Start running on the target board. */
|
|
|
Line 1144... |
Line 1304... |
{
|
{
|
CORE_ADDR entry_pt;
|
CORE_ADDR entry_pt;
|
|
|
if (args && *args)
|
if (args && *args)
|
{
|
{
|
warning ("\
|
warning ("Can't pass arguments to remote OR1K board; arguments ignored.");
|
Can't pass arguments to remote OR1K board; arguments ignored.");
|
|
/* And don't try to use them on the next "run" command. */
|
/* And don't try to use them on the next "run" command. */
|
execute_command ("set args", 0);
|
execute_command ("set args", 0);
|
}
|
}
|
|
|
if (execfile == 0 || exec_bfd == 0)
|
if (execfile == 0 || exec_bfd == 0)
|
Line 1161... |
Line 1321... |
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
|
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
|
init_wait_for_inferior ();
|
init_wait_for_inferior ();
|
|
|
/* FIXME: Should we set inferior_pid here? */
|
/* FIXME: Should we set inferior_pid here? */
|
|
|
insert_breakpoints (); /* Needed to get correct instruction in cache */
|
/* Needed to get correct instruction in cache */
|
|
insert_breakpoints ();
|
clear_proceed_status ();
|
clear_proceed_status ();
|
or1k_status = TARGET_STOPPED;
|
or1k_status = TARGET_STOPPED;
|
proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
|
proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
|
}
|
}
|
|
|
Line 1272... |
Line 1433... |
or1k_dummy_ops.to_kill = or1k_kill;
|
or1k_dummy_ops.to_kill = or1k_kill;
|
or1k_dummy_ops.to_load = generic_load;
|
or1k_dummy_ops.to_load = generic_load;
|
or1k_dummy_ops.to_create_inferior = or1k_create_inferior;
|
or1k_dummy_ops.to_create_inferior = or1k_create_inferior;
|
or1k_dummy_ops.to_mourn_inferior = or1k_mourn_inferior;
|
or1k_dummy_ops.to_mourn_inferior = or1k_mourn_inferior;
|
or1k_dummy_ops.to_stratum = process_stratum;
|
or1k_dummy_ops.to_stratum = process_stratum;
|
or1k_dummy_ops.to_has_all_memory = 0; /* We can access memory while program is running. */
|
|
|
/* We can access memory while program is running. */
|
|
or1k_dummy_ops.to_has_all_memory = 0;
|
|
|
or1k_dummy_ops.to_has_memory = 1;
|
or1k_dummy_ops.to_has_memory = 1;
|
or1k_dummy_ops.to_has_stack = 1;
|
or1k_dummy_ops.to_has_stack = 1;
|
or1k_dummy_ops.to_has_registers = 1;
|
or1k_dummy_ops.to_has_registers = 1;
|
or1k_dummy_ops.to_has_execution = 1;
|
or1k_dummy_ops.to_has_execution = 1;
|
or1k_dummy_ops.to_magic = OPS_MAGIC;
|
or1k_dummy_ops.to_magic = OPS_MAGIC;
|