Line 187... |
Line 187... |
static void or1k_create_inferior (char *execfile,
|
static void or1k_create_inferior (char *execfile,
|
char *args,
|
char *args,
|
char **env,
|
char **env,
|
int from_tty);
|
int from_tty);
|
static void or1k_mourn_inferior ();
|
static void or1k_mourn_inferior ();
|
|
static void or1k_rcmd (char *command,
|
|
struct ui_file *outbuf);
|
/* Global target operations specific to the OR1K */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*!Read a special purpose register from the target
|
|
|
|
Use the target operation for this.
|
|
|
|
@param[in] regnum The register to read
|
|
|
|
@return The value read */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
ULONGEST
|
|
or1k_read_spr (unsigned int regnum)
|
|
{
|
|
return or1k_jtag_read_spr (regnum);
|
|
|
|
} /* or1k_read_spr() */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*!Write a special purpose register on the target
|
|
|
|
Use the target operation for this.
|
|
|
|
@param[in] regnum The register to write
|
|
@param[in] data The value to write */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void
|
|
or1k_write_spr (unsigned int regnum,
|
|
ULONGEST data)
|
|
{
|
|
or1k_jtag_write_spr (regnum, data);
|
|
|
|
} /* or1k_write_spr() */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Ask the user about an interrupt
|
/*!Ask the user about an interrupt
|
|
|
Line 665... |
Line 629... |
}
|
}
|
|
|
/* The "special" registers */
|
/* The "special" registers */
|
switch (regnum)
|
switch (regnum)
|
{
|
{
|
|
case OR1K_PPC_REGNUM: return OR1K_NPC_SPRNUM;
|
|
case OR1K_NPC_REGNUM: return OR1K_NPC_SPRNUM;
|
case OR1K_SR_REGNUM: return OR1K_SR_SPRNUM;
|
case OR1K_SR_REGNUM: return OR1K_SR_SPRNUM;
|
case OR1K_PC_REGNUM: return OR1K_NPC_SPRNUM;
|
|
|
|
default:
|
default:
|
error ("or1k_regnum_to_sprnum: invalid register number!");
|
error ("or1k_regnum_to_sprnum: invalid register number!");
|
break;
|
break;
|
}
|
}
|
Line 706... |
Line 671... |
dcr |= or1k_dbgcache.dcr[i].dp ? OR1K_DCR_DP : 0;
|
dcr |= or1k_dbgcache.dcr[i].dp ? OR1K_DCR_DP : 0;
|
dcr |= (or1k_dbgcache.dcr[i].cc << OR1K_DCR_CC_OFF) & OR1K_DCR_CC;
|
dcr |= (or1k_dbgcache.dcr[i].cc << OR1K_DCR_CC_OFF) & OR1K_DCR_CC;
|
dcr |= or1k_dbgcache.dcr[i].sc ? OR1K_DCR_SC : 0;
|
dcr |= or1k_dbgcache.dcr[i].sc ? OR1K_DCR_SC : 0;
|
dcr |= (or1k_dbgcache.dcr[i].ct << OR1K_DCR_CT_OFF) & OR1K_DCR_CT;
|
dcr |= (or1k_dbgcache.dcr[i].ct << OR1K_DCR_CT_OFF) & OR1K_DCR_CT;
|
|
|
or1k_write_spr (OR1K_DVR0_SPRNUM + i, or1k_dbgcache.dvr[i]);
|
or1k_jtag_write_spr (OR1K_DVR0_SPRNUM + i, or1k_dbgcache.dvr[i]);
|
or1k_write_spr (OR1K_DCR0_SPRNUM + i, dcr);
|
or1k_jtag_write_spr (OR1K_DCR0_SPRNUM + i, dcr);
|
}
|
}
|
|
|
or1k_write_spr (OR1K_DMR1_SPRNUM, or1k_dbgcache.dmr1);
|
or1k_jtag_write_spr (OR1K_DMR1_SPRNUM, or1k_dbgcache.dmr1);
|
or1k_write_spr (OR1K_DMR2_SPRNUM, or1k_dbgcache.dmr2);
|
or1k_jtag_write_spr (OR1K_DMR2_SPRNUM, or1k_dbgcache.dmr2);
|
or1k_write_spr (OR1K_DSR_SPRNUM, or1k_dbgcache.dsr);
|
or1k_jtag_write_spr (OR1K_DSR_SPRNUM, or1k_dbgcache.dsr);
|
or1k_write_spr (OR1K_DRR_SPRNUM, or1k_dbgcache.drr);
|
or1k_jtag_write_spr (OR1K_DRR_SPRNUM, or1k_dbgcache.drr);
|
|
|
} /* or1k_commit_debug_registers() */
|
} /* or1k_commit_debug_registers() */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
Line 807... |
Line 772... |
|
|
/* Initialize the connection to the remote target. */
|
/* Initialize the connection to the remote target. */
|
or1k_jtag_init (name);
|
or1k_jtag_init (name);
|
|
|
/* Make sure we have system and debug groups implemented. */
|
/* Make sure we have system and debug groups implemented. */
|
tmp = or1k_read_spr (OR1K_UPR_SPRNUM);
|
tmp = or1k_jtag_read_spr (OR1K_UPR_SPRNUM);
|
if (0 == (tmp & OR1K_SPR_UPR_UP))
|
if (0 == (tmp & OR1K_SPR_UPR_UP))
|
{
|
{
|
error ("or1k_open: system group missing");
|
error ("or1k_open: system group missing");
|
}
|
}
|
if (0 == (tmp & OR1K_SPR_UPR_DUP))
|
if (0 == (tmp & OR1K_SPR_UPR_DUP))
|
Line 820... |
Line 785... |
}
|
}
|
|
|
/* Determine number of gpr_regs (this is a bit simplified - the bit just
|
/* Determine number of gpr_regs (this is a bit simplified - the bit just
|
means "less than 32", but we assume that means 16) and the number of
|
means "less than 32", but we assume that means 16) and the number of
|
supported watchpoints. */
|
supported watchpoints. */
|
tmp = or1k_read_spr (OR1K_CPUCFGR_SPRNUM);
|
tmp = or1k_jtag_read_spr (OR1K_CPUCFGR_SPRNUM);
|
tdep->num_gpr_regs = (0 == (tmp & OR1K_SPR_CPUCFGR_CGF)) ? 32 : 16;
|
tdep->num_gpr_regs = (0 == (tmp & OR1K_SPR_CPUCFGR_CGF)) ? 32 : 16;
|
|
|
tmp = or1k_read_spr (OR1K_DCFGR_SPRNUM);
|
tmp = or1k_jtag_read_spr (OR1K_DCFGR_SPRNUM);
|
tdep->num_matchpoints = (tmp & OR1K_SPR_DCFGR_NDP) + 1;
|
tdep->num_matchpoints = (tmp & OR1K_SPR_DCFGR_NDP) + 1;
|
|
|
/* Stall the processor. A pause after stalling is appropriate for real
|
/* Stall the processor. A pause after stalling is appropriate for real
|
hardware. */
|
hardware. */
|
or1k_jtag_stall ();
|
or1k_jtag_stall ();
|
Line 950... |
Line 915... |
{
|
{
|
error ("or1k_fetch_registers: invalid register number");
|
error ("or1k_fetch_registers: invalid register number");
|
}
|
}
|
|
|
/* Convert to SPRNUM and read. */
|
/* Convert to SPRNUM and read. */
|
val = or1k_read_spr (or1k_regnum_to_sprnum (regnum));
|
val = or1k_jtag_read_spr (or1k_regnum_to_sprnum (regnum));
|
|
|
/* We got the number the register holds, but gdb expects to see a value in
|
/* We got the number the register holds, but gdb expects to see a value in
|
the target byte ordering.
|
the target byte ordering.
|
|
|
This is new for GDB 6.8. Not sure if I need get_thread_regcache() using
|
This is new for GDB 6.8. Not sure if I need get_thread_regcache() using
|
Line 996... |
Line 961... |
error ("or1k_store_registers: invalid register number");
|
error ("or1k_store_registers: invalid register number");
|
}
|
}
|
|
|
regcache = get_current_regcache();
|
regcache = get_current_regcache();
|
regcache_cooked_read_unsigned (regcache, regnum, &res);
|
regcache_cooked_read_unsigned (regcache, regnum, &res);
|
or1k_write_spr (or1k_regnum_to_sprnum (regnum), res);
|
or1k_jtag_write_spr (or1k_regnum_to_sprnum (regnum), res);
|
|
|
} /* or1k_store_registers() */
|
} /* or1k_store_registers() */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
Line 1489... |
Line 1454... |
|
|
/* We can now continue normally, independent of step. If this is called for
|
/* We can now continue normally, independent of step. If this is called for
|
the first time due to a run command, we won't actually be executing, so
|
the first time due to a run command, we won't actually be executing, so
|
start the target running. */
|
start the target running. */
|
|
|
or1k_write_spr( OR1K_NPC_SPRNUM, read_pc());
|
or1k_jtag_write_spr( OR1K_NPC_SPRNUM, read_pc());
|
target_has_execution = 1;
|
target_has_execution = 1;
|
or1k_jtag_unstall ();
|
or1k_jtag_unstall ();
|
|
|
} /* or1k_resume() */
|
} /* or1k_resume() */
|
|
|
Line 1534... |
Line 1499... |
|
|
/* Registers and frame caches are now all unreliable */
|
/* Registers and frame caches are now all unreliable */
|
registers_changed();
|
registers_changed();
|
|
|
/* Refresh the debug registers that may have changed */
|
/* Refresh the debug registers that may have changed */
|
or1k_dbgcache.drr = or1k_read_spr (OR1K_DRR_SPRNUM);
|
or1k_dbgcache.drr = or1k_jtag_read_spr (OR1K_DRR_SPRNUM);
|
or1k_dbgcache.dmr2 = or1k_read_spr (OR1K_DMR2_SPRNUM);
|
or1k_dbgcache.dmr2 = or1k_jtag_read_spr (OR1K_DMR2_SPRNUM);
|
|
|
/* If we got a trap, then it was a breakpoint/watchpoint of some sort (but
|
/* If we got a trap, then it was a breakpoint/watchpoint of some sort (but
|
not single step, which does not set the trap exception). We need to back
|
not single step, which does not set the trap exception). We need to back
|
up the program counter, so the instruction will be re-executed. This
|
up the program counter, so the instruction will be re-executed. This
|
must be the value of the PPC, in case we have just done a branch. */
|
must be the value of the PPC, in case we have just done a branch. */
|
|
|
if (OR1K_DRR_TE == (or1k_dbgcache.drr & OR1K_DRR_TE))
|
if (OR1K_DRR_TE == (or1k_dbgcache.drr & OR1K_DRR_TE))
|
{
|
{
|
write_pc (or1k_read_spr (OR1K_PPC_SPRNUM));
|
write_pc (or1k_jtag_read_spr (OR1K_PPC_SPRNUM));
|
}
|
}
|
|
|
/* Single step does not set trap exception, so we set it manually to
|
/* Single step does not set trap exception, so we set it manually to
|
simplify our code. */
|
simplify our code. */
|
if (OR1K_DMR1_ST == (or1k_dbgcache.dmr1 & OR1K_DMR1_ST))
|
if (OR1K_DMR1_ST == (or1k_dbgcache.dmr1 & OR1K_DMR1_ST))
|
Line 1583... |
Line 1548... |
interrupt. This happens at reset and exit. The latter we distinquish
|
interrupt. This happens at reset and exit. The latter we distinquish
|
by looking at the instruction just executed, to see if it is
|
by looking at the instruction just executed, to see if it is
|
"l.nop NOP_EXIT". If this is the case, get the result from GPR 3 and
|
"l.nop NOP_EXIT". If this is the case, get the result from GPR 3 and
|
set the NPC to the reset vector, so a new start will behave well. */
|
set the NPC to the reset vector, so a new start will behave well. */
|
|
|
addr = or1k_read_spr (OR1K_PPC_SPRNUM);
|
addr = or1k_jtag_read_spr (OR1K_PPC_SPRNUM);
|
res = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
|
res = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
|
if (0 != res)
|
if (0 != res)
|
{
|
{
|
memory_error (res, addr);
|
memory_error (res, addr);
|
}
|
}
|
Line 1721... |
Line 1686... |
}
|
}
|
} /* or1k_mourn_inferior () */
|
} /* or1k_mourn_inferior () */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
|
/*!Send a command to the remote target
|
|
|
|
The target can't actually run any remote commands, in the sense of having a
|
|
command interpreter. However we use this as a GDB "standard" way of
|
|
wrapping up commands to access the SPRs.
|
|
|
|
Current commands supported are:
|
|
- readspr <regno>
|
|
- writespr <regno> <value>
|
|
|
|
The output is either the value read (for successful read) or OK (for
|
|
successful write) or E01 to indicate and wrror. All values are represented
|
|
as unsigned hex.
|
|
|
|
@param[in] command The command to execute
|
|
@param[out] output The result of the command */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void or1k_rcmd (char *command,
|
|
struct ui_file *outbuf)
|
|
{
|
|
/* Sort out which command */
|
|
if (0 == strncmp ("readspr", command, strlen ("readspr")))
|
|
{
|
|
unsigned int regno; /* SPR to read */
|
|
|
|
if (1 != sscanf (command, "readspr %4x", ®no))
|
|
{
|
|
error ("or1k_rcmd: unrecognized readspr");
|
|
fputs_unfiltered ("E01", outbuf);
|
|
}
|
|
else
|
|
{
|
|
char strbuf[sizeof ("ffffffff")];
|
|
ULONGEST data = or1k_jtag_read_spr (regno);
|
|
|
|
sprintf (strbuf, "%8llx", data);
|
|
fputs_unfiltered (strbuf, outbuf);
|
|
}
|
|
}
|
|
else if (0 == strncmp ("writespr", command, strlen ("writespr")))
|
|
{
|
|
unsigned int regno; /* SPR to write */
|
|
ULONGEST data; /* Value to write */
|
|
|
|
if (2 != sscanf (command, "writespr %4x %8llx", ®no, &data))
|
|
{
|
|
error ("or1k_rcmd: unrecognized writespr");
|
|
fputs_unfiltered ("E01", outbuf);
|
|
}
|
|
else
|
|
{
|
|
or1k_jtag_write_spr (regno, data);
|
|
fputs_unfiltered ("OK", outbuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error ("or1k_rcmd: unrecognized remote command");
|
|
fputs_unfiltered ("E01", outbuf);
|
|
}
|
|
} /* or1k_rcmd () */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*!Main entry point for the remote OpenRISC JTAG protocol
|
/*!Main entry point for the remote OpenRISC JTAG protocol
|
|
|
Initializes the target ops for each version of the remote
|
Initializes the target ops for each version of the remote
|
protocol. Currently only the JTAG protocol is implemented.
|
protocol. Currently only the JTAG protocol is implemented.
|
|
|
Line 1790... |
Line 1820... |
or1k_target.to_stop = or1k_stop;
|
or1k_target.to_stop = or1k_stop;
|
or1k_target.to_kill = or1k_kill;
|
or1k_target.to_kill = or1k_kill;
|
or1k_target.to_create_inferior = or1k_create_inferior;
|
or1k_target.to_create_inferior = or1k_create_inferior;
|
or1k_target.to_mourn_inferior = or1k_mourn_inferior;
|
or1k_target.to_mourn_inferior = or1k_mourn_inferior;
|
|
|
|
or1k_target.to_rcmd = or1k_rcmd;
|
|
|
or1k_target.to_magic = OPS_MAGIC;
|
or1k_target.to_magic = OPS_MAGIC;
|
|
|
/* Tell GDB about the new target */
|
/* Tell GDB about the new target */
|
|
|
add_target (&or1k_target);
|
add_target (&or1k_target);
|