Add support for read and write watchpoints.

This commit is contained in:
Daniel Beer 2012-04-25 14:10:26 +12:00
parent 7413531715
commit 09ca20c91c
9 changed files with 87 additions and 13 deletions

View File

@ -53,7 +53,9 @@ typedef enum {
typedef enum { typedef enum {
DEVICE_BPTYPE_BREAK, DEVICE_BPTYPE_BREAK,
DEVICE_BPTYPE_WATCH DEVICE_BPTYPE_WATCH,
DEVICE_BPTYPE_READ,
DEVICE_BPTYPE_WRITE
} device_bptype_t; } device_bptype_t;
struct device_breakpoint { struct device_breakpoint {

View File

@ -226,6 +226,14 @@ static int bp_send(struct gdb_data *gdb, int c, address_t addr,
type_code = 1; type_code = 1;
break; break;
case DEVICE_BPTYPE_WRITE:
type_code = 2;
break;
case DEVICE_BPTYPE_READ:
type_code = 3;
break;
case DEVICE_BPTYPE_WATCH: case DEVICE_BPTYPE_WATCH:
type_code = 4; type_code = 4;
break; break;

View File

@ -53,7 +53,8 @@ struct sim_device {
(dev)->memory[offset | 1] = (value) >> 8; \ (dev)->memory[offset | 1] = (value) >> 8; \
} while (0); } 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; int i;
@ -62,8 +63,10 @@ static void watchpoint_check(struct sim_device *dev, uint16_t addr)
&dev->base.breakpoints[i]; &dev->base.breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) && 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; dev->watchpoint_hit = 1;
return; return;
} }
@ -133,12 +136,12 @@ static int fetch_operand(struct sim_device *dev,
break; break;
} }
watchpoint_check(dev, addr);
if (addr_ret) if (addr_ret)
*addr_ret = addr; *addr_ret = addr;
if (data_ret) { if (data_ret) {
watchpoint_check(dev, addr, 0);
*data_ret = MEM_GETW(dev, addr) & mask; *data_ret = MEM_GETW(dev, addr) & mask;
if (addr < MEM_IO_END) { if (addr < MEM_IO_END) {
@ -172,7 +175,7 @@ static int store_operand(struct sim_device *dev,
return 0; return 0;
} }
watchpoint_check(dev, addr); watchpoint_check(dev, addr, 1);
if (is_byte) if (is_byte)
MEM_SETB(dev, addr, data); MEM_SETB(dev, addr, data);

View File

@ -324,13 +324,14 @@ static void load_break(BpParameter_t *param, address_t addr)
param->wExtCombine = 0; /* not used? */ 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->bpMode = BP_COMPLEX;
param->lAddrVal = addr; param->lAddrVal = addr;
param->bpType = BP_MAB; param->bpType = BP_MAB;
param->lReg = 0; /* not used (only for register-write) */ param->lReg = 0; /* not used (only for register-write) */
param->bpAccess = BP_NO_FETCH; param->bpAccess = acc;
param->bpAction = BP_BRK; param->bpAction = BP_BRK;
param->bpOperat = BP_EQUAL; param->bpOperat = BP_EQUAL;
param->lMask = 0xffffff; param->lMask = 0xffffff;
@ -338,7 +339,7 @@ static void load_watch(BpParameter_t *param, address_t addr)
param->bpRangeAction = 0; /* not used */ param->bpRangeAction = 0; /* not used */
param->bpCondition = BP_NO_COND; param->bpCondition = BP_NO_COND;
param->lCondMdbVal = 0; param->lCondMdbVal = 0;
param->bpCondAccess = BP_NO_FETCH; param->bpCondAccess = acc;
param->lCondMask = 0; /* what's this? */ param->lCondMask = 0; /* what's this? */
param->bpCondOperat = BP_EQUAL; param->bpCondOperat = BP_EQUAL;
param->wExtCombine = 0; /* not used? */ param->wExtCombine = 0; /* not used? */
@ -362,7 +363,17 @@ static int refresh_bps(struct tilib_device *dev)
break; break;
case DEVICE_BPTYPE_WATCH: case DEVICE_BPTYPE_WATCH:
load_watch(&param, bp->addr); load_complex(&param, bp->addr, BP_NO_FETCH);
break;
case DEVICE_BPTYPE_READ:
load_complex(&param, bp->addr,
BP_READ_DMA);
break;
case DEVICE_BPTYPE_WRITE:
load_complex(&param, bp->addr,
BP_WRITE_DMA);
break; break;
} }
} else { } else {

View File

@ -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 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 of breakpoint and can be inspected or removed using the \fBbreak\fR and
\fBdelbreak\fR commands. Note that not all drivers support watchpoints. \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]" .IP "\fBsimio add\fR \fIclass\fR \fIname\fR [\fIargs ...\fR]"
Add a new peripheral to the IO simulator. The \fIclass\fR parameter may be 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 any of the peripheral types named in the output of the \fBsimio classes\fR

View File

@ -68,6 +68,20 @@ const struct cmddb_record commands[] = {
"setwatch <addr> [index]\n" "setwatch <addr> [index]\n"
" Set a watchpoint. If no index is specified. the first available\n" " Set a watchpoint. If no index is specified. the first available\n"
" slot will be used.\n" " slot will be used.\n"
},
{
.name = "setwatch_r",
.func = cmd_setwatch_r,
.help =
"setwatch_r <addr> [index]\n"
" Set a read-only watchpoint.\n"
},
{
.name = "setwatch_w",
.func = cmd_setwatch_w,
.help =
"setwatch_w <addr> [index]\n"
" Set a write-only watchpoint.\n"
}, },
{ {
.name = "delbreak", .name = "delbreak",

View File

@ -615,6 +615,16 @@ int cmd_setwatch(char **arg)
return do_setbreak(DEVICE_BPTYPE_WATCH, 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) int cmd_delbreak(char **arg)
{ {
char *index_text = get_arg(arg); char *index_text = get_arg(arg);
@ -661,10 +671,22 @@ int cmd_break(char **arg)
print_address(bp->addr, name, sizeof(name)); print_address(bp->addr, name, sizeof(name));
printc(" %d. %s", i, name); printc(" %d. %s", i, name);
if (bp->type == DEVICE_BPTYPE_WATCH) { switch (bp->type) {
case DEVICE_BPTYPE_WATCH:
printc(" [watchpoint]\n"); 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"); printc("\n");
break;
} }
} }
} }

View File

@ -33,6 +33,8 @@ int cmd_prog(char **arg);
int cmd_load(char **arg); int cmd_load(char **arg);
int cmd_setbreak(char **arg); int cmd_setbreak(char **arg);
int cmd_setwatch(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_delbreak(char **arg);
int cmd_break(char **arg); int cmd_break(char **arg);
int cmd_locka(char **arg); int cmd_locka(char **arg);

View File

@ -329,6 +329,14 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
type = DEVICE_BPTYPE_BREAK; type = DEVICE_BPTYPE_BREAK;
break; break;
case 2:
type = DEVICE_BPTYPE_WRITE;
break;
case 3:
type = DEVICE_BPTYPE_READ;
break;
case 4: case 4:
type = DEVICE_BPTYPE_WATCH; type = DEVICE_BPTYPE_WATCH;
break; break;