diff --git a/drivers/device.h b/drivers/device.h index 416ef13..4c170ba 100644 --- a/drivers/device.h +++ b/drivers/device.h @@ -53,7 +53,9 @@ typedef enum { typedef enum { DEVICE_BPTYPE_BREAK, - DEVICE_BPTYPE_WATCH + DEVICE_BPTYPE_WATCH, + DEVICE_BPTYPE_READ, + DEVICE_BPTYPE_WRITE } device_bptype_t; struct device_breakpoint { diff --git a/drivers/gdbc.c b/drivers/gdbc.c index 05af2e2..63cc04f 100644 --- a/drivers/gdbc.c +++ b/drivers/gdbc.c @@ -226,6 +226,14 @@ static int bp_send(struct gdb_data *gdb, int c, address_t addr, type_code = 1; break; + case DEVICE_BPTYPE_WRITE: + type_code = 2; + break; + + case DEVICE_BPTYPE_READ: + type_code = 3; + break; + case DEVICE_BPTYPE_WATCH: type_code = 4; break; diff --git a/drivers/sim.c b/drivers/sim.c index 0d5d5e4..a415d2d 100644 --- a/drivers/sim.c +++ b/drivers/sim.c @@ -53,7 +53,8 @@ struct sim_device { (dev)->memory[offset | 1] = (value) >> 8; \ } while (0); -static void watchpoint_check(struct sim_device *dev, uint16_t addr) +static void watchpoint_check(struct sim_device *dev, uint16_t addr, + int is_write) { int i; @@ -62,8 +63,10 @@ static void watchpoint_check(struct sim_device *dev, uint16_t addr) &dev->base.breakpoints[i]; if ((bp->flags & DEVICE_BP_ENABLED) && - bp->type == DEVICE_BPTYPE_WATCH && - bp->addr == addr) { + (bp->addr == addr) && + ((bp->type == DEVICE_BPTYPE_WATCH || + (bp->type == DEVICE_BPTYPE_READ && !is_write) || + (bp->type == DEVICE_BPTYPE_WRITE && is_write)))) { dev->watchpoint_hit = 1; return; } @@ -133,12 +136,12 @@ static int fetch_operand(struct sim_device *dev, break; } - watchpoint_check(dev, addr); - if (addr_ret) *addr_ret = addr; if (data_ret) { + watchpoint_check(dev, addr, 0); + *data_ret = MEM_GETW(dev, addr) & mask; if (addr < MEM_IO_END) { @@ -172,7 +175,7 @@ static int store_operand(struct sim_device *dev, return 0; } - watchpoint_check(dev, addr); + watchpoint_check(dev, addr, 1); if (is_byte) MEM_SETB(dev, addr, data); diff --git a/drivers/tilib.c b/drivers/tilib.c index c5220ef..59affbe 100644 --- a/drivers/tilib.c +++ b/drivers/tilib.c @@ -324,13 +324,14 @@ static void load_break(BpParameter_t *param, address_t addr) param->wExtCombine = 0; /* not used? */ } -static void load_watch(BpParameter_t *param, address_t addr) +static void load_complex(BpParameter_t *param, address_t addr, + BpAccess_t acc) { 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->bpAccess = acc; param->bpAction = BP_BRK; param->bpOperat = BP_EQUAL; param->lMask = 0xffffff; @@ -338,7 +339,7 @@ static void load_watch(BpParameter_t *param, address_t addr) param->bpRangeAction = 0; /* not used */ param->bpCondition = BP_NO_COND; param->lCondMdbVal = 0; - param->bpCondAccess = BP_NO_FETCH; + param->bpCondAccess = acc; param->lCondMask = 0; /* what's this? */ param->bpCondOperat = BP_EQUAL; param->wExtCombine = 0; /* not used? */ @@ -362,7 +363,17 @@ static int refresh_bps(struct tilib_device *dev) break; case DEVICE_BPTYPE_WATCH: - load_watch(¶m, bp->addr); + load_complex(¶m, bp->addr, BP_NO_FETCH); + break; + + case DEVICE_BPTYPE_READ: + load_complex(¶m, bp->addr, + BP_READ_DMA); + break; + + case DEVICE_BPTYPE_WRITE: + load_complex(¶m, bp->addr, + BP_WRITE_DMA); break; } } else { diff --git a/mspdebug.man b/mspdebug.man index 53863b2..b349082 100644 --- a/mspdebug.man +++ b/mspdebug.man @@ -408,6 +408,10 @@ 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 "\fBsetwatch_r\fR \fIaddress\fR [\fIindex\fR]" +Add a watchpoint which is triggered only on read access. +.IP "\fBsetwatch_w\fR \fIaddress\fR [\fIindex\fR]" +Add a watchpoint which is triggered only on write access. .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 c804ca5..512b080 100644 --- a/ui/cmddb.c +++ b/ui/cmddb.c @@ -68,6 +68,20 @@ const struct cmddb_record commands[] = { "setwatch [index]\n" " Set a watchpoint. If no index is specified. the first available\n" " slot will be used.\n" + }, + { + .name = "setwatch_r", + .func = cmd_setwatch_r, + .help = +"setwatch_r [index]\n" +" Set a read-only watchpoint.\n" + }, + { + .name = "setwatch_w", + .func = cmd_setwatch_w, + .help = +"setwatch_w [index]\n" +" Set a write-only watchpoint.\n" }, { .name = "delbreak", diff --git a/ui/devcmd.c b/ui/devcmd.c index c776e93..b96afd2 100644 --- a/ui/devcmd.c +++ b/ui/devcmd.c @@ -615,6 +615,16 @@ int cmd_setwatch(char **arg) return do_setbreak(DEVICE_BPTYPE_WATCH, arg); } +int cmd_setwatch_w(char **arg) +{ + return do_setbreak(DEVICE_BPTYPE_WRITE, arg); +} + +int cmd_setwatch_r(char **arg) +{ + return do_setbreak(DEVICE_BPTYPE_READ, arg); +} + int cmd_delbreak(char **arg) { char *index_text = get_arg(arg); @@ -661,10 +671,22 @@ int cmd_break(char **arg) print_address(bp->addr, name, sizeof(name)); printc(" %d. %s", i, name); - if (bp->type == DEVICE_BPTYPE_WATCH) { + switch (bp->type) { + case DEVICE_BPTYPE_WATCH: printc(" [watchpoint]\n"); - } else { + break; + + case DEVICE_BPTYPE_READ: + printc(" [read watchpoint]\n"); + break; + + case DEVICE_BPTYPE_WRITE: + printc(" [write watchpoint]\n"); + break; + + case DEVICE_BPTYPE_BREAK: printc("\n"); + break; } } } diff --git a/ui/devcmd.h b/ui/devcmd.h index f223eaa..35b28b9 100644 --- a/ui/devcmd.h +++ b/ui/devcmd.h @@ -33,6 +33,8 @@ int cmd_prog(char **arg); int cmd_load(char **arg); int cmd_setbreak(char **arg); int cmd_setwatch(char **arg); +int cmd_setwatch_r(char **arg); +int cmd_setwatch_w(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 262fb26..1e9520b 100644 --- a/ui/gdb.c +++ b/ui/gdb.c @@ -329,6 +329,14 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf) type = DEVICE_BPTYPE_BREAK; break; + case 2: + type = DEVICE_BPTYPE_WRITE; + break; + + case 3: + type = DEVICE_BPTYPE_READ; + break; + case 4: type = DEVICE_BPTYPE_WATCH; break;