diff --git a/Makefile b/Makefile index 1473a46..cfdc87f 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ install: mspdebug mspdebug.man mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \ util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \ cproc.o vector.o cproc_util.o expr.o fet_error.o binfile.o fet_db.o \ - usbutil.o titext.o srec.o + usbutil.o titext.o srec.o device.o $(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/bsl.c b/bsl.c index 0979e24..48aa182 100644 --- a/bsl.c +++ b/bsl.c @@ -222,18 +222,6 @@ static device_status_t bsl_poll(device_t dev_base) return DEVICE_STATUS_HALTED; } -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; -} - static int bsl_getregs(device_t dev_base, uint16_t *regs) { fprintf(stderr, "bsl: register fetch is not implemented\n"); @@ -327,14 +315,13 @@ device_t bsl_open(const char *device) return NULL; } - dev->base.max_breakpoints = 0; + memset(dev, 0, sizeof(*dev)); + 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.setbrk = bsl_setbrk; - dev->base.getbrk = bsl_getbrk; dev->base.ctl = bsl_ctl; dev->base.poll = bsl_poll; diff --git a/devcmd.c b/devcmd.c index b2dde40..5be30af 100644 --- a/devcmd.c +++ b/devcmd.c @@ -559,7 +559,7 @@ static int cmd_setbreak(cproc_t cp, char **arg) stab_t stab = cproc_stab(cp); char *addr_text = get_arg(arg); char *index_text = get_arg(arg); - int index; + int index = -1; int addr; if (!addr_text) { @@ -574,29 +574,22 @@ static int cmd_setbreak(cproc_t cp, char **arg) 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"); + if (index < 0 || index >= dev->max_breakpoints) { + fprintf(stderr, "setbreak: invalid breakpoint " + "slot: %d\n", index); return -1; } - - index = i; } - printf("Setting breakpoint %d\n", index); - dev->setbrk(dev, index, 1, addr); + index = device_setbrk(dev, index, 1, addr); + if (index < 0) { + fprintf(stderr, "setbreak: all breakpoint slots are " + "occupied\n"); + return -1; + } + printf("Set breakpoint %d\n", index); return 0; } @@ -609,15 +602,20 @@ static int cmd_delbreak(cproc_t cp, char **arg) if (index_text) { int index = atoi(index_text); + if (index < 0 || index >= dev->max_breakpoints) { + fprintf(stderr, "delbreak: invalid breakpoint " + "slot: %d\n", index); + return -1; + } + printf("Clearing breakpoint %d\n", index); - ret = dev->setbrk(dev, index, 0, 0); + device_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; + device_setbrk(dev, i, 0, 0); } return ret; @@ -631,15 +629,14 @@ static int cmd_break(cproc_t cp, char **arg) printf("%d breakpoints available:\n", dev->max_breakpoints); for (i = 0; i < dev->max_breakpoints; i++) { - int enabled; - uint16_t addr; + const struct device_breakpoint *bp = &dev->breakpoints[i]; - if (!dev->getbrk(dev, i, &enabled, &addr) && enabled) { + if (bp->flags & DEVICE_BP_ENABLED) { char name[128]; uint16_t offset; - printf(" %d. 0x%04x", i, addr); - if (!stab_nearest(stab, addr, name, + printf(" %d. 0x%04x", i, bp->addr); + if (!stab_nearest(stab, bp->addr, name, sizeof(name), &offset)) { printf(" (%s", name); if (offset) diff --git a/device.c b/device.c new file mode 100644 index 0000000..e0777f2 --- /dev/null +++ b/device.c @@ -0,0 +1,85 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009, 2010 Daniel Beer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "device.h" + +static int addbrk(device_t dev, uint16_t addr) +{ + int i; + int which = -1; + struct device_breakpoint *bp; + + for (i = 0; i < dev->max_breakpoints; i++) { + bp = &dev->breakpoints[i]; + + if (bp->flags & DEVICE_BP_ENABLED) { + if (bp->addr == addr) + return i; + } else if (which < 0) { + which = i; + } + } + + if (which < 0) + return -1; + + bp = &dev->breakpoints[which]; + bp->flags = DEVICE_BP_ENABLED | DEVICE_BP_DIRTY; + bp->addr = addr; + + return which; +} + +static void delbrk(device_t dev, uint16_t addr) +{ + int i; + + for (i = 0; i < dev->max_breakpoints; i++) { + struct device_breakpoint *bp = &dev->breakpoints[i]; + + if ((bp->flags & DEVICE_BP_ENABLED) && + bp->addr == addr) { + bp->flags = DEVICE_BP_DIRTY; + bp->addr = 0; + } + } +} + +int device_setbrk(device_t dev, int which, int enabled, uint16_t addr) +{ + if (which < 0) { + if (enabled) + return addbrk(dev, addr); + + delbrk(dev, addr); + } else { + struct device_breakpoint *bp = &dev->breakpoints[which]; + int new_flags = enabled ? DEVICE_BP_ENABLED : 0; + + if (!enabled) + addr = 0; + + if (bp->addr != addr || + (bp->flags & DEVICE_BP_ENABLED) != new_flags) { + bp->flags = new_flags | DEVICE_BP_DIRTY; + bp->addr = addr; + } + } + + return 0; +} diff --git a/device.h b/device.h index 4497504..54e6670 100644 --- a/device.h +++ b/device.h @@ -40,9 +40,24 @@ typedef enum { } device_status_t; #define DEVICE_NUM_REGS 16 +#define DEVICE_MAX_BREAKPOINTS 32 + +#define DEVICE_BP_ENABLED 0x01 +#define DEVICE_BP_DIRTY 0x02 + +struct device_breakpoint { + uint16_t addr; + int flags; +}; struct device { + /* Breakpoint table. This should not be modified directly. + * Instead, you should use the device_setbrk() helper function. This + * will set the appropriate flags and ensure that the breakpoint is + * reloaded before the next run. + */ int max_breakpoints; + struct device_breakpoint breakpoints[DEVICE_MAX_BREAKPOINTS]; /* Close the connection to the device and destroy the driver object */ void (*destroy)(device_t dev); @@ -57,10 +72,6 @@ struct device { int (*getregs)(device_t dev, uint16_t *regs); int (*setregs)(device_t dev, const uint16_t *regs); - /* Breakpoint control */ - 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); @@ -68,4 +79,14 @@ struct device { device_status_t (*poll)(device_t dev); }; +/* Set or clear a breakpoint. The index of the modified entry is + * returned, or -1 if no free entries were available. The modified + * entry is flagged so that it will be reloaded on the next run. + * + * If which is specified, a particular breakpoint slot is + * modified. Otherwise, if which < 0, breakpoint slots are selected + * automatically. + */ +int device_setbrk(device_t dev, int which, int enabled, uint16_t address); + #endif diff --git a/fet.c b/fet.c index f05cd6b..06e1bd6 100644 --- a/fet.c +++ b/fet.c @@ -33,12 +33,6 @@ #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; @@ -47,9 +41,6 @@ struct fet_device { int proto_flags; int version; - /* Breakpoint array */ - struct fet_bp bps[MAX_BREAKPOINTS]; - /* Device-specific information */ u_int16_t code_start; @@ -627,6 +618,33 @@ static device_status_t fet_poll(device_t dev_base) return DEVICE_STATUS_RUNNING; } +static int refresh_bps(struct fet_device *dev) +{ + int i; + int ret = 0; + + for (i = 0; i < dev->base.max_breakpoints; i++) { + struct device_breakpoint *bp = &dev->base.breakpoints[i]; + + if (bp->flags & DEVICE_BP_DIRTY) { + uint16_t addr = bp->addr; + + if (!(bp->flags & DEVICE_BP_ENABLED)) + addr = 0; + + if (xfer(dev, C_BREAKPOINT, NULL, 0, 2, i, addr) < 0) { + fprintf(stderr, "fet: failed to refresh " + "breakpoint #%d\n", i); + ret = -1; + } else { + bp->flags &= ~DEVICE_BP_DIRTY; + } + } + } + + return ret; +} + static int fet_ctl(device_t dev_base, device_ctl_t action) { struct fet_device *dev = (struct fet_device *)dev_base; @@ -640,6 +658,9 @@ static int fet_ctl(device_t dev_base, device_ctl_t action) break; case DEVICE_CTL_RUN: + if (refresh_bps(dev) < 0) + fprintf(stderr, "warning: fet: failed to refresh " + "breakpoints\n"); return do_run(dev, FET_RUN_BREAKPOINT); case DEVICE_CTL_HALT: @@ -783,43 +804,6 @@ static int fet_setregs(device_t dev_base, const uint16_t *regs) return 0; } -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 (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; -} - static int do_configure(struct fet_device *dev) { if (dev->proto_flags & FET_PROTO_SPYBIWIRE) { @@ -863,23 +847,19 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv, return NULL; } + memset(dev, 0, sizeof(*dev)); + dev->base.destroy = fet_destroy; dev->base.readmem = fet_readmem; dev->base.writemem = fet_writemem; dev->base.getregs = fet_getregs; dev->base.setregs = fet_setregs; - 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->fet_len = 0; - if (proto_flags & FET_PROTO_OLIMEX) { printf("Resetting Olimex command processor...\n"); transport->send(dev->transport, (const uint8_t *)"\x7e", 1); @@ -917,11 +897,11 @@ device_t fet_open(transport_t transport, int proto_flags, int vcc_mv, goto fail; } - printf("Resetting all breakpoints...\n"); + /* Make sure breakpoints get reset on the first run */ + if (dev->base.max_breakpoints > DEVICE_MAX_BREAKPOINTS) + dev->base.max_breakpoints = DEVICE_MAX_BREAKPOINTS; 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; + dev->base.breakpoints[i].flags = DEVICE_BP_DIRTY; return (device_t)dev; diff --git a/gdb.c b/gdb.c index 4f01a25..6a3c901 100644 --- a/gdb.c +++ b/gdb.c @@ -435,50 +435,6 @@ 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]; @@ -514,7 +470,7 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf) addr = strtoul(parts[1], NULL, 16); if (enable) { - if (add_breakpoint(data->device, addr) < 0) { + if (device_setbrk(data->device, -1, 1, addr) < 0) { fprintf(stderr, "gdb: can't add breakpoint at " "0x%04x\n", addr); return gdb_send(data, "E00"); @@ -522,12 +478,7 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf) printf("Breakpoint set at 0x%04x\n", addr); } 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"); - } - + device_setbrk(data->device, -1, 0, addr); printf("Breakpoint cleared at 0x%04x\n", addr); } @@ -695,7 +646,7 @@ static int gdb_server(device_t device, int port) /* Put the hardware breakpoint setting into a known state. */ printf("Clearing all breakpoints...\n"); for (i = 0; i < device->max_breakpoints; i++) - device->setbrk(device, i, 0, 0); + device_setbrk(device, i, 0, 0); gdb_reader_loop(&data); diff --git a/sim.c b/sim.c index 701abc5..55d4a73 100644 --- a/sim.c +++ b/sim.c @@ -28,13 +28,6 @@ #define MEM_SIZE 65536 #define MEM_IO_END 0x200 -#define NUM_BREAKPOINTS 8 - -struct sim_bp { - int enabled; - uint16_t addr; -}; - struct sim_device { struct device base; @@ -47,8 +40,6 @@ struct sim_device { int running; uint16_t current_insn; - - struct sim_bp bps[NUM_BREAKPOINTS]; }; #define MEM_GETB(dev, offset) ((dev)->memory[offset]) @@ -489,38 +480,6 @@ static int sim_setregs(device_t dev_base, const uint16_t *regs) return 0; } -static int sim_setbrk(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; - } - - 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; -} - static int sim_ctl(device_t dev_base, device_ctl_t op) { struct sim_device *dev = (struct sim_device *)dev_base; @@ -562,10 +521,11 @@ static device_status_t sim_poll(device_t dev_base) while (count > 0) { int i; - for (i = 0; i < NUM_BREAKPOINTS; i++) { - struct sim_bp *bp = &dev->bps[i]; + for (i = 0; i < dev->base.max_breakpoints; i++) { + struct device_breakpoint *bp = + &dev->base.breakpoints[i]; - if (bp->enabled && + if ((bp->flags & DEVICE_BP_ENABLED) && dev->regs[MSP430_REG_PC] == bp->addr) { dev->running = 0; return DEVICE_STATUS_HALTED; @@ -603,14 +563,14 @@ device_t sim_open(sim_fetch_func_t fetch_func, return NULL; } - dev->base.max_breakpoints = NUM_BREAKPOINTS; + memset(dev, 0, sizeof(*dev)); + + dev->base.max_breakpoints = DEVICE_MAX_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.setbrk = sim_setbrk; - dev->base.getbrk = sim_getbrk; dev->base.ctl = sim_ctl; dev->base.poll = sim_poll; @@ -624,8 +584,6 @@ device_t sim_open(sim_fetch_func_t fetch_func, dev->running = 0; dev->current_insn = 0; - memset(dev->bps, 0, sizeof(dev->bps)); - printf("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE); return (device_t)dev; }