From a354116441b90004cf996cfb726d6f764dbc3f18 Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Wed, 25 Apr 2012 12:43:14 +1200 Subject: [PATCH] Watchpoint support (only implemented for tilib driver). --- drivers/device.c | 17 +++++++------ drivers/device.h | 13 +++++++--- drivers/fet.c | 6 +++-- drivers/gdbc.c | 3 +++ drivers/sim.c | 1 + drivers/tilib.c | 65 ++++++++++++++++++++++++++++++++++++------------ mspdebug.man | 8 +++++- ui/cmddb.c | 8 ++++++ ui/devcmd.c | 33 ++++++++++++++++++------ ui/devcmd.h | 1 + ui/gdb.c | 8 +++--- 11 files changed, 124 insertions(+), 39 deletions(-) diff --git a/drivers/device.c b/drivers/device.c index 6384adc..3fdb5ad 100644 --- a/drivers/device.c +++ b/drivers/device.c @@ -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; } } diff --git a/drivers/device.h b/drivers/device.h index 708b50a..416ef13 100644 --- a/drivers/device.h +++ b/drivers/device.h @@ -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; diff --git a/drivers/fet.c b/drivers/fet.c index d84b357..cdd1500 100644 --- a/drivers/fet.c +++ b/drivers/fet.c @@ -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; diff --git a/drivers/gdbc.c b/drivers/gdbc.c index efc9f57..266a2a2 100644 --- a/drivers/gdbc.c +++ b/drivers/gdbc.c @@ -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; diff --git a/drivers/sim.c b/drivers/sim.c index f07f738..8e66420 100644 --- a/drivers/sim.c +++ b/drivers/sim.c @@ -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; diff --git a/drivers/tilib.c b/drivers/tilib.c index ff57e5d..c5220ef 100644 --- a/drivers/tilib.c +++ b/drivers/tilib.c @@ -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(¶m, bp->addr); + break; + + case DEVICE_BPTYPE_WATCH: + load_watch(¶m, bp->addr); + break; + } } else { param.bpMode = BP_CLEAR; } diff --git a/mspdebug.man b/mspdebug.man index 71728db..53863b2 100644 --- a/mspdebug.man +++ b/mspdebug.man @@ -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 diff --git a/ui/cmddb.c b/ui/cmddb.c index 1220cba..c804ca5 100644 --- a/ui/cmddb.c +++ b/ui/cmddb.c @@ -59,6 +59,14 @@ const struct cmddb_record commands[] = { .help = "setbreak [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 [index]\n" +" Set a watchpoint. If no index is specified. the first available\n" " slot will be used.\n" }, { diff --git a/ui/devcmd.c b/ui/devcmd.c index 21ee25c..c776e93 100644 --- a/ui/devcmd.c +++ b/ui/devcmd.c @@ -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"); + } } } diff --git a/ui/devcmd.h b/ui/devcmd.h index fa20af9..f223eaa 100644 --- a/ui/devcmd.h +++ b/ui/devcmd.h @@ -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); diff --git a/ui/gdb.c b/ui/gdb.c index 6e92034..5942fd7 100644 --- a/ui/gdb.c +++ b/ui/gdb.c @@ -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");