Watchpoint support (only implemented for tilib driver).

This commit is contained in:
Daniel Beer 2012-04-25 12:43:14 +12:00
parent a914bc732d
commit a354116441
11 changed files with 124 additions and 39 deletions

View File

@ -20,7 +20,7 @@
device_t device_default;
static int addbrk(device_t dev, uint16_t addr)
static int addbrk(device_t dev, uint16_t addr, device_bptype_t type)
{
int i;
int which = -1;
@ -30,7 +30,7 @@ static int addbrk(device_t dev, uint16_t addr)
bp = &dev->breakpoints[i];
if (bp->flags & DEVICE_BP_ENABLED) {
if (bp->addr == addr)
if (bp->addr == addr && bp->type == type)
return i;
} else if (which < 0) {
which = i;
@ -43,11 +43,12 @@ static int addbrk(device_t dev, uint16_t addr)
bp = &dev->breakpoints[which];
bp->flags = DEVICE_BP_ENABLED | DEVICE_BP_DIRTY;
bp->addr = addr;
bp->type = type;
return which;
}
static void delbrk(device_t dev, uint16_t addr)
static void delbrk(device_t dev, uint16_t addr, device_bptype_t type)
{
int i;
@ -55,20 +56,21 @@ static void delbrk(device_t dev, uint16_t addr)
struct device_breakpoint *bp = &dev->breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) &&
bp->addr == addr) {
bp->addr == addr && bp->type == type) {
bp->flags = DEVICE_BP_DIRTY;
bp->addr = 0;
}
}
}
int device_setbrk(device_t dev, int which, int enabled, address_t addr)
int device_setbrk(device_t dev, int which, int enabled, address_t addr,
device_bptype_t type)
{
if (which < 0) {
if (enabled)
return addbrk(dev, addr);
return addbrk(dev, addr, type);
delbrk(dev, addr);
delbrk(dev, addr, type);
} else {
struct device_breakpoint *bp = &dev->breakpoints[which];
int new_flags = enabled ? DEVICE_BP_ENABLED : 0;
@ -80,6 +82,7 @@ int device_setbrk(device_t dev, int which, int enabled, address_t addr)
(bp->flags & DEVICE_BP_ENABLED) != new_flags) {
bp->flags = new_flags | DEVICE_BP_DIRTY;
bp->addr = addr;
bp->type = type;
}
}

View File

@ -51,9 +51,15 @@ typedef enum {
#define DEVICE_BP_ENABLED 0x01
#define DEVICE_BP_DIRTY 0x02
typedef enum {
DEVICE_BPTYPE_BREAK,
DEVICE_BPTYPE_WATCH
} device_bptype_t;
struct device_breakpoint {
address_t addr;
int flags;
device_bptype_t type;
address_t addr;
int flags;
};
#define DEVICE_FLAG_JTAG 0x01 /* default is SBW */
@ -122,7 +128,8 @@ struct device {
* modified. Otherwise, if which < 0, breakpoint slots are selected
* automatically.
*/
int device_setbrk(device_t dev, int which, int enabled, address_t address);
int device_setbrk(device_t dev, int which, int enabled, address_t address,
device_bptype_t type);
extern device_t device_default;

View File

@ -698,13 +698,15 @@ static int refresh_bps(struct fet_device *dev)
for (i = 0; i < dev->base.max_breakpoints; i++) {
struct device_breakpoint *bp = &dev->base.breakpoints[i];
if (bp->flags & DEVICE_BP_DIRTY) {
if ((bp->flags & DEVICE_BP_DIRTY) &&
bp->type == DEVICE_BPTYPE_BREAK) {
uint16_t addr = bp->addr;
if (!(bp->flags & DEVICE_BP_ENABLED))
addr = 0;
if (xfer(dev, C_BREAKPOINT, NULL, 0, 2, i, addr) < 0) {
if (xfer(dev, C_BREAKPOINT, NULL, 0,
2, i, addr) < 0) {
printc_err("fet: failed to refresh "
"breakpoint #%d\n", i);
ret = -1;

View File

@ -238,6 +238,9 @@ static int refresh_bps(struct gdb_client *dev)
if (!(bp->flags & DEVICE_BP_DIRTY))
continue;
if (bp->type != DEVICE_BPTYPE_BREAK)
continue;
if ((old->flags & DEVICE_BP_ENABLED) &&
(bp_send(&dev->gdb, 'z', old->addr) < 0))
return -1;

View File

@ -702,6 +702,7 @@ static device_status_t sim_poll(device_t dev_base)
&dev->base.breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) &&
(bp->type == DEVICE_BPTYPE_BREAK) &&
dev->regs[MSP430_REG_PC] == bp->addr) {
dev->running = 0;
return DEVICE_STATUS_HALTED;

View File

@ -304,6 +304,46 @@ static int tilib_setregs(device_t dev_base, const address_t *regs)
return 0;
}
static void load_break(BpParameter_t *param, address_t addr)
{
param->bpMode = BP_CODE;
param->lAddrVal = addr;
param->bpType = BP_MAB;
param->lReg = 0; /* not used */
param->bpAccess = BP_FETCH;
param->bpAction = BP_BRK;
param->bpOperat = BP_EQUAL;
param->lMask = 0; /* what's this? */
param->lRangeEndAdVa = 0; /* not used */
param->bpRangeAction = 0; /* not used */
param->bpCondition = BP_NO_COND;
param->lCondMdbVal = 0;
param->bpCondAccess = BP_FETCH;
param->lCondMask = 0; /* what's this? */
param->bpCondOperat = BP_EQUAL;
param->wExtCombine = 0; /* not used? */
}
static void load_watch(BpParameter_t *param, address_t addr)
{
param->bpMode = BP_COMPLEX;
param->lAddrVal = addr;
param->bpType = BP_MAB;
param->lReg = 0; /* not used (only for register-write) */
param->bpAccess = BP_NO_FETCH;
param->bpAction = BP_BRK;
param->bpOperat = BP_EQUAL;
param->lMask = 0xffffff;
param->lRangeEndAdVa = 0; /* not used */
param->bpRangeAction = 0; /* not used */
param->bpCondition = BP_NO_COND;
param->lCondMdbVal = 0;
param->bpCondAccess = BP_NO_FETCH;
param->lCondMask = 0; /* what's this? */
param->bpCondOperat = BP_EQUAL;
param->wExtCombine = 0; /* not used? */
}
static int refresh_bps(struct tilib_device *dev)
{
int i;
@ -316,22 +356,15 @@ static int refresh_bps(struct tilib_device *dev)
continue;
if (bp->flags & DEVICE_BP_ENABLED) {
param.bpMode = BP_CODE;
param.lAddrVal = bp->addr;
param.bpType = BP_MAB;
param.lReg = 0; /* not used */
param.bpAccess = BP_FETCH;
param.bpAction = BP_BRK;
param.bpOperat = BP_EQUAL;
param.lMask = 0; /* what's this? */
param.lRangeEndAdVa = 0; /* not used */
param.bpRangeAction = 0; /* not used */
param.bpCondition = BP_NO_COND;
param.lCondMdbVal = 0;
param.bpCondAccess = BP_FETCH;
param.lCondMask = 0; /* what's this? */
param.bpCondOperat = BP_EQUAL;
param.wExtCombine = 0; /* not used? */
switch (bp->type) {
case DEVICE_BPTYPE_BREAK:
load_break(&param, bp->addr);
break;
case DEVICE_BPTYPE_WATCH:
load_watch(&param, bp->addr);
break;
}
} else {
param.bpMode = BP_CLEAR;
}

View File

@ -153,7 +153,8 @@ Use the Texas Instruments MSP430.DLL to access the device. The library
file (MSP430.DLL for Windows, libmsp430.so for Unix-like systems) must
be present in the dynamic loader search path.
USB connection is not supported for this driver.
USB connection is not supported for this driver. This driver supports
watchpoints.
.SH COMMANDS
MSPDebug can accept commands either through an interactive prompt, or
non-interactively when specified on the command line. The supported
@ -402,6 +403,11 @@ Add a new breakpoint. The breakpoint location is an address expression. An
optional index may be specified, indicating that this new breakpoint should
overwrite an existing slot. If no index is specified, then the breakpoint
will be stored in the next unused slot.
.IP "\fBsetwatch\fR \fIaddress\fR [\fIindex\fR]"
Add a new watchpoint. The watchpoint location is an address expression, and
an optional index may be specified. Watchpoints are considered to be a type
of breakpoint and can be inspected or removed using the \fBbreak\fR and
\fBdelbreak\fR commands. Note that not all drivers support watchpoints.
.IP "\fBsimio add\fR \fIclass\fR \fIname\fR [\fIargs ...\fR]"
Add a new peripheral to the IO simulator. The \fIclass\fR parameter may be
any of the peripheral types named in the output of the \fBsimio classes\fR

View File

@ -59,6 +59,14 @@ const struct cmddb_record commands[] = {
.help =
"setbreak <addr> [index]\n"
" Set a breakpoint. If no index is specified, the first available\n"
" slot will be used.\n"
},
{
.name = "setwatch",
.func = cmd_setwatch,
.help =
"setwatch <addr> [index]\n"
" Set a watchpoint. If no index is specified. the first available\n"
" slot will be used.\n"
},
{

View File

@ -215,6 +215,7 @@ int cmd_run(char **arg)
&device_default->breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) &&
bp->type == DEVICE_BPTYPE_BREAK &&
bp->addr == regs[0])
break;
}
@ -563,7 +564,7 @@ int cmd_load(char **arg)
return do_cmd_prog(arg, 0);
}
int cmd_setbreak(char **arg)
static int do_setbreak(device_bptype_t type, char **arg)
{
char *addr_text = get_arg(arg);
char *index_text = get_arg(arg);
@ -585,14 +586,15 @@ int cmd_setbreak(char **arg)
if (expr_eval(index_text, &val) < 0 ||
val >= device_default->max_breakpoints) {
printc("setbreak: invalid breakpoint slot: %d\n", val);
printc("setbreak: invalid breakpoint slot: %d\n",
val);
return -1;
}
index = val;
}
index = device_setbrk(device_default, index, 1, addr);
index = device_setbrk(device_default, index, 1, addr, type);
if (index < 0) {
printc_err("setbreak: all breakpoint slots are "
"occupied\n");
@ -603,6 +605,16 @@ int cmd_setbreak(char **arg)
return 0;
}
int cmd_setbreak(char **arg)
{
return do_setbreak(DEVICE_BPTYPE_BREAK, arg);
}
int cmd_setwatch(char **arg)
{
return do_setbreak(DEVICE_BPTYPE_WATCH, arg);
}
int cmd_delbreak(char **arg)
{
char *index_text = get_arg(arg);
@ -619,13 +631,13 @@ int cmd_delbreak(char **arg)
}
printc("Clearing breakpoint %d\n", index);
device_setbrk(device_default, index, 0, 0);
device_setbrk(device_default, index, 0, 0, 0);
} else {
int i;
printc("Clearing all breakpoints...\n");
for (i = 0; i < device_default->max_breakpoints; i++)
device_setbrk(device_default, i, 0, 0);
device_setbrk(device_default, i, 0, 0, 0);
}
return ret;
@ -637,7 +649,8 @@ int cmd_break(char **arg)
(void)arg;
printc("%d breakpoints available:\n", device_default->max_breakpoints);
printc("%d breakpoints available:\n",
device_default->max_breakpoints);
for (i = 0; i < device_default->max_breakpoints; i++) {
const struct device_breakpoint *bp =
&device_default->breakpoints[i];
@ -646,7 +659,13 @@ int cmd_break(char **arg)
char name[128];
print_address(bp->addr, name, sizeof(name));
printc(" %d. %s\n", i, name);
printc(" %d. %s", i, name);
if (bp->type == DEVICE_BPTYPE_WATCH) {
printc(" [watchpoint]\n");
} else {
printc("\n");
}
}
}

View File

@ -32,6 +32,7 @@ int cmd_hexout(char **arg);
int cmd_prog(char **arg);
int cmd_load(char **arg);
int cmd_setbreak(char **arg);
int cmd_setwatch(char **arg);
int cmd_delbreak(char **arg);
int cmd_break(char **arg);
int cmd_locka(char **arg);

View File

@ -341,7 +341,8 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
addr = strtoul(parts[1], NULL, 16);
if (enable) {
if (device_setbrk(device_default, -1, 1, addr) < 0) {
if (device_setbrk(device_default, -1, 1, addr,
DEVICE_BPTYPE_BREAK) < 0) {
printc_err("gdb: can't add breakpoint at "
"0x%04x\n", addr);
return gdb_send(data, "E00");
@ -349,7 +350,8 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
printc("Breakpoint set at 0x%04x\n", addr);
} else {
device_setbrk(device_default, -1, 0, addr);
device_setbrk(device_default, -1, 0, addr,
DEVICE_BPTYPE_BREAK);
printc("Breakpoint cleared at 0x%04x\n", addr);
}
@ -502,7 +504,7 @@ static int gdb_server(int port)
/* Put the hardware breakpoint setting into a known state. */
printc("Clearing all breakpoints...\n");
for (i = 0; i < device_default->max_breakpoints; i++)
device_setbrk(device_default, i, 0, 0);
device_setbrk(device_default, i, 0, 0, 0);
#ifdef DEBUG_GDB
printc("starting GDB reader loop...\n");