Implemented support for multiple breakpoints.

This commit is contained in:
Daniel Beer 2010-07-02 14:22:52 +12:00
parent 2d76eb0184
commit 74a11c1ae0
7 changed files with 342 additions and 98 deletions

12
bsl.c
View File

@ -222,7 +222,13 @@ static device_status_t bsl_poll(device_t dev_base)
return DEVICE_STATUS_HALTED; 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"); fprintf(stderr, "bsl: breakpoints are not implemented\n");
return -1; return -1;
@ -321,12 +327,14 @@ device_t bsl_open(const char *device)
return NULL; return NULL;
} }
dev->base.max_breakpoints = 0;
dev->base.destroy = bsl_destroy; dev->base.destroy = bsl_destroy;
dev->base.readmem = bsl_readmem; dev->base.readmem = bsl_readmem;
dev->base.writemem = bsl_writemem; dev->base.writemem = bsl_writemem;
dev->base.getregs = bsl_getregs; dev->base.getregs = bsl_getregs;
dev->base.setregs = bsl_setregs; 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.ctl = bsl_ctl;
dev->base.poll = bsl_poll; dev->base.poll = bsl_poll;

150
devcmd.c
View File

@ -183,31 +183,12 @@ static int cmd_step(cproc_t cp, char **arg)
static int cmd_run(cproc_t cp, char **arg) static int cmd_run(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp); 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; 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) if (dev->ctl(dev, DEVICE_CTL_RUN) < 0)
return -1; return -1;
if (bp_text) printf("Running. Press Ctrl+C to interrupt...\n");
printf("Running to 0x%04x.", bp_addr);
else
printf("Running.");
printf(" Press Ctrl+C to interrupt...\n");
do { do {
status = dev->poll(dev); status = dev->poll(dev);
@ -572,7 +553,130 @@ static int cmd_prog(cproc_t cp, char **arg)
return 0; 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[] = { 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", .name = "regs",
.func = cmd_regs, .func = cmd_regs,
@ -629,9 +733,9 @@ static const struct cproc_command commands[] = {
.name = "run", .name = "run",
.func = cmd_run, .func = cmd_run,
.help = .help =
"run [breakpoint]\n" "run\n"
" Run the CPU until either a specified breakpoint occurs or the\n" " Run the CPU to until a breakpoint is reached or the command is\n"
" command is interrupted.\n" " interrupted.\n"
}, },
{ {
.name = "set", .name = "set",

View File

@ -42,6 +42,8 @@ typedef enum {
#define DEVICE_NUM_REGS 16 #define DEVICE_NUM_REGS 16
struct device { struct device {
int max_breakpoints;
/* Close the connection to the device and destroy the driver object */ /* Close the connection to the device and destroy the driver object */
void (*destroy)(device_t dev); void (*destroy)(device_t dev);
@ -56,7 +58,8 @@ struct device {
int (*setregs)(device_t dev, const uint16_t *regs); int (*setregs)(device_t dev, const uint16_t *regs);
/* Breakpoint control */ /* 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 */ /* CPU control */
int (*ctl)(device_t dev, device_ctl_t op); int (*ctl)(device_t dev, device_ctl_t op);

80
fet.c
View File

@ -33,6 +33,12 @@
#include "fet_db.h" #include "fet_db.h"
#define MAX_PARAMS 16 #define MAX_PARAMS 16
#define MAX_BREAKPOINTS 16
struct fet_bp {
int enabled;
uint16_t addr;
};
struct fet_device { struct fet_device {
struct device base; struct device base;
@ -40,7 +46,9 @@ struct fet_device {
transport_t transport; transport_t transport;
int proto_flags; int proto_flags;
int version; int version;
int have_breakpoint;
/* Breakpoint array */
struct fet_bp bps[MAX_BREAKPOINTS];
/* Device-specific information */ /* Device-specific information */
u_int16_t code_start; u_int16_t code_start;
@ -475,6 +483,13 @@ static int xfer(struct fet_device *dev,
* MSP430 high-level control functions * 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) static int identify_old(struct fet_device *dev)
{ {
char idtext[64]; char idtext[64];
@ -491,9 +506,9 @@ static int identify_old(struct fet_device *dev)
idtext[32] = 0; idtext[32] = 0;
dev->code_start = LE_WORD(dev->fet_reply.data, 0x24); 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); show_dev_info(idtext, dev);
printf("Code memory starts at 0x%04x\n", dev->code_start);
return 0; 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->code_start = LE_WORD(r->msg29_data, 0);
dev->base.max_breakpoints = LE_WORD(r->msg29_data, 0x14);
printf("Device: %s\n", r->name); show_dev_info(r->name, dev);
printf("Code memory starts at 0x%04x\n", dev->code_start);
if (xfer(dev, C_IDENT3, r->msg2b_data, r->msg2b_len, 0) < 0) if (xfer(dev, C_IDENT3, r->msg2b_data, r->msg2b_len, 0) < 0)
fprintf(stderr, "fet: warning: message C_IDENT3 failed\n"); 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; break;
case DEVICE_CTL_RUN: case DEVICE_CTL_RUN:
return do_run(dev, dev->have_breakpoint ? return do_run(dev, FET_RUN_BREAKPOINT);
FET_RUN_BREAKPOINT : FET_RUN_FREE);
case DEVICE_CTL_HALT: case DEVICE_CTL_HALT:
if (xfer(dev, C_STATE, NULL, 0, 1, 1) < 0) { 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; 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; struct fet_device *dev = (struct fet_device *)dev_base;
if (enabled) { if (n < 0 || n > dev_base->max_breakpoints) {
dev->have_breakpoint = 1; fprintf(stderr, "fet: invalid breakpoint number: %d\n", n);
return -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 (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; return 0;
} }
@ -823,6 +856,7 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv,
const char *force_id) const char *force_id)
{ {
struct fet_device *dev = malloc(sizeof(*dev)); struct fet_device *dev = malloc(sizeof(*dev));
int i;
if (!dev) { if (!dev) {
perror("fet: failed to allocate memory"); 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.writemem = fet_writemem;
dev->base.getregs = fet_getregs; dev->base.getregs = fet_getregs;
dev->base.setregs = fet_setregs; 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.ctl = fet_ctl;
dev->base.poll = fet_poll; dev->base.poll = fet_poll;
memset(dev->bps, 0, sizeof(dev->bps));
dev->transport = transport; dev->transport = transport;
dev->proto_flags = proto_flags; dev->proto_flags = proto_flags;
dev->have_breakpoint = 0;
dev->fet_len = 0; dev->fet_len = 0;
@ -881,6 +917,12 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv,
goto fail; 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; return (device_t)dev;
fail: fail:

88
gdb.c
View File

@ -49,12 +49,6 @@ struct gdb_data {
int outlen; int outlen;
device_t device; 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, ...) 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); 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) static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
{ {
char *parts[2]; char *parts[2];
@ -475,23 +513,23 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf)
/* Parse the breakpoint address */ /* Parse the breakpoint address */
addr = strtoul(parts[1], NULL, 16); addr = strtoul(parts[1], NULL, 16);
/* Only one breakpoint at a time is allowed */ if (enable) {
if (enable && data->have_breakpoint) { if (add_breakpoint(data->device, addr) < 0) {
fprintf(stderr, "gdb: only one breakpoint allowed " fprintf(stderr, "gdb: can't add breakpoint at "
"at a time\n"); "0x%04x\n", addr);
return gdb_send(data, "E00"); 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); printf("Breakpoint set at 0x%04x\n", addr);
else } else {
printf("Breakpoint cleared\n"); 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"); return gdb_send(data, "OK");
} }
@ -605,6 +643,7 @@ static int gdb_server(device_t device, int port)
socklen_t len; socklen_t len;
int arg; int arg;
struct gdb_data data; struct gdb_data data;
int i;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) { if (sock < 0) {
@ -654,13 +693,12 @@ static int gdb_server(device_t device, int port)
data.device = device; data.device = device;
/* Put the hardware breakpoint setting into a known state. */ /* Put the hardware breakpoint setting into a known state. */
data.have_breakpoint = 0; printf("Clearing all breakpoints...\n");
device->breakpoint(device, 0, 0); for (i = 0; i < device->max_breakpoints; i++)
device->setbrk(device, i, 0, 0);
gdb_reader_loop(&data); gdb_reader_loop(&data);
device->breakpoint(device, 0, 0);
return data.error ? -1 : 0; return data.error ? -1 : 0;
} }

View File

@ -121,6 +121,10 @@ question.
See the section marked \fBADDRESS EXPRESSIONS\fR for more information on See the section marked \fBADDRESS EXPRESSIONS\fR for more information on
the syntax of expressions. 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]" .IP "\fBcgraph\fR \fIaddress\fR \fIlength\fR [\fIaddress\fR]"
Construct the call graph of all functions contained or referenced in Construct the call graph of all functions contained or referenced in
the given range of memory. If a particular function is specified, then 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 Callers and callee names are shown prefixed by a "*" where the
transition is a tail-call type transition. 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]" .IP "\fBdis\fR \fIaddress\fR [\fIlength\fR]"
Dissassemble a section of memory. Both arguments may be address Dissassemble a section of memory. Both arguments may be address
expressions. If no length is specified, a section of the default 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. Show the current value of all CPU registers in the device under test.
.IP "\fBreset\fR" .IP "\fBreset\fR"
Reset (and halt) the CPU of the device under test. Reset (and halt) the CPU of the device under test.
.IP "\fBrun\fR [\fIbreakpoint\fR]" .IP "\fBrun\fR"
Run the CPU, optionally specifying a breakpoint. The breakpoint can be Start running the CPU. The interactive command prompt is blocked when
specified as an address expression. 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
The interactive command prompt is blocked when the CPU is started and is pressed by the user.
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.
After the CPU halts, the current register values are shown as well as After the CPU halts, the current register values are shown as well as
a disassembly of the first few instructions at the address selected 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 0 through 15. Any leading non-numeric characters are ignored (so a
register may be specified as, for example, "R12"). The value argument register may be specified as, for example, "R12"). The value argument
is an address expression. 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]" .IP "\fBstep\fR [\fIcount\fR]"
Step the CPU through one or more instructions. After stepping, the new Step the CPU through one or more instructions. After stepping, the new
register values are displayed, as well as a disassembly of the register values are displayed, as well as a disassembly of the

80
sim.c
View File

@ -26,7 +26,14 @@
#include "sim.h" #include "sim.h"
#define MEM_SIZE 65536 #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 sim_device {
struct device base; struct device base;
@ -35,13 +42,13 @@ struct sim_device {
sim_store_func_t store_func; sim_store_func_t store_func;
void *user_data; void *user_data;
uint8_t memory[MEM_SIZE]; uint8_t memory[MEM_SIZE];
uint16_t regs[DEVICE_NUM_REGS]; uint16_t regs[DEVICE_NUM_REGS];
int running; int running;
uint16_t current_insn; uint16_t current_insn;
int have_breakpoint;
uint16_t breakpoint_addr; struct sim_bp bps[NUM_BREAKPOINTS];
}; };
#define MEM_GETB(dev, offset) ((dev)->memory[offset]) #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; 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; struct sim_device *dev = (struct sim_device *)dev_base;
dev->have_breakpoint = enabled; if (n < 0 || n > NUM_BREAKPOINTS) {
dev->breakpoint_addr = addr; 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; 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; struct sim_device *dev = (struct sim_device *)dev_base;
int count = 1000000; int count = 1000000;
if (!dev->running)
return DEVICE_STATUS_HALTED;
ctrlc_reset(); ctrlc_reset();
while (dev->running && count > 0) { while (count > 0) {
if (dev->have_breakpoint && int i;
dev->regs[MSP430_REG_PC] == dev->breakpoint_addr) {
printf("Breakpoint reached\n"); for (i = 0; i < NUM_BREAKPOINTS; i++) {
dev->running = 0; struct sim_bp *bp = &dev->bps[i];
break;
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) { if (dev->regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) {
printf("CPU disabled\n"); printf("CPU disabled\n");
dev->running = 0; dev->running = 0;
break; return DEVICE_STATUS_HALTED;
} }
if (step_cpu(dev) < 0) { if (step_cpu(dev) < 0) {
@ -551,7 +589,7 @@ static device_status_t sim_poll(device_t dev_base)
count--; count--;
} }
return dev->running ? DEVICE_STATUS_RUNNING : DEVICE_STATUS_HALTED; return DEVICE_STATUS_RUNNING;
} }
device_t sim_open(sim_fetch_func_t fetch_func, 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; return NULL;
} }
dev->base.max_breakpoints = NUM_BREAKPOINTS;
dev->base.destroy = sim_destroy; dev->base.destroy = sim_destroy;
dev->base.readmem = sim_readmem; dev->base.readmem = sim_readmem;
dev->base.writemem = sim_writemem; dev->base.writemem = sim_writemem;
dev->base.getregs = sim_getregs; dev->base.getregs = sim_getregs;
dev->base.setregs = sim_setregs; 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.ctl = sim_ctl;
dev->base.poll = sim_poll; dev->base.poll = sim_poll;
@ -583,8 +623,8 @@ device_t sim_open(sim_fetch_func_t fetch_func,
dev->running = 0; dev->running = 0;
dev->current_insn = 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); printf("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE);
return (device_t)dev; return (device_t)dev;