Add support for read and write watchpoints.
This commit is contained in:
parent
7413531715
commit
09ca20c91c
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(¶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;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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
|
||||||
|
|
14
ui/cmddb.c
14
ui/cmddb.c
|
@ -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",
|
||||||
|
|
26
ui/devcmd.c
26
ui/devcmd.c
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
8
ui/gdb.c
8
ui/gdb.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue