Implemented support for multiple breakpoints.
This commit is contained in:
parent
2d76eb0184
commit
74a11c1ae0
12
bsl.c
12
bsl.c
|
@ -222,7 +222,13 @@ static device_status_t bsl_poll(device_t dev_base)
|
|||
return DEVICE_STATUS_HALTED;
|
||||
}
|
||||
|
||||
static int bsl_breakpoint(device_t dev_base, int enabled, uint16_t addr)
|
||||
static int bsl_setbrk(device_t dev_base, int n, int enabled, uint16_t addr)
|
||||
{
|
||||
fprintf(stderr, "bsl: breakpoints are not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bsl_getbrk(device_t dev_base, int n, int *enabled, uint16_t *addr)
|
||||
{
|
||||
fprintf(stderr, "bsl: breakpoints are not implemented\n");
|
||||
return -1;
|
||||
|
@ -321,12 +327,14 @@ device_t bsl_open(const char *device)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dev->base.max_breakpoints = 0;
|
||||
dev->base.destroy = bsl_destroy;
|
||||
dev->base.readmem = bsl_readmem;
|
||||
dev->base.writemem = bsl_writemem;
|
||||
dev->base.getregs = bsl_getregs;
|
||||
dev->base.setregs = bsl_setregs;
|
||||
dev->base.breakpoint = bsl_breakpoint;
|
||||
dev->base.setbrk = bsl_setbrk;
|
||||
dev->base.getbrk = bsl_getbrk;
|
||||
dev->base.ctl = bsl_ctl;
|
||||
dev->base.poll = bsl_poll;
|
||||
|
||||
|
|
150
devcmd.c
150
devcmd.c
|
@ -183,31 +183,12 @@ static int cmd_step(cproc_t cp, char **arg)
|
|||
static int cmd_run(cproc_t cp, char **arg)
|
||||
{
|
||||
device_t dev = cproc_device(cp);
|
||||
stab_t stab = cproc_stab(cp);
|
||||
char *bp_text = get_arg(arg);
|
||||
int bp_addr;
|
||||
device_status_t status;
|
||||
|
||||
if (bp_text) {
|
||||
if (expr_eval(stab, bp_text, &bp_addr) < 0) {
|
||||
fprintf(stderr, "run: can't parse breakpoint: %s\n",
|
||||
bp_text);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->breakpoint(dev, 1, bp_addr);
|
||||
} else {
|
||||
dev->breakpoint(dev, 0, 0);
|
||||
}
|
||||
|
||||
if (dev->ctl(dev, DEVICE_CTL_RUN) < 0)
|
||||
return -1;
|
||||
|
||||
if (bp_text)
|
||||
printf("Running to 0x%04x.", bp_addr);
|
||||
else
|
||||
printf("Running.");
|
||||
printf(" Press Ctrl+C to interrupt...\n");
|
||||
printf("Running. Press Ctrl+C to interrupt...\n");
|
||||
|
||||
do {
|
||||
status = dev->poll(dev);
|
||||
|
@ -572,7 +553,130 @@ static int cmd_prog(cproc_t cp, char **arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_setbreak(cproc_t cp, char **arg)
|
||||
{
|
||||
device_t dev = cproc_device(cp);
|
||||
stab_t stab = cproc_stab(cp);
|
||||
char *addr_text = get_arg(arg);
|
||||
char *index_text = get_arg(arg);
|
||||
int index;
|
||||
int addr;
|
||||
|
||||
if (!addr_text) {
|
||||
fprintf(stderr, "setbreak: address required\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (expr_eval(stab, addr_text, &addr) < 0) {
|
||||
fprintf(stderr, "setbreak: invalid address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index_text) {
|
||||
index = atoi(index_text);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
int enabled;
|
||||
|
||||
if (!dev->getbrk(dev, i, &enabled, NULL) &&
|
||||
!enabled)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= dev->max_breakpoints) {
|
||||
fprintf(stderr, "setbreak: all breakpoint slots are "
|
||||
"occupied\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
index = i;
|
||||
}
|
||||
|
||||
printf("Setting breakpoint %d\n", index);
|
||||
dev->setbrk(dev, index, 1, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_delbreak(cproc_t cp, char **arg)
|
||||
{
|
||||
device_t dev = cproc_device(cp);
|
||||
char *index_text = get_arg(arg);
|
||||
int ret = 0;
|
||||
|
||||
if (index_text) {
|
||||
int index = atoi(index_text);
|
||||
|
||||
printf("Clearing breakpoint %d\n", index);
|
||||
ret = dev->setbrk(dev, index, 0, 0);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
printf("Clearing all breakpoints...\n");
|
||||
for (i = 0; i < dev->max_breakpoints; i++)
|
||||
if (dev->setbrk(dev, i, 0, 0) < 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmd_break(cproc_t cp, char **arg)
|
||||
{
|
||||
device_t dev = cproc_device(cp);
|
||||
stab_t stab = cproc_stab(cp);
|
||||
int i;
|
||||
|
||||
printf("%d breakpoints available:\n", dev->max_breakpoints);
|
||||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
int enabled;
|
||||
uint16_t addr;
|
||||
|
||||
if (!dev->getbrk(dev, i, &enabled, &addr) && enabled) {
|
||||
char name[128];
|
||||
uint16_t offset;
|
||||
|
||||
printf(" %d. 0x%04x", i, addr);
|
||||
if (!stab_nearest(stab, addr, name,
|
||||
sizeof(name), &offset)) {
|
||||
printf(" (%s", name);
|
||||
if (offset)
|
||||
printf("+0x%x", offset);
|
||||
printf(")");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cproc_command commands[] = {
|
||||
{
|
||||
.name = "setbreak",
|
||||
.func = cmd_setbreak,
|
||||
.help =
|
||||
"setbreak <addr> [index]\n"
|
||||
" Set a breakpoint. If no index is specified, the first available\n"
|
||||
" slot will be used.\n"
|
||||
},
|
||||
{
|
||||
.name = "delbreak",
|
||||
.func = cmd_delbreak,
|
||||
.help =
|
||||
"delbreak [index]\n"
|
||||
" Delete a breakpoint. If no index is specified, then all active\n"
|
||||
" breakpoints are cleared.\n"
|
||||
},
|
||||
{
|
||||
.name = "break",
|
||||
.func = cmd_break,
|
||||
.help =
|
||||
"break\n"
|
||||
" List active breakpoints.\n"
|
||||
},
|
||||
{
|
||||
.name = "regs",
|
||||
.func = cmd_regs,
|
||||
|
@ -629,9 +733,9 @@ static const struct cproc_command commands[] = {
|
|||
.name = "run",
|
||||
.func = cmd_run,
|
||||
.help =
|
||||
"run [breakpoint]\n"
|
||||
" Run the CPU until either a specified breakpoint occurs or the\n"
|
||||
" command is interrupted.\n"
|
||||
"run\n"
|
||||
" Run the CPU to until a breakpoint is reached or the command is\n"
|
||||
" interrupted.\n"
|
||||
},
|
||||
{
|
||||
.name = "set",
|
||||
|
|
5
device.h
5
device.h
|
@ -42,6 +42,8 @@ typedef enum {
|
|||
#define DEVICE_NUM_REGS 16
|
||||
|
||||
struct device {
|
||||
int max_breakpoints;
|
||||
|
||||
/* Close the connection to the device and destroy the driver object */
|
||||
void (*destroy)(device_t dev);
|
||||
|
||||
|
@ -56,7 +58,8 @@ struct device {
|
|||
int (*setregs)(device_t dev, const uint16_t *regs);
|
||||
|
||||
/* Breakpoint control */
|
||||
int (*breakpoint)(device_t dev, int enabled, uint16_t addr);
|
||||
int (*setbrk)(device_t dev, int n, int enabled, uint16_t addr);
|
||||
int (*getbrk)(device_t dev, int n, int *enabled, uint16_t *addr);
|
||||
|
||||
/* CPU control */
|
||||
int (*ctl)(device_t dev, device_ctl_t op);
|
||||
|
|
80
fet.c
80
fet.c
|
@ -33,6 +33,12 @@
|
|||
#include "fet_db.h"
|
||||
|
||||
#define MAX_PARAMS 16
|
||||
#define MAX_BREAKPOINTS 16
|
||||
|
||||
struct fet_bp {
|
||||
int enabled;
|
||||
uint16_t addr;
|
||||
};
|
||||
|
||||
struct fet_device {
|
||||
struct device base;
|
||||
|
@ -40,7 +46,9 @@ struct fet_device {
|
|||
transport_t transport;
|
||||
int proto_flags;
|
||||
int version;
|
||||
int have_breakpoint;
|
||||
|
||||
/* Breakpoint array */
|
||||
struct fet_bp bps[MAX_BREAKPOINTS];
|
||||
|
||||
/* Device-specific information */
|
||||
u_int16_t code_start;
|
||||
|
@ -475,6 +483,13 @@ static int xfer(struct fet_device *dev,
|
|||
* MSP430 high-level control functions
|
||||
*/
|
||||
|
||||
static void show_dev_info(const char *name, const struct fet_device *dev)
|
||||
{
|
||||
printf("Device: %s\n", name);
|
||||
printf("Code memory starts at 0x%04x\n", dev->code_start);
|
||||
printf("Number of breakpoints: %d\n", dev->base.max_breakpoints);
|
||||
}
|
||||
|
||||
static int identify_old(struct fet_device *dev)
|
||||
{
|
||||
char idtext[64];
|
||||
|
@ -491,9 +506,9 @@ static int identify_old(struct fet_device *dev)
|
|||
idtext[32] = 0;
|
||||
|
||||
dev->code_start = LE_WORD(dev->fet_reply.data, 0x24);
|
||||
dev->base.max_breakpoints = LE_WORD(dev->fet_reply.data, 0x2a);
|
||||
|
||||
printf("Device: %s\n", idtext);
|
||||
printf("Code memory starts at 0x%04x\n", dev->code_start);
|
||||
show_dev_info(idtext, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -529,9 +544,9 @@ static int identify_new(struct fet_device *dev, const char *force_id)
|
|||
}
|
||||
|
||||
dev->code_start = LE_WORD(r->msg29_data, 0);
|
||||
dev->base.max_breakpoints = LE_WORD(r->msg29_data, 0x14);
|
||||
|
||||
printf("Device: %s\n", r->name);
|
||||
printf("Code memory starts at 0x%04x\n", dev->code_start);
|
||||
show_dev_info(r->name, dev);
|
||||
|
||||
if (xfer(dev, C_IDENT3, r->msg2b_data, r->msg2b_len, 0) < 0)
|
||||
fprintf(stderr, "fet: warning: message C_IDENT3 failed\n");
|
||||
|
@ -625,8 +640,7 @@ static int fet_ctl(device_t dev_base, device_ctl_t action)
|
|||
break;
|
||||
|
||||
case DEVICE_CTL_RUN:
|
||||
return do_run(dev, dev->have_breakpoint ?
|
||||
FET_RUN_BREAKPOINT : FET_RUN_FREE);
|
||||
return do_run(dev, FET_RUN_BREAKPOINT);
|
||||
|
||||
case DEVICE_CTL_HALT:
|
||||
if (xfer(dev, C_STATE, NULL, 0, 1, 1) < 0) {
|
||||
|
@ -769,21 +783,40 @@ static int fet_setregs(device_t dev_base, const uint16_t *regs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fet_breakpoint(device_t dev_base, int enabled, uint16_t addr)
|
||||
static int fet_setbrk(device_t dev_base, int n, int enabled, uint16_t addr)
|
||||
{
|
||||
struct fet_device *dev = (struct fet_device *)dev_base;
|
||||
|
||||
if (enabled) {
|
||||
dev->have_breakpoint = 1;
|
||||
|
||||
if (xfer(dev, C_BREAKPOINT, NULL, 0, 2, 0, addr) < 0) {
|
||||
fprintf(stderr, "fet: set breakpoint failed\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
dev->have_breakpoint = 0;
|
||||
if (n < 0 || n > dev_base->max_breakpoints) {
|
||||
fprintf(stderr, "fet: invalid breakpoint number: %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfer(dev, C_BREAKPOINT, NULL, 0, 2, n, enabled ? addr : 0) < 0) {
|
||||
fprintf(stderr, "fet: set breakpoint failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->bps[n].enabled = enabled;
|
||||
dev->bps[n].addr = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fet_getbrk(device_t dev_base, int n, int *enabled, uint16_t *addr)
|
||||
{
|
||||
struct fet_device *dev = (struct fet_device *)dev_base;
|
||||
|
||||
if (n < 0 || n > dev_base->max_breakpoints) {
|
||||
fprintf(stderr, "fet: invalid breakpoint number: %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
*enabled = dev->bps[n].enabled;
|
||||
if (addr)
|
||||
*addr = dev->bps[n].addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -823,6 +856,7 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv,
|
|||
const char *force_id)
|
||||
{
|
||||
struct fet_device *dev = malloc(sizeof(*dev));
|
||||
int i;
|
||||
|
||||
if (!dev) {
|
||||
perror("fet: failed to allocate memory");
|
||||
|
@ -834,13 +868,15 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv,
|
|||
dev->base.writemem = fet_writemem;
|
||||
dev->base.getregs = fet_getregs;
|
||||
dev->base.setregs = fet_setregs;
|
||||
dev->base.breakpoint = fet_breakpoint;
|
||||
dev->base.setbrk = fet_setbrk;
|
||||
dev->base.getbrk = fet_getbrk;
|
||||
dev->base.ctl = fet_ctl;
|
||||
dev->base.poll = fet_poll;
|
||||
|
||||
memset(dev->bps, 0, sizeof(dev->bps));
|
||||
|
||||
dev->transport = transport;
|
||||
dev->proto_flags = proto_flags;
|
||||
dev->have_breakpoint = 0;
|
||||
|
||||
dev->fet_len = 0;
|
||||
|
||||
|
@ -881,6 +917,12 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
printf("Resetting all breakpoints...\n");
|
||||
for (i = 0; i < dev->base.max_breakpoints; i++)
|
||||
xfer(dev, C_BREAKPOINT, NULL, 0, 2, i, 0);
|
||||
if (dev->base.max_breakpoints > MAX_BREAKPOINTS)
|
||||
dev->base.max_breakpoints = MAX_BREAKPOINTS;
|
||||
|
||||
return (device_t)dev;
|
||||
|
||||
fail:
|
||||
|
|
88
gdb.c
88
gdb.c
|
@ -49,12 +49,6 @@ struct gdb_data {
|
|||
int outlen;
|
||||
|
||||
device_t device;
|
||||
|
||||
/* The underlying device driver supports only one breakpoint at
|
||||
* a time. We keep track of whether or not it's in use and report
|
||||
* an error to gdb if more than one is set.
|
||||
*/
|
||||
int have_breakpoint;
|
||||
};
|
||||
|
||||
static void gdb_printf(struct gdb_data *data, const char *fmt, ...)
|
||||
|
@ -441,6 +435,50 @@ static int run(struct gdb_data *data, char *buf)
|
|||
return run_final_status(data);
|
||||
}
|
||||
|
||||
static int add_breakpoint(device_t dev, int addr)
|
||||
{
|
||||
int i;
|
||||
int avail = -1;
|
||||
|
||||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
int enabled;
|
||||
uint16_t ba;
|
||||
|
||||
if (!dev->getbrk(dev, i, &enabled, &ba)) {
|
||||
if (!enabled && avail < 0)
|
||||
avail = i;
|
||||
if (enabled && addr == ba) {
|
||||
fprintf(stderr, "warning: gdb: breakpoint at "
|
||||
"0x%04x already set", addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (avail < 0) {
|
||||
fprintf(stderr, "gdb: no breakpoint slots available\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dev->setbrk(dev, avail, 1, addr);
|
||||
}
|
||||
|
||||
static int remove_breakpoint(device_t dev, int addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
int enabled;
|
||||
uint16_t ba;
|
||||
|
||||
if (!dev->getbrk(dev, i, &enabled, &ba) && enabled &&
|
||||
ba == addr && dev->setbrk(dev, i, 0, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
|
||||
{
|
||||
char *parts[2];
|
||||
|
@ -475,23 +513,23 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
|
|||
/* Parse the breakpoint address */
|
||||
addr = strtoul(parts[1], NULL, 16);
|
||||
|
||||
/* Only one breakpoint at a time is allowed */
|
||||
if (enable && data->have_breakpoint) {
|
||||
fprintf(stderr, "gdb: only one breakpoint allowed "
|
||||
"at a time\n");
|
||||
return gdb_send(data, "E00");
|
||||
}
|
||||
if (enable) {
|
||||
if (add_breakpoint(data->device, addr) < 0) {
|
||||
fprintf(stderr, "gdb: can't add breakpoint at "
|
||||
"0x%04x\n", addr);
|
||||
return gdb_send(data, "E00");
|
||||
}
|
||||
|
||||
/* Set the breakpoint */
|
||||
if (data->device->breakpoint(data->device, enable, addr) < 0)
|
||||
return gdb_send(data, "E00");
|
||||
|
||||
data->have_breakpoint = enable;
|
||||
|
||||
if (enable)
|
||||
printf("Breakpoint set at 0x%04x\n", addr);
|
||||
else
|
||||
printf("Breakpoint cleared\n");
|
||||
} else {
|
||||
if (remove_breakpoint(data->device, addr) < 0) {
|
||||
fprintf(stderr, "gdb: can't remove breakpoint at "
|
||||
"0x%04x\n", addr);
|
||||
return gdb_send(data, "E00");
|
||||
}
|
||||
|
||||
printf("Breakpoint cleared at 0x%04x\n", addr);
|
||||
}
|
||||
|
||||
return gdb_send(data, "OK");
|
||||
}
|
||||
|
@ -605,6 +643,7 @@ static int gdb_server(device_t device, int port)
|
|||
socklen_t len;
|
||||
int arg;
|
||||
struct gdb_data data;
|
||||
int i;
|
||||
|
||||
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock < 0) {
|
||||
|
@ -654,13 +693,12 @@ static int gdb_server(device_t device, int port)
|
|||
data.device = device;
|
||||
|
||||
/* Put the hardware breakpoint setting into a known state. */
|
||||
data.have_breakpoint = 0;
|
||||
device->breakpoint(device, 0, 0);
|
||||
printf("Clearing all breakpoints...\n");
|
||||
for (i = 0; i < device->max_breakpoints; i++)
|
||||
device->setbrk(device, i, 0, 0);
|
||||
|
||||
gdb_reader_loop(&data);
|
||||
|
||||
device->breakpoint(device, 0, 0);
|
||||
|
||||
return data.error ? -1 : 0;
|
||||
}
|
||||
|
||||
|
|
25
mspdebug.man
25
mspdebug.man
|
@ -121,6 +121,10 @@ question.
|
|||
|
||||
See the section marked \fBADDRESS EXPRESSIONS\fR for more information on
|
||||
the syntax of expressions.
|
||||
.IP "\fBbreak\fR"
|
||||
Show a list of active breakpoints. Breakpoints can be added and removed
|
||||
with the \fBsetbreak\fR and \fBdelbreak\fR commands. Each breakpoint is
|
||||
numbered with an integer index starting at 0.
|
||||
.IP "\fBcgraph\fR \fIaddress\fR \fIlength\fR [\fIaddress\fR]"
|
||||
Construct the call graph of all functions contained or referenced in
|
||||
the given range of memory. If a particular function is specified, then
|
||||
|
@ -133,6 +137,9 @@ is considered a possible function start.
|
|||
|
||||
Callers and callee names are shown prefixed by a "*" where the
|
||||
transition is a tail-call type transition.
|
||||
.IP "\fBdelbreak\fR [\fIindex\fR]"
|
||||
Delete one or all breakpoints. If an index is given, the selected breakpoint
|
||||
is deleted. Otherwise, all breakpoints are cleared.
|
||||
.IP "\fBdis\fR \fIaddress\fR [\fIlength\fR]"
|
||||
Dissassemble a section of memory. Both arguments may be address
|
||||
expressions. If no length is specified, a section of the default
|
||||
|
@ -274,14 +281,11 @@ processed.
|
|||
Show the current value of all CPU registers in the device under test.
|
||||
.IP "\fBreset\fR"
|
||||
Reset (and halt) the CPU of the device under test.
|
||||
.IP "\fBrun\fR [\fIbreakpoint\fR]"
|
||||
Run the CPU, optionally specifying a breakpoint. The breakpoint can be
|
||||
specified as an address expression.
|
||||
|
||||
The interactive command prompt is blocked when the CPU is started and
|
||||
the prompt will not appear again until the CPU halts. The CPU will halt
|
||||
if it encounters the specified breakpoint, or if Ctrl\-C is pressed by
|
||||
the user.
|
||||
.IP "\fBrun\fR"
|
||||
Start running the CPU. The interactive command prompt is blocked when
|
||||
the CPU is started and the prompt will not appear again until the CPU
|
||||
halts. The CPU will halt if it encounters a breakpoint, or if Ctrl\-C
|
||||
is pressed by the user.
|
||||
|
||||
After the CPU halts, the current register values are shown as well as
|
||||
a disassembly of the first few instructions at the address selected
|
||||
|
@ -291,6 +295,11 @@ Alter the value of a register. Registers are specified as numbers from
|
|||
0 through 15. Any leading non-numeric characters are ignored (so a
|
||||
register may be specified as, for example, "R12"). The value argument
|
||||
is an address expression.
|
||||
.IP "\fBsetbreak\fR \fIaddress\fR [\fIindex\fR]"
|
||||
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 "\fBstep\fR [\fIcount\fR]"
|
||||
Step the CPU through one or more instructions. After stepping, the new
|
||||
register values are displayed, as well as a disassembly of the
|
||||
|
|
80
sim.c
80
sim.c
|
@ -26,7 +26,14 @@
|
|||
#include "sim.h"
|
||||
|
||||
#define MEM_SIZE 65536
|
||||
#define MEM_IO_END 0x200
|
||||
#define MEM_IO_END 0x200
|
||||
|
||||
#define NUM_BREAKPOINTS 8
|
||||
|
||||
struct sim_bp {
|
||||
int enabled;
|
||||
uint16_t addr;
|
||||
};
|
||||
|
||||
struct sim_device {
|
||||
struct device base;
|
||||
|
@ -35,13 +42,13 @@ struct sim_device {
|
|||
sim_store_func_t store_func;
|
||||
void *user_data;
|
||||
|
||||
uint8_t memory[MEM_SIZE];
|
||||
uint16_t regs[DEVICE_NUM_REGS];
|
||||
uint8_t memory[MEM_SIZE];
|
||||
uint16_t regs[DEVICE_NUM_REGS];
|
||||
|
||||
int running;
|
||||
uint16_t current_insn;
|
||||
int have_breakpoint;
|
||||
uint16_t breakpoint_addr;
|
||||
uint16_t current_insn;
|
||||
|
||||
struct sim_bp bps[NUM_BREAKPOINTS];
|
||||
};
|
||||
|
||||
#define MEM_GETB(dev, offset) ((dev)->memory[offset])
|
||||
|
@ -482,12 +489,35 @@ static int sim_setregs(device_t dev_base, const uint16_t *regs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sim_breakpoint(device_t dev_base, int enabled, uint16_t addr)
|
||||
static int sim_setbrk(device_t dev_base, int n, int enabled, uint16_t addr)
|
||||
{
|
||||
struct sim_device *dev = (struct sim_device *)dev_base;
|
||||
|
||||
dev->have_breakpoint = enabled;
|
||||
dev->breakpoint_addr = addr;
|
||||
if (n < 0 || n > NUM_BREAKPOINTS) {
|
||||
fprintf(stderr, "sim: invalid breakpoint number: %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->bps[n].enabled = enabled;
|
||||
dev->bps[n].addr = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_getbrk(device_t dev_base, int n, int *enabled, uint16_t *addr)
|
||||
{
|
||||
struct sim_device *dev = (struct sim_device *)dev_base;
|
||||
|
||||
if (n < 0 || n > NUM_BREAKPOINTS) {
|
||||
fprintf(stderr, "sim: invalid breakpoint number: %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
*enabled = dev->bps[n].enabled;
|
||||
if (addr)
|
||||
*addr = dev->bps[n].addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -525,19 +555,27 @@ static device_status_t sim_poll(device_t dev_base)
|
|||
struct sim_device *dev = (struct sim_device *)dev_base;
|
||||
int count = 1000000;
|
||||
|
||||
if (!dev->running)
|
||||
return DEVICE_STATUS_HALTED;
|
||||
|
||||
ctrlc_reset();
|
||||
while (dev->running && count > 0) {
|
||||
if (dev->have_breakpoint &&
|
||||
dev->regs[MSP430_REG_PC] == dev->breakpoint_addr) {
|
||||
printf("Breakpoint reached\n");
|
||||
dev->running = 0;
|
||||
break;
|
||||
while (count > 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BREAKPOINTS; i++) {
|
||||
struct sim_bp *bp = &dev->bps[i];
|
||||
|
||||
if (bp->enabled &&
|
||||
dev->regs[MSP430_REG_PC] == bp->addr) {
|
||||
dev->running = 0;
|
||||
return DEVICE_STATUS_HALTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) {
|
||||
printf("CPU disabled\n");
|
||||
dev->running = 0;
|
||||
break;
|
||||
return DEVICE_STATUS_HALTED;
|
||||
}
|
||||
|
||||
if (step_cpu(dev) < 0) {
|
||||
|
@ -551,7 +589,7 @@ static device_status_t sim_poll(device_t dev_base)
|
|||
count--;
|
||||
}
|
||||
|
||||
return dev->running ? DEVICE_STATUS_RUNNING : DEVICE_STATUS_HALTED;
|
||||
return DEVICE_STATUS_RUNNING;
|
||||
}
|
||||
|
||||
device_t sim_open(sim_fetch_func_t fetch_func,
|
||||
|
@ -565,12 +603,14 @@ device_t sim_open(sim_fetch_func_t fetch_func,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dev->base.max_breakpoints = NUM_BREAKPOINTS;
|
||||
dev->base.destroy = sim_destroy;
|
||||
dev->base.readmem = sim_readmem;
|
||||
dev->base.writemem = sim_writemem;
|
||||
dev->base.getregs = sim_getregs;
|
||||
dev->base.setregs = sim_setregs;
|
||||
dev->base.breakpoint = sim_breakpoint;
|
||||
dev->base.setbrk = sim_setbrk;
|
||||
dev->base.getbrk = sim_getbrk;
|
||||
dev->base.ctl = sim_ctl;
|
||||
dev->base.poll = sim_poll;
|
||||
|
||||
|
@ -583,8 +623,8 @@ device_t sim_open(sim_fetch_func_t fetch_func,
|
|||
|
||||
dev->running = 0;
|
||||
dev->current_insn = 0;
|
||||
dev->have_breakpoint = 0;
|
||||
dev->breakpoint_addr = 0;
|
||||
|
||||
memset(dev->bps, 0, sizeof(dev->bps));
|
||||
|
||||
printf("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE);
|
||||
return (device_t)dev;
|
||||
|
|
Loading…
Reference in New Issue