Line 37... |
Line 37... |
#include <sys/stat.h>
|
#include <sys/stat.h>
|
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
|
|
extern void jtag_init PARAMS ((char * args));
|
extern void jtag_init PARAMS ((char * args));
|
extern unsigned 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 int data));
|
extern void jtag_write_reg PARAMS ((unsigned int regno, unsigned long long int data));
|
extern unsigned int jtag_read_tap_reg PARAMS ((unsigned int regno));
|
|
extern void jtag_write_tap_reg PARAMS ((unsigned int regno, unsigned int data));
|
|
extern void jtag_done PARAMS ((void));
|
extern void jtag_done PARAMS ((void));
|
|
extern void jtag_set_chain PARAMS ((int chain));
|
struct target_ops or1k_jtag_ops;
|
struct target_ops or1k_jtag_ops;
|
static struct or1k_target_ops or1k_target_jtag =
|
static struct or1k_target_ops or1k_target_jtag =
|
{
|
{
|
"jtag",
|
"jtag",
|
jtag_init,
|
jtag_init,
|
jtag_done,
|
jtag_done,
|
jtag_read_reg,
|
jtag_read_reg,
|
jtag_write_reg,
|
jtag_write_reg,
|
jtag_read_tap_reg,
|
jtag_set_chain,
|
jtag_write_tap_reg,
|
|
NULL,
|
NULL,
|
&or1k_jtag_ops,
|
&or1k_jtag_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
Line 68... |
Line 65... |
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
|
&or1k_sim_ops,
|
&or1k_sim_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
struct target_ops or1k_dummy_ops;
|
struct target_ops or1k_dummy_ops;
|
Line 83... |
Line 79... |
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
|
&or1k_dummy_ops,
|
&or1k_dummy_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
const char *str_err[] =
|
const char *str_err[] =
|
Line 98... |
Line 93... |
const char *status_name[] =
|
const char *status_name[] =
|
{
|
{
|
"UNDEFINED", "CONNECTING", "DISCONNECTING", "RUNNING", "STOPPED"
|
"UNDEFINED", "CONNECTING", "DISCONNECTING", "RUNNING", "STOPPED"
|
};
|
};
|
|
|
|
/* Names for matchpoint related stuff. */
|
|
static char *ct_names[] =
|
|
{
|
|
"DIS", "IFEA", "LEA", "SEA", "AEA", "LDATA", "SDATA", "ADATA"
|
|
};
|
|
|
|
static char *cc_names[] =
|
|
{
|
|
"&", "==", "<", "<=", ">", ">=", "!=", "ERR"
|
|
};
|
|
|
|
static char *ch_names[] =
|
|
{
|
|
"ERR", "&", "|", "ERR"
|
|
};
|
|
|
/* Implementation specific information. Set by or1k_initialize. */
|
/* Implementation specific information. Set by or1k_initialize. */
|
struct struct_or1k_implementation or1k_implementation;
|
struct struct_or1k_implementation or1k_implementation;
|
|
|
/* Current target status. */
|
/* Current target status. */
|
static enum target_status or1k_status = TARGET_UNDEFINED;
|
static enum target_status or1k_status = TARGET_UNDEFINED;
|
Line 122... |
Line 133... |
static int err = 0;
|
static int err = 0;
|
|
|
/* 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. */
|
|
static int hit_watchpoint = 0;
|
|
|
/* Current register values. */
|
/* Current register values. */
|
static unsigned int dmr1 = 0;
|
static unsigned int dmr1 = 0;
|
static unsigned int dmr2 = 0;
|
static unsigned int dmr2 = 0;
|
static unsigned int dsr = 0;
|
static unsigned int dsr = 0;
|
static unsigned int drr = 0;
|
static unsigned int drr = 0;
|
Line 207... |
Line 221... |
|
|
while ((c = *string++) != '\0')
|
while ((c = *string++) != '\0')
|
fputc_readable (c, file);
|
fputc_readable (c, file);
|
}
|
}
|
|
|
|
/* Sets scan chain. */
|
|
|
|
static void
|
|
or1k_set_chain (chain)
|
|
int chain;
|
|
{
|
|
if (current_or1k_target != NULL && current_or1k_target->to_set_chain != NULL)
|
|
current_or1k_target->to_set_chain (chain);
|
|
}
|
|
|
/* Sets register/memory regno to data. */
|
/* Sets register/memory regno to data. */
|
|
|
void
|
static void
|
or1k_write_reg (regno, data)
|
or1k_write_reg (regno, data)
|
unsigned int regno;
|
unsigned int regno;
|
unsigned int data;
|
unsigned long long int data;
|
{
|
{
|
if (current_or1k_target != NULL && current_or1k_target->to_write_spr_reg != NULL)
|
if (current_or1k_target != NULL && current_or1k_target->to_write_reg != NULL)
|
current_or1k_target->to_write_spr_reg (regno, data);
|
current_or1k_target->to_write_reg (regno, data);
|
}
|
}
|
|
|
/* Reads register/memory from regno. */
|
/* Reads register/memory from regno. */
|
|
|
unsigned int
|
static unsigned long long int
|
or1k_read_reg (regno)
|
or1k_read_reg (regno)
|
unsigned int regno;
|
unsigned int regno;
|
{
|
{
|
if (current_or1k_target != NULL && current_or1k_target->to_read_spr_reg != NULL)
|
if (current_or1k_target != NULL && current_or1k_target->to_read_reg != NULL)
|
return current_or1k_target->to_read_spr_reg (regno);
|
return current_or1k_target->to_read_reg (regno);
|
else
|
else
|
return 0x1234;
|
return 0x1234;
|
}
|
}
|
|
|
|
/* Sets SPR register regno to data. */
|
|
|
|
void
|
|
or1k_write_spr_reg (regno, data)
|
|
unsigned int regno;
|
|
unsigned int data;
|
|
{
|
|
or1k_set_chain (SC_RISC_DEBUG);
|
|
or1k_write_reg (regno + REG_SPACE, data);
|
|
}
|
|
|
|
/* Reads register SPR from regno. */
|
|
|
|
unsigned int
|
|
or1k_read_spr_reg (regno)
|
|
unsigned int regno;
|
|
{
|
|
or1k_set_chain (SC_RISC_DEBUG);
|
|
return or1k_read_reg (regno + REG_SPACE);
|
|
}
|
|
|
/* Stalls the CPU. */
|
/* Stalls the CPU. */
|
|
|
static void
|
static void
|
or1k_stall ()
|
or1k_stall ()
|
{
|
{
|
//!!! or1k_write_tap_reg (xxx, xxx);
|
int val;
|
|
or1k_set_chain (SC_REGISTER);
|
|
val = or1k_read_reg (JTAG_RISCOP);
|
|
or1k_write_reg (JTAG_RISCOP, val | 1);
|
|
or1k_flush_pipeline ();
|
}
|
}
|
|
|
/* Unstalls the CPU. */
|
/* Unstalls the CPU. */
|
|
|
static void
|
static void
|
or1k_unstall ()
|
or1k_unstall ()
|
{
|
{
|
//!!! or1k_write_tap_reg (xxx, xxx);
|
unsigned int val;
|
|
or1k_set_chain (SC_REGISTER);
|
|
val = or1k_read_reg (JTAG_RISCOP);
|
|
or1k_write_reg (JTAG_RISCOP, val & ~1);
|
|
}
|
|
|
|
/* Resets the CPU and stalls it. */
|
|
static void
|
|
or1k_reset ()
|
|
{
|
|
unsigned int val;
|
|
or1k_set_chain (SC_REGISTER);
|
|
val = or1k_read_reg (JTAG_RISCOP);
|
|
val &= ~3;
|
|
or1k_write_reg (JTAG_RISCOP, val | 3); /* Assert reset signal. */
|
|
usleep (1000); /* give it some time */
|
|
or1k_flush_pipeline ();
|
|
or1k_write_reg (JTAG_RISCOP, val | 1); /* Release reset signal, but keep in stall state. */
|
|
or1k_flush_pipeline ();
|
}
|
}
|
|
|
static void
|
static void
|
or1k_set_undefined_cleanups (arg)
|
or1k_set_undefined_cleanups (arg)
|
PTR arg;
|
PTR arg;
|
Line 274... |
Line 341... |
warning ("internal error: or1k_initialize called twice");
|
warning ("internal error: or1k_initialize called twice");
|
return;
|
return;
|
}
|
}
|
|
|
or1k_status = TARGET_CONNECTING;
|
or1k_status = TARGET_CONNECTING;
|
or1k_stall ();
|
or1k_reset ();
|
if (current_or1k_target != NULL && current_or1k_target->to_init != NULL)
|
if (current_or1k_target != NULL && current_or1k_target->to_init != NULL)
|
current_or1k_target->to_init (args);
|
current_or1k_target->to_init (args);
|
|
|
/* Determine implementation configuration. */
|
/* Determine implementation configuration. */
|
or1k_implementation.VR = or1k_read_reg (VR_SPRNUM);
|
or1k_implementation.VR = or1k_read_spr_reg (VR_SPRNUM);
|
or1k_implementation.UPR = or1k_read_reg (UPR_SPRNUM);
|
or1k_implementation.UPR = or1k_read_spr_reg (UPR_SPRNUM);
|
|
|
/* Determine max number of supported matchpoints. */
|
/* Determine max number of supported matchpoints. */
|
or1k_implementation.num_matchpoints = 2;
|
or1k_implementation.num_matchpoints = 2;
|
|
or1k_implementation.num_used_matchpoints = 0;
|
or1k_implementation.num_gpr_regs = 32;
|
or1k_implementation.num_gpr_regs = 32;
|
/*!!! FINISH */
|
/*!!! FINISH */
|
|
|
|
|
/* Is implementation supported? */
|
/* Is implementation supported? */
|
Line 300... |
Line 368... |
|
|
|
|
|
|
/* 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_reg (DCR0_SPRNUM + i, 0);
|
or1k_write_spr_reg (DCR0_SPRNUM + i, 0);
|
|
|
dmr1 = 0;
|
dmr1 = 0;
|
or1k_write_reg (DMR1_SPRNUM, dmr1);
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
dmr2 = 0;
|
dmr2 = 0;
|
or1k_write_reg (DMR2_SPRNUM, dmr2);
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2);
|
if (err != 0)
|
if (err != 0)
|
error ("Cannot connect.");
|
error ("Cannot connect.");
|
|
|
/* Stop when breakpoint occurs. */
|
/* Stop when breakpoint occurs. */
|
or1k_write_reg (DSR_SPRNUM, 0x1000);
|
or1k_write_spr_reg (DSR_SPRNUM, 0x1000);
|
|
|
do_cleanups (old_cleanups);
|
do_cleanups (old_cleanups);
|
|
|
/* This should cause an error if not connected. */
|
/* This should cause an error if not connected. */
|
or1k_fetch_registers (-1);
|
or1k_fetch_registers (-1);
|
Line 329... |
Line 397... |
or1k_kill ()
|
or1k_kill ()
|
{
|
{
|
if (or1k_status != TARGET_RUNNING)
|
if (or1k_status != TARGET_RUNNING)
|
return;
|
return;
|
or1k_status = TARGET_UNDEFINED;
|
or1k_status = TARGET_UNDEFINED;
|
/* HW STEP. Set DMR1_ST. */
|
or1k_reset();
|
dmr1 |= DMR1_ST;
|
or1k_status = TARGET_STOPPED;
|
or1k_write_reg (DMR1_SPRNUM, dmr1);
|
|
dmr1 &= ~DMR1_ST;
|
|
or1k_stall();
|
|
or1k_status = TARGET_UNDEFINED;
|
|
|
|
inferior_pid = 0;
|
inferior_pid = 0;
|
}
|
}
|
|
|
/* Open a connection to the remote board. */
|
/* Open a connection to the remote board. */
|
Line 418... |
Line 482... |
error ("Program is already running.");
|
error ("Program is already running.");
|
else
|
else
|
error ("The program is not being run.");
|
error ("The program is not being run.");
|
|
|
/* Clear reason register for later. */
|
/* Clear reason register for later. */
|
or1k_write_reg (DRR_SPRNUM, 0);
|
or1k_write_spr_reg (DRR_SPRNUM, 0);
|
|
|
if (step)
|
if (step)
|
{
|
{
|
/* HW STEP. Set DMR1_ST. */
|
/* HW STEP. Set DMR1_ST. */
|
dmr1 |= DMR1_ST;
|
dmr1 |= DMR1_ST;
|
or1k_write_reg (DMR1_SPRNUM, dmr1);
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
dmr1 &= ~DMR1_ST;
|
dmr1 &= ~DMR1_ST;
|
}
|
}
|
|
|
/* Run the target. */
|
/* Run the target. */
|
or1k_unstall ();
|
or1k_unstall ();
|
Line 460... |
Line 524... |
or1k_error ("Remote failure: %s", or1k_err_name (err));
|
or1k_error ("Remote failure: %s", or1k_err_name (err));
|
|
|
/* Wait for or1k DRR register to be nonzero. */
|
/* Wait for or1k DRR register to be nonzero. */
|
do
|
do
|
{
|
{
|
drr = or1k_read_reg (DRR_SPRNUM);
|
drr = or1k_read_spr_reg (DRR_SPRNUM);
|
usleep (10);
|
usleep (10);
|
}
|
}
|
while (drr == 0);
|
while (drr == 0);
|
|
|
status->kind = TARGET_WAITKIND_STOPPED;
|
status->kind = TARGET_WAITKIND_STOPPED;
|
|
|
|
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)
|
status->value.sig = TARGET_SIGNAL_BUS;
|
status->value.sig = TARGET_SIGNAL_BUS;
|
else if (drr & DRR_DPFE)
|
else if (drr & DRR_DPFE)
|
Line 499... |
Line 565... |
{
|
{
|
status->value.sig = TARGET_SIGNAL_UNKNOWN;
|
status->value.sig = TARGET_SIGNAL_UNKNOWN;
|
warning ("Invalid exception occured.");
|
warning ("Invalid exception occured.");
|
}
|
}
|
|
|
|
/* Log remote stop. */
|
or1k_status = TARGET_STOPPED;
|
or1k_status = TARGET_STOPPED;
|
|
|
|
/* Determine what caused trap - breakpoint or watchpoint. */
|
|
if (status->value.sig == TARGET_SIGNAL_TRAP)
|
|
{
|
|
/* Search all active breakpoints for a match. */
|
|
CORE_ADDR pc = read_pc ();
|
|
int breakpoint = 0;
|
|
int 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)
|
|
{
|
|
breakpoint = 1;
|
|
break;
|
|
}
|
|
hit_watchpoint = !breakpoint;
|
|
}
|
|
else
|
|
hit_watchpoint = 0;
|
|
|
/* If the stop PC is in the _exit function, assume
|
/* If the stop PC is in the _exit function, assume
|
we hit the 'break 0x3ff' instruction in _exit, so this
|
we hit the 'break 0x3ff' instruction in _exit, so this
|
is not a normal breakpoint. */
|
is not a normal breakpoint. */
|
{
|
{
|
char *func_name;
|
char *func_name;
|
Line 517... |
Line 602... |
status->kind = TARGET_WAITKIND_EXITED;
|
status->kind = TARGET_WAITKIND_EXITED;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Fetch a word from the target board. */
|
/* Fetch a word from the target board. All memory accesses to the
|
|
remote board are word aligned. */
|
|
|
static unsigned int
|
static unsigned int
|
or1k_fetch_word (addr)
|
or1k_fetch_word (addr)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
{
|
{
|
|
if (addr & 3)
|
|
{
|
|
int subaddr = addr & 3;
|
|
unsigned char buf[8];
|
|
unsigned int low, high;
|
|
addr >>= 2;
|
|
low = or1k_read_reg (addr + MEM_SPACE);
|
|
high = or1k_read_reg (addr + 1 + MEM_SPACE);
|
|
memcpy (&buf[0], &low, 4);
|
|
memcpy (&buf[4], &high, 4);
|
|
memcpy (&low, &buf[subaddr], 4);
|
|
return low;
|
|
}
|
|
else
|
|
{
|
|
addr >>= 2;
|
return or1k_read_reg (addr + MEM_SPACE);
|
return or1k_read_reg (addr + MEM_SPACE);
|
}
|
}
|
|
}
|
|
|
/* 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. */
|
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;
|
{
|
{
|
|
if (addr & 3)
|
|
{
|
|
int subaddr = addr & 3;
|
|
unsigned char buf[8];
|
|
unsigned int low, high;
|
|
addr >>= 2;
|
|
low = or1k_read_reg (addr + MEM_SPACE);
|
|
high = or1k_read_reg (addr + 1 + MEM_SPACE);
|
|
memcpy (&buf[0], &low, 4);
|
|
memcpy (&buf[4], &high, 4);
|
|
memcpy (&buf[subaddr], &val, 4);
|
|
memcpy (&low, &buf[0], 4);
|
|
memcpy (&high, &buf[4], 4);
|
|
or1k_write_reg (addr + MEM_SPACE, low);
|
|
or1k_write_reg (addr + 1 + MEM_SPACE, high);
|
|
}
|
|
else
|
|
{
|
|
addr >>= 2;
|
or1k_write_reg (addr + MEM_SPACE, val);
|
or1k_write_reg (addr + MEM_SPACE, val);
|
|
}
|
return err;
|
return err;
|
}
|
}
|
|
|
/* Fetch the remote registers. */
|
/* Fetch the remote registers. */
|
|
|
Line 556... |
Line 679... |
|
|
if (regno >= NUM_REGS)
|
if (regno >= NUM_REGS)
|
error("Invalid register number!");
|
error("Invalid register number!");
|
|
|
/* Convert to SPRNUM and read. */
|
/* Convert to SPRNUM and read. */
|
val = or1k_read_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE);
|
val = or1k_read_spr_reg (REGNUM_TO_SPRNUM(regno));
|
|
|
{
|
{
|
char buf[MAX_REGISTER_RAW_SIZE];
|
char buf[MAX_REGISTER_RAW_SIZE];
|
|
|
/* We got the number the register holds, but gdb expects to see a
|
/* We got the number the register holds, but gdb expects to see a
|
Line 585... |
Line 708... |
if (status)
|
if (status)
|
memory_error (status, addr);
|
memory_error (status, addr);
|
return extract_unsigned_integer (buf, OR1K_INSTLEN);
|
return extract_unsigned_integer (buf, OR1K_INSTLEN);
|
}
|
}
|
|
|
|
/* Currently not needed. */
|
|
|
static void
|
static void
|
or1k_prepare_to_store ()
|
or1k_prepare_to_store ()
|
{
|
{
|
}
|
}
|
|
|
Line 606... |
Line 731... |
}
|
}
|
|
|
if (regno >= NUM_REGS)
|
if (regno >= NUM_REGS)
|
error("Invalid register number!");
|
error("Invalid register number!");
|
|
|
or1k_write_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_read_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE));
|
or1k_write_spr_reg (REGNUM_TO_SPRNUM(regno), or1k_read_spr_reg (REGNUM_TO_SPRNUM(regno)));
|
if (err)
|
if (err)
|
or1k_error ("Can't write register %d(%i): %s", regno, REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_err_name (err));
|
or1k_error ("Can't write register %d(%i): %s", regno, REGNUM_TO_SPRNUM(regno), or1k_err_name (err));
|
}
|
}
|
|
|
/* Read or write LEN bytes from inferior memory at MEMADDR,
|
/* Read or write LEN bytes from inferior memory at MEMADDR,
|
transferring to or from debugger address MYADDR. Write to inferior
|
transferring to or from debugger address MYADDR. Write to inferior
|
if SHOULD_WRITE is nonzero. Returns length of data written or
|
if SHOULD_WRITE is nonzero. Returns length of data written or
|
Line 697... |
Line 822... |
memcpy (myaddr, buffer + (memaddr & 3), len);
|
memcpy (myaddr, buffer + (memaddr & 3), len);
|
}
|
}
|
return len;
|
return len;
|
}
|
}
|
|
|
|
/* Flushes pipeline. May not be needed by all implementations, but
|
|
it doen't hurt to do it. This function should be called every time
|
|
or1k stops.
|
|
When or1k stops it still has instructions in pipeline.
|
|
We do this by inserting nop instructions.
|
|
IF cycle remains unaffacted by writing to DIR, and it still holds
|
|
instruction, that caused break or watchpoint. */
|
|
|
|
void
|
|
or1k_flush_pipeline ()
|
|
{
|
|
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR);
|
|
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR);
|
|
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR);
|
|
}
|
|
|
/* Print info on this target. */
|
/* Print info on this target. */
|
|
|
static void
|
static void
|
or1k_files_info (ignore)
|
or1k_files_info (ignore)
|
struct target_ops *ignore;
|
struct target_ops *ignore;
|
Line 719... |
Line 860... |
}
|
}
|
/* Print target info. */
|
/* Print target info. */
|
printf_filtered ("Status: %s\n", status_name[or1k_status]);
|
printf_filtered ("Status: %s\n", status_name[or1k_status]);
|
}
|
}
|
|
|
|
|
/* We can write a breakpoint and read the shadow contents in one
|
|
operation. */
|
|
|
|
/* 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. */
|
for (i = 0; i < NUM_MATCHPOINTS; i++)
|
return or1k_implementation.num_used_matchpoints < or1k_implementation.num_matchpoints;
|
if (dcr[i].dp == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
}
|
|
|
/* Insert a breakpoint. On targets that don't have built-in breakpoint
|
/* Insert a breakpoint. On targets that don't have built-in breakpoint
|
support, we read the contents of the target location and stash it,
|
support, we read the contents of the target location and stash it,
|
then overwrite it with a breakpoint instruction. ADDR is the target
|
then overwrite it with a breakpoint instruction. ADDR is the target
|
location in the target machine. CONTENTS_CACHE is a pointer to
|
location in the target machine. CONTENTS_CACHE is a pointer to
|
memory allocated for saving the target contents. It is guaranteed
|
memory allocated for saving the target contents. It is guaranteed
|
by the caller to be long enough to save sizeof BREAKPOINT bytes (this
|
by the caller to be long enough to save sizeof BREAKPOINT bytes (this
|
is accomplished via BREAKPOINT_MAX). */
|
is accomplished via BREAKPOINT_MAX). */
|
|
|
static int
|
int
|
or1k_insert_breakpoint (addr, contents_cache)
|
or1k_insert_breakpoint (addr, contents_cache)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
char *contents_cache;
|
char *contents_cache;
|
{
|
{
|
if (or1k_can_use_hardware_breakpoint())
|
if (or1k_can_use_hardware_breakpoint())
|
return set_breakpoint (addr);
|
return set_breakpoint (addr);
|
else
|
else
|
return memory_insert_breakpoint (addr, contents_cache);
|
return memory_insert_breakpoint (addr, contents_cache);
|
}
|
}
|
|
|
static int
|
int
|
or1k_remove_breakpoint (addr, contents_cache)
|
or1k_remove_breakpoint (addr, contents_cache)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
char *contents_cache;
|
char *contents_cache;
|
{
|
{
|
/* First try to remove HW breakpoint at address */
|
/* First try to remove HW breakpoint at address */
|
Line 766... |
Line 900... |
return memory_remove_breakpoint (addr, contents_cache);
|
return memory_remove_breakpoint (addr, contents_cache);
|
else
|
else
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
/* Tell whether this target can support a hardware breakpoint. CNT
|
|
is the number of hardware breakpoints already installed. This
|
|
implements the TARGET_CAN_USE_HARDWARE_WATCHPOINT macro.
|
|
Lower bound is estimated. !!! Can we estimate better? */
|
|
|
|
int
|
|
or1k_can_use_hardware_watchpoint (bp_type, cnt)
|
|
enum bptype bp_type;
|
|
int cnt;
|
|
{
|
|
/* Are there at least two matchpoints left for watch? - estimate lower bound */
|
|
return cnt + ((bp_type == bp_hardware_watchpoint)?(1):(0))
|
|
<= or1k_implementation.num_matchpoints;
|
|
}
|
|
|
|
/* Sifts unused matchpoints to higher indexses. */
|
|
|
|
static void
|
|
sift_matchpoints ()
|
|
{
|
|
int i, first_free = 0;
|
|
unsigned int u;
|
|
for (i = 0; i < or1k_implementation.num_matchpoints; i++)
|
|
if (dcr[i].dp)
|
|
{
|
|
int chaining;
|
|
dvr[first_free] = dvr[i];
|
|
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++;
|
|
}
|
|
/* Disable unused. */
|
|
for (i = first_free; i < or1k_implementation.num_matchpoints; i++)
|
|
{
|
|
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. */
|
|
|
|
static int
|
|
translate_type (gdb_type)
|
|
int gdb_type;
|
|
{
|
|
switch (gdb_type)
|
|
{
|
|
case 0:
|
|
return CT_SDATA;
|
|
case 1:
|
|
return CT_LDATA;
|
|
case 2:
|
|
return CT_ADATA;
|
|
default:
|
|
error ("Invalid type.");
|
|
}
|
|
}
|
|
|
|
/* Set 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
|
|
watchpoint. */
|
|
|
|
int
|
|
or1k_insert_watchpoint (addr, len, type)
|
|
CORE_ADDR addr;
|
|
int len;
|
|
int type;
|
|
{
|
|
int i;
|
|
unsigned int u;
|
|
if (len < 1)
|
|
return -1;
|
|
|
|
type = translate_type (type);
|
|
|
|
/* Moves unused watchpoints to the top. */
|
|
sift_matchpoints ();
|
|
/* Place at first free matchpoint. */
|
|
i = or1k_implementation.num_used_matchpoints;
|
|
dvr[i] = addr;
|
|
dcr[i].dp = 1;
|
|
dcr[i].cc = CC_GREATE;
|
|
dcr[i].sc = 0;
|
|
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. */
|
|
dmr1 &= ~(3 << (2 * i));
|
|
dmr1 |= 2 << (2 * i);
|
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
|
|
/* Set upper watchpoint bound. */
|
|
i++;
|
|
dvr[i] = addr + len - 1;
|
|
dcr[i].dp = 1;
|
|
dcr[i].cc = CC_LESSE;
|
|
dcr[i].sc = 0;
|
|
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 */
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 |= (1 << i));
|
|
or1k_implementation.num_used_matchpoints += 2;
|
|
return 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
|
|
watchpoint. */
|
|
int
|
|
or1k_remove_watchpoint (addr, len, type)
|
|
CORE_ADDR addr;
|
|
int len;
|
|
int type;
|
|
{
|
|
int i, found = -1;
|
|
unsigned int u;
|
|
if (len < 1)
|
|
return -1;
|
|
|
|
type = translate_type (type);
|
|
|
|
/* Find the right one. */
|
|
for (i = 0; i < or1k_implementation.num_used_matchpoints; i++)
|
|
if (dvr[i] == addr && dcr[i].dp && dcr[i].cc == CC_GREATE && !dcr[i].sc && dcr[i].ct == type
|
|
&& dvr[i + 1] == addr + len - 1 && dcr[i + 1].dp && dcr[i + 1].cc == CC_LESSE
|
|
&& !dcr[i + 1].sc && dcr[i + 1].ct == type)
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
|
|
if (found < 0)
|
|
return -1;
|
|
|
|
dcr[found].dp = 0;
|
|
memcpy (&u, &dcr[found], sizeof(dcr[found]));
|
|
or1k_write_spr_reg (DCR0_SPRNUM + found, u);
|
|
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. */
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 &= ~(1 << i));
|
|
or1k_implementation.num_used_matchpoints -= 2;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
or1k_stopped_by_watchpoint (void)
|
|
{
|
|
return hit_watchpoint;
|
|
}
|
|
|
/* Insert a breakpoint. */
|
/* Insert a breakpoint. */
|
|
|
int
|
int
|
set_breakpoint (addr)
|
set_breakpoint (addr)
|
CORE_ADDR addr;
|
CORE_ADDR addr;
|
Line 783... |
Line 1090... |
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_reg (DVR0_SPRNUM + i, dvr[i]);
|
or1k_write_spr_reg (DVR0_SPRNUM + i, dvr[i]);
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
or1k_write_reg (DCR0_SPRNUM + i, u);
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
or1k_implementation.num_used_matchpoints++;
|
|
|
|
/* No chaining here. */
|
|
dmr1 &= ~(3 << (2*i));
|
|
or1k_write_spr_reg (DMR1_SPRNUM, dmr1);
|
|
/* Matchpoints will cause breakpoints */
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 |= (1 << i));
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Clear a breakpoint. */
|
/* Clear a breakpoint. */
|
|
|
Line 805... |
Line 1119... |
&& (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]));
|
memcpy (&u, &dcr[i], sizeof(dcr[i]));
|
or1k_write_reg (DCR0_SPRNUM + i, u);
|
or1k_write_spr_reg (DCR0_SPRNUM + i, u);
|
|
/* Matchpoints will cause breakpoints */
|
|
or1k_write_spr_reg (DMR2_SPRNUM, dmr2 &= ~(1 << i));
|
|
or1k_implementation.num_used_matchpoints--;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Start running on the target board. */
|
/* Start running on the target board. */
|
|
|
Line 837... |
Line 1154... |
|
|
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? */
|
//inferior_pid = 42;
|
|
insert_breakpoints (); /* Needed to get correct instruction in cache */
|
insert_breakpoints (); /* Needed to get correct instruction in cache */
|
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 899... |
Line 1216... |
current_or1k_target->to_exec_command (args, from_tty);
|
current_or1k_target->to_exec_command (args, from_tty);
|
else
|
else
|
error ("Command not supported on this target. ");
|
error ("Command not supported on this target. ");
|
}
|
}
|
|
|
|
/* Displays matchpoints usage. */
|
|
|
|
void
|
|
info_matchpoints_command (char *args, int from_tty)
|
|
{
|
|
int i;
|
|
for (i = 0; i < or1k_implementation.num_matchpoints; i++)
|
|
{
|
|
printf_filtered ("WP%i ", i);
|
|
if (dcr[i].dp)
|
|
{
|
|
int chaining = (dmr1 << 2*i) & 3;
|
|
printf_filtered ("= %s ", ct_names[dcr[i].ct]);
|
|
if (dcr[i]. sc)
|
|
printf_filtered ("s%s %i", cc_names[dcr[i].cc], (int)dvr[i]);
|
|
else
|
|
printf_filtered ("%s %u", cc_names[dcr[i].cc], (unsigned int)dvr[i]);
|
|
if (chaining)
|
|
printf_filtered ("%s WP%i", ch_names[chaining], i - 1);
|
|
}
|
|
else
|
|
printf_filtered ("NOT USED");
|
|
if ((dmr2 >> i) & 1)
|
|
printf_filtered (", causes breakpoint");
|
|
if ((dmr2 >> (i + 11)) & 1)
|
|
printf_filtered (", increments counter");
|
|
printf_filtered ("\n");
|
|
}
|
|
}
|
|
|
void
|
void
|
_initialize_remote_or1k ()
|
_initialize_remote_or1k ()
|
{
|
{
|
/* Initialize the fields in or1k_ops that are common to all targets. */
|
/* Initialize the fields in or1k_ops that are common to all targets. */
|
or1k_dummy_ops.to_close = or1k_close;
|
or1k_dummy_ops.to_close = or1k_close;
|
Line 925... |
Line 1272... |
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;
|
//or1k_ops.to_wait = or1k_wait;
|
|
|
|
/* Copy the common fields to all target vectors. */
|
/* Copy the common fields to all target vectors. */
|
or1k_jtag_ops = or1k_sim_ops = or1k_dummy_ops;
|
or1k_jtag_ops = or1k_sim_ops = or1k_dummy_ops;
|
|
|
/* Initialize target-specific fields in the target vectors adn add targets. */
|
/* Initialize target-specific fields in the target vectors adn add targets. */
|
Line 950... |
Line 1296... |
or1k_sim_ops.to_shortname = "sim";
|
or1k_sim_ops.to_shortname = "sim";
|
or1k_sim_ops.to_longname = "Remote or1k debugging using architecture simulator";
|
or1k_sim_ops.to_longname = "Remote or1k debugging using architecture simulator";
|
or1k_sim_ops.to_doc = "Debug using an architecture simulator.\n";
|
or1k_sim_ops.to_doc = "Debug using an architecture simulator.\n";
|
or1k_sim_ops.to_open = or1k_sim_open;
|
or1k_sim_ops.to_open = or1k_sim_open;
|
add_target (&or1k_sim_ops);
|
add_target (&or1k_sim_ops);
|
|
add_info ("matchpoints", info_matchpoints_command, "Show current matchpoints allocation status.");
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|