diff --git a/binfile.h b/binfile.h index 5037a70..966120f 100644 --- a/binfile.h +++ b/binfile.h @@ -23,18 +23,19 @@ #include /* Callback for binary image data */ -typedef int (*imgfunc_t)(u_int16_t addr, const u_int8_t *data, int len); +typedef int (*imgfunc_t)(void *user_data, + u_int16_t addr, const u_int8_t *data, int len); /* Callback for symbol data */ typedef int (*symfunc_t)(const char *name, int value); /* Intel HEX file support */ int ihex_check(FILE *in); -int ihex_extract(FILE *in, imgfunc_t cb); +int ihex_extract(FILE *in, imgfunc_t cb, void *user_data); /* ELF32 file support */ int elf32_check(FILE *in); -int elf32_extract(FILE *in, imgfunc_t cb); +int elf32_extract(FILE *in, imgfunc_t cb, void *user_data); int elf32_syms(FILE *in, symfunc_t cb); /* *.map file support */ diff --git a/bsl.c b/bsl.c index c02f170..47fe62c 100644 --- a/bsl.c +++ b/bsl.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -25,20 +26,26 @@ #include #include -#include "device.h" +#include "bsl.h" #include "util.h" -static int serial_fd; +struct bsl_device { + struct device base; + + int serial_fd; + u_int8_t reply_buf[256]; + int reply_len; +}; #define DATA_HDR 0x80 #define DATA_ACK 0x90 #define DATA_NAK 0xA0 -static int bsl_ack(void) +static int bsl_ack(struct bsl_device *dev) { u_int8_t reply; - if (read_with_timeout(serial_fd, &reply, 1) < 0) { + if (read_with_timeout(dev->serial_fd, &reply, 1) < 0) { fprintf(stderr, "bsl: failed to receive reply\n"); return -1; } @@ -56,25 +63,26 @@ static int bsl_ack(void) return 0; } -static int bsl_sync(void) +static int bsl_sync(struct bsl_device *dev) { static const u_int8_t c = DATA_HDR; int tries = 2; - if (tcflush(serial_fd, TCIFLUSH) < 0) { + if (tcflush(dev->serial_fd, TCIFLUSH) < 0) { perror("bsl: tcflush"); return -1; } while (tries--) - if (!(write_all(serial_fd, &c, 1) || bsl_ack())) + if (!(write_all(dev->serial_fd, &c, 1) || bsl_ack(dev))) return 0; fprintf(stderr, "bsl: sync failed\n"); return -1; } -static int send_command(int code, u_int16_t addr, +static int send_command(struct bsl_device *dev, + int code, u_int16_t addr, const u_int8_t *data, int len) { u_int8_t pktbuf[256]; @@ -108,23 +116,19 @@ static int send_command(int code, u_int16_t addr, pktbuf[pktlen + 4] = cklow; pktbuf[pktlen + 5] = ckhigh; - return write_all(serial_fd, pktbuf, pktlen + 6); + return write_all(dev->serial_fd, pktbuf, pktlen + 6); } -static u_int8_t reply_buf[256]; -static int reply_len; - -static int verify_checksum(void) +static int verify_checksum(struct bsl_device *dev) { u_int8_t cklow = 0xff; u_int8_t ckhigh = 0xff; int i; - - for (i = 0; i < reply_len; i += 2) - cklow ^= reply_buf[i]; - for (i = 1; i < reply_len; i += 2) - ckhigh ^= reply_buf[i]; + for (i = 0; i < dev->reply_len; i += 2) + cklow ^= dev->reply_buf[i]; + for (i = 1; i < dev->reply_len; i += 2) + ckhigh ^= dev->reply_buf[i]; if (cklow || ckhigh) { fprintf(stderr, "bsl: checksum invalid (%02x %02x)\n", @@ -135,47 +139,50 @@ static int verify_checksum(void) return 0; } -static int fetch_reply(void) +static int fetch_reply(struct bsl_device *dev) { - reply_len = 0; + dev->reply_len = 0; for (;;) { - int r = read_with_timeout(serial_fd, reply_buf + reply_len, - sizeof(reply_buf) - reply_len); + int r = read_with_timeout(dev->serial_fd, + dev->reply_buf + dev->reply_len, + sizeof(dev->reply_buf) - + dev->reply_len); if (r < 0) return -1; - reply_len += r; + dev->reply_len += r; - if (reply_buf[0] == DATA_ACK) { + if (dev->reply_buf[0] == DATA_ACK) { return 0; - } else if (reply_buf[0] == DATA_HDR) { - if (reply_len >= 6 && - reply_len == reply_buf[2] + 6) - return verify_checksum(); - } else if (reply_buf[0] == DATA_NAK) { + } else if (dev->reply_buf[0] == DATA_HDR) { + if (dev->reply_len >= 6 && + dev->reply_len == dev->reply_buf[2] + 6) + return verify_checksum(dev); + } else if (dev->reply_buf[0] == DATA_NAK) { fprintf(stderr, "bsl: received NAK\n"); return -1; } else { fprintf(stderr, "bsl: unknown reply type: %02x\n", - reply_buf[0]); + dev->reply_buf[0]); return -1; } - if (reply_len >= sizeof(reply_buf)) { + if (dev->reply_len >= sizeof(dev->reply_buf)) { fprintf(stderr, "bsl: reply buffer overflow\n"); return -1; } } } -static int bsl_xfer(int command_code, u_int16_t addr, const u_int8_t *txdata, +static int bsl_xfer(struct bsl_device *dev, + int command_code, u_int16_t addr, const u_int8_t *txdata, int len) { - if (bsl_sync() < 0 || - send_command(command_code, addr, txdata, len) < 0 || - fetch_reply() < 0) { + if (bsl_sync(dev) < 0 || + send_command(dev, command_code, addr, txdata, len) < 0 || + fetch_reply(dev) < 0) { fprintf(stderr, "bsl: failed on command 0x%02x " "(addr = 0x%04x, len = 0x%04x)\n", command_code, addr, len); @@ -190,64 +197,71 @@ static int bsl_xfer(int command_code, u_int16_t addr, const u_int8_t *txdata, #define CMD_RX_DATA 0x3a #define CMD_RESET 0x3b -static void bsl_close(void) +static void bsl_destroy(device_t dev_base) { - bsl_xfer(CMD_RESET, 0, NULL, 0); - close(serial_fd); + struct bsl_device *dev = (struct bsl_device *)dev_base; + + bsl_xfer(dev, CMD_RESET, 0, NULL, 0); + close(dev->serial_fd); + free(dev); } -static int bsl_control(device_ctl_t type) +static int bsl_ctl(device_t dev_base, device_ctl_t type) { fprintf(stderr, "bsl: CPU control is not implemented\n"); return -1; } -static device_status_t bsl_wait(int blocking) +static device_status_t bsl_poll(device_t dev_base) { return DEVICE_STATUS_HALTED; } -static int bsl_breakpoint(u_int16_t addr) +static int bsl_breakpoint(device_t dev_base, int enabled, u_int16_t addr) { fprintf(stderr, "bsl: breakpoints are not implemented\n"); return -1; } -static int bsl_getregs(u_int16_t *regs) +static int bsl_getregs(device_t dev_base, u_int16_t *regs) { fprintf(stderr, "bsl: register fetch is not implemented\n"); return -1; } -static int bsl_setregs(const u_int16_t *regs) +static int bsl_setregs(device_t dev_base, const u_int16_t *regs) { fprintf(stderr, "bsl: register store is not implemented\n"); return -1; } -static int bsl_writemem(u_int16_t addr, const u_int8_t *mem, int len) +static int bsl_writemem(device_t dev_base, + u_int16_t addr, const u_int8_t *mem, int len) { fprintf(stderr, "bsl: memory write is not implemented\n"); return -1; } -static int bsl_readmem(u_int16_t addr, u_int8_t *mem, int len) +static int bsl_readmem(device_t dev_base, + u_int16_t addr, u_int8_t *mem, int len) { + struct bsl_device *dev = (struct bsl_device *)dev_base; + while (len) { int count = len; if (count > 128) count = 128; - if (bsl_xfer(CMD_TX_DATA, addr, NULL, count) < 0) { + if (bsl_xfer(dev, CMD_TX_DATA, addr, NULL, count) < 0) { fprintf(stderr, "bsl: failed to read memory\n"); return -1; } - if (count > reply_buf[2]) - count = reply_buf[2]; + if (count > dev->reply_buf[2]) + count = dev->reply_buf[2]; - memcpy(mem, reply_buf + 4, count); + memcpy(mem, dev->reply_buf + 4, count); mem += count; len -= count; } @@ -255,27 +269,15 @@ static int bsl_readmem(u_int16_t addr, u_int8_t *mem, int len) return 0; } -const static struct device bsl_device = { - .close = bsl_close, - .control = bsl_control, - .wait = bsl_wait, - .breakpoint = bsl_breakpoint, - .getregs = bsl_getregs, - .setregs = bsl_setregs, - .writemem = bsl_writemem, - .readmem = bsl_readmem -}; - -#include - -static int enter_via_fet(void) +static int enter_via_fet(struct bsl_device *dev) { u_int8_t buf[16]; u_int8_t *data = buf; int len = 8; /* Enter bootloader command */ - if (write_all(serial_fd, (u_int8_t *)"\x7e\x24\x01\x9d\x5a\x7e", 6)) { + if (write_all(dev->serial_fd, + (u_int8_t *)"\x7e\x24\x01\x9d\x5a\x7e", 6)) { fprintf(stderr, "bsl: couldn't write bootloader transition " "command\n"); return -1; @@ -283,7 +285,7 @@ static int enter_via_fet(void) /* Wait for reply */ while (len) { - int r = read_with_timeout(serial_fd, data, len); + int r = read_with_timeout(dev->serial_fd, data, len); if (r < 0) { fprintf(stderr, "bsl: couldn't read bootloader " @@ -305,40 +307,62 @@ static int enter_via_fet(void) return 0; } -const struct device *bsl_open(const char *device) +device_t bsl_open(const char *device) { + struct bsl_device *dev = malloc(sizeof(*dev)); char idtext[64]; u_int16_t id; - serial_fd = open_serial(device, B460800); - if (serial_fd < 0) { - fprintf(stderr, "bsl: can't open %s: %s\n", - device, strerror(errno)); + if (!dev) { + perror("bsl: can't allocate memory"); return NULL; } - if (enter_via_fet() < 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.ctl = bsl_ctl; + dev->base.poll = bsl_poll; + + dev->serial_fd = open_serial(device, B460800); + if (dev->serial_fd < 0) { + fprintf(stderr, "bsl: can't open %s: %s\n", + device, strerror(errno)); + free(dev); + return NULL; + } + + if (enter_via_fet(dev) < 0) return NULL; usleep(500000); /* Show chip info */ - if (bsl_xfer(CMD_TX_DATA, 0xff0, NULL, 0x10) < 0) { + if (bsl_xfer(dev, CMD_TX_DATA, 0xff0, NULL, 0x10) < 0) { fprintf(stderr, "bsl: failed to read chip info\n"); - return NULL; + goto fail; } - if (reply_len < 0x16) { + if (dev->reply_len < 0x16) { fprintf(stderr, "bsl: missing chip info\n"); - return NULL; + goto fail; } - id = (reply_buf[4] << 8) | reply_buf[5]; - if (find_device_id(id, idtext, sizeof(idtext)) < 0) + id = (dev->reply_buf[4] << 8) | dev->reply_buf[5]; + if (device_id_text(id, idtext, sizeof(idtext)) < 0) printf("Unknown device ID: 0x%04x\n", id); else printf("Device: %s\n", idtext); - printf("BSL version is %x.%02x\n", reply_buf[14], reply_buf[15]); - return &bsl_device; + printf("BSL version is %x.%02x\n", dev->reply_buf[14], + dev->reply_buf[15]); + return (device_t)dev; + + fail: + close(dev->serial_fd); + free(dev); + return NULL; } diff --git a/bsl.h b/bsl.h new file mode 100644 index 0000000..58f9a89 --- /dev/null +++ b/bsl.h @@ -0,0 +1,27 @@ +/* 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 + */ + +#ifndef BSL_H_ +#define BSL_H_ + +#include "device.h" + +/* MSP430 FET Bootloader implementation. */ +device_t bsl_open(const char *devpath); + +#endif diff --git a/cproc.c b/cproc.c index f74bf43..f4ef6a6 100644 --- a/cproc.c +++ b/cproc.c @@ -40,6 +40,8 @@ struct cproc { int modify_flags; int in_reader_loop; + + device_t device; }; static struct cproc_option *find_option(cproc_t cp, const char *name) @@ -319,7 +321,7 @@ static const struct cproc_option built_in_options[] = { } }; -cproc_t cproc_new(void) +cproc_t cproc_new(device_t dev) { cproc_t cp = malloc(sizeof(*cp)); @@ -328,6 +330,8 @@ cproc_t cproc_new(void) memset(cp, 0, sizeof(*cp)); + cp->device = dev; + vector_init(&cp->command_list, sizeof(struct cproc_command)); vector_init(&cp->option_list, sizeof(struct cproc_option)); @@ -346,11 +350,17 @@ cproc_t cproc_new(void) void cproc_destroy(cproc_t cp) { + cp->device->destroy(cp->device); vector_destroy(&cp->command_list); vector_destroy(&cp->option_list); free(cp); } +device_t cproc_device(cproc_t cp) +{ + return cp->device; +} + int cproc_register_commands(cproc_t cp, const struct cproc_command *cmd, int count) { diff --git a/cproc.h b/cproc.h index 9c2c6c3..20b765f 100644 --- a/cproc.h +++ b/cproc.h @@ -19,6 +19,8 @@ #ifndef CPROC_H_ #define CPROC_H_ +#include "device.h" + /* Command processor. * * This contains a list of all defined commands and options, plus modification @@ -82,10 +84,17 @@ struct cproc_option { /* Create/destroy a command processor. The init function returns 0 if * successful, or -1 if an error occurs. + * + * The command processor takes responsibility for the device object it + * has been given. When you destroy a command processor, the device is + * also destroyed. */ -cproc_t cproc_new(void); +cproc_t cproc_new(device_t dev); void cproc_destroy(cproc_t cp); +/* Fetch the command processor's device */ +device_t cproc_device(cproc_t cp); + /* Register commands and options with the command processor. These functions * return 0 on success or -1 if an error occurs (failure to allocate memory). */ diff --git a/devcmd.c b/devcmd.c index e08fbb4..130258d 100644 --- a/devcmd.c +++ b/devcmd.c @@ -32,15 +32,16 @@ static int cmd_regs(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); u_int16_t regs[DEVICE_NUM_REGS]; u_int8_t code[16]; - if (device_get()->getregs(regs) < 0) + if (dev->getregs(dev, regs) < 0) return -1; cproc_regs(cp, regs); /* Try to disassemble the instruction at PC */ - if (device_get()->readmem(regs[0], code, sizeof(code)) < 0) + if (dev->readmem(dev, regs[0], code, sizeof(code)) < 0) return 0; cproc_disassemble(cp, regs[0], (u_int8_t *)code, sizeof(code)); @@ -49,6 +50,7 @@ static int cmd_regs(cproc_t cp, char **arg) static int cmd_md(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *off_text = get_arg(arg); char *len_text = get_arg(arg); int offset = 0; @@ -83,7 +85,7 @@ static int cmd_md(cproc_t cp, char **arg) u_int8_t buf[128]; int blen = length > sizeof(buf) ? sizeof(buf) : length; - if (device_get()->readmem(offset, buf, blen) < 0) + if (dev->readmem(dev, offset, buf, blen) < 0) return -1; cproc_hexdump(cp, offset, buf, blen); @@ -96,6 +98,7 @@ static int cmd_md(cproc_t cp, char **arg) static int cmd_mw(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *off_text = get_arg(arg); char *byte_text; int offset = 0; @@ -129,7 +132,7 @@ static int cmd_mw(cproc_t cp, char **arg) return -1; } - if (device_get()->writemem(offset, buf, length) < 0) + if (dev->writemem(dev, offset, buf, length) < 0) return -1; return 0; @@ -137,20 +140,25 @@ static int cmd_mw(cproc_t cp, char **arg) static int cmd_reset(cproc_t cp, char **arg) { - return device_get()->control(DEVICE_CTL_RESET); + device_t dev = cproc_device(cp); + + return dev->ctl(dev, DEVICE_CTL_RESET); } static int cmd_erase(cproc_t cp, char **arg) { - if (device_get()->control(DEVICE_CTL_HALT) < 0) + device_t dev = cproc_device(cp); + + if (dev->ctl(dev, DEVICE_CTL_HALT) < 0) return -1; printf("Erasing...\n"); - return device_get()->control(DEVICE_CTL_ERASE); + return dev->ctl(dev, DEVICE_CTL_ERASE); } static int cmd_step(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *count_text = get_arg(arg); int count = 1; @@ -158,7 +166,7 @@ static int cmd_step(cproc_t cp, char **arg) count = atoi(count_text); while (count > 0) { - if (device_get()->control(DEVICE_CTL_STEP) < 0) + if (dev->ctl(dev, DEVICE_CTL_STEP) < 0) return -1; count--; } @@ -168,6 +176,7 @@ static int cmd_step(cproc_t cp, char **arg) static int cmd_run(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *bp_text = get_arg(arg); int bp_addr; device_status_t status; @@ -179,11 +188,12 @@ static int cmd_run(cproc_t cp, char **arg) return -1; } - device_get()->breakpoint(bp_addr); + dev->breakpoint(dev, 1, bp_addr); + } else { + dev->breakpoint(dev, 0, 0); } - if (device_get()->control(bp_text ? - DEVICE_CTL_RUN_BP : DEVICE_CTL_RUN) < 0) + if (dev->ctl(dev, DEVICE_CTL_RUN) < 0) return -1; if (bp_text) @@ -192,11 +202,17 @@ static int cmd_run(cproc_t cp, char **arg) printf("Running."); printf(" Press Ctrl+C to interrupt...\n"); - status = device_get()->wait(1); + do { + status = dev->poll(dev); + } while (status == DEVICE_STATUS_RUNNING); + if (status == DEVICE_STATUS_INTR) printf("\n"); - if (device_get()->control(DEVICE_CTL_HALT) < 0) + if (status == DEVICE_STATUS_ERROR) + return -1; + + if (dev->ctl(dev, DEVICE_CTL_HALT) < 0) return -1; return cmd_regs(cp, NULL); @@ -204,6 +220,7 @@ static int cmd_run(cproc_t cp, char **arg) static int cmd_set(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *reg_text = get_arg(arg); char *val_text = get_arg(arg); int reg; @@ -229,10 +246,10 @@ static int cmd_set(cproc_t cp, char **arg) return -1; } - if (device_get()->getregs(regs) < 0) + if (dev->getregs(dev, regs) < 0) return -1; regs[reg] = value; - if (device_get()->setregs(regs) < 0) + if (dev->setregs(dev, regs) < 0) return -1; cproc_regs(cp, regs); @@ -241,6 +258,7 @@ static int cmd_set(cproc_t cp, char **arg) static int cmd_dis(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *off_text = get_arg(arg); char *len_text = get_arg(arg); int offset = 0; @@ -273,7 +291,7 @@ static int cmd_dis(cproc_t cp, char **arg) return -1; } - if (device_get()->readmem(offset, buf, length) < 0) + if (dev->readmem(dev, offset, buf, length) < 0) return -1; cproc_disassemble(cp, offset, (u_int8_t *)buf, length); @@ -357,6 +375,7 @@ static int hexout_feed(u_int16_t addr, const u_int8_t *buf, int len) static int cmd_hexout(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); char *off_text = get_arg(arg); char *len_text = get_arg(arg); char *filename = *arg; @@ -383,7 +402,7 @@ static int cmd_hexout(cproc_t cp, char **arg) count = sizeof(buf); printf("Reading %d bytes from 0x%04x...\n", count, off); - if (device_get()->readmem(off, buf, count) < 0) { + if (dev->readmem(dev, off, buf, count) < 0) { perror("hexout: can't read memory"); goto fail; } @@ -410,69 +429,79 @@ fail: return -1; } -static u_int8_t prog_buf[128]; -static u_int16_t prog_addr; -static int prog_len; -static int prog_have_erased; +struct prog_data { + device_t dev; -static void prog_init(void) + u_int8_t buf[128]; + u_int16_t addr; + int len; + int have_erased; +}; + +static void prog_init(struct prog_data *prog, device_t dev) { - prog_len = 0; - prog_have_erased = 0; + prog->dev = dev; + prog->len = 0; + prog->have_erased = 0; } -static int prog_flush(void) +static int prog_flush(struct prog_data *prog) { - while (prog_len) { - int wlen = prog_len; + while (prog->len) { + int wlen = prog->len; /* Writing across this address seems to cause a hang */ - if (prog_addr < 0x999a && wlen + prog_addr > 0x999a) - wlen = 0x999a - prog_addr; + if (prog->addr < 0x999a && wlen + prog->addr > 0x999a) + wlen = 0x999a - prog->addr; - if (!prog_have_erased) { + if (!prog->have_erased) { printf("Erasing...\n"); - if (device_get()->control(DEVICE_CTL_ERASE) < 0) + if (prog->dev->ctl(prog->dev, DEVICE_CTL_ERASE) < 0) return -1; - prog_have_erased = 1; + prog->have_erased = 1; } - printf("Writing %3d bytes to %04x...\n", wlen, prog_addr); - if (device_get()->writemem(prog_addr, prog_buf, wlen) < 0) + printf("Writing %3d bytes to %04x...\n", wlen, prog->addr); + if (prog->dev->writemem(prog->dev, prog->addr, + prog->buf, wlen) < 0) return -1; - memmove(prog_buf, prog_buf + wlen, prog_len - wlen); - prog_len -= wlen; - prog_addr += wlen; + memmove(prog->buf, prog->buf + wlen, prog->len - wlen); + prog->len -= wlen; + prog->addr += wlen; } return 0; } -static int prog_feed(u_int16_t addr, const u_int8_t *data, int len) +static int prog_feed(void *user_data, + u_int16_t addr, const u_int8_t *data, int len) { + struct prog_data *prog = (struct prog_data *)user_data; + /* Flush if this section is discontiguous */ - if (prog_len && prog_addr + prog_len != addr && prog_flush() < 0) + if (prog->len && prog->addr + prog->len != addr && + prog_flush(prog) < 0) return -1; - if (!prog_len) - prog_addr = addr; + if (!prog->len) + prog->addr = addr; /* Add the buffer in piece by piece, flushing when it gets * full. */ while (len) { - int count = sizeof(prog_buf) - prog_len; + int count = sizeof(prog->buf) - prog->len; if (count > len) count = len; if (!count) { - if (prog_flush() < 0) + if (prog_flush(prog) < 0) return -1; } else { - memcpy(prog_buf + prog_len, data, count); - prog_len += count; + memcpy(prog->buf + prog->len, data, count); + prog->len += count; data += count; len -= count; } @@ -483,8 +512,10 @@ static int prog_feed(u_int16_t addr, const u_int8_t *data, int len) static int cmd_prog(cproc_t cp, char **arg) { + device_t dev = cproc_device(cp); FILE *in; int result = 0; + struct prog_data prog; if (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS)) return 0; @@ -495,29 +526,29 @@ static int cmd_prog(cproc_t cp, char **arg) return -1; } - if (device_get()->control(DEVICE_CTL_HALT) < 0) { + if (dev->ctl(dev, DEVICE_CTL_HALT) < 0) { fclose(in); return -1; } - prog_init(); + prog_init(&prog, dev); if (elf32_check(in)) { - result = elf32_extract(in, prog_feed); + result = elf32_extract(in, prog_feed, &prog); stab_clear(); elf32_syms(in, stab_set); } else if (ihex_check(in)) { - result = ihex_extract(in, prog_feed); + result = ihex_extract(in, prog_feed, &prog); } else { fprintf(stderr, "prog: %s: unknown file type\n", *arg); } fclose(in); - if (prog_flush() < 0) + if (prog_flush(&prog) < 0) return -1; - if (device_get()->control(DEVICE_CTL_RESET) < 0) { + if (dev->ctl(dev, DEVICE_CTL_RESET) < 0) { fprintf(stderr, "prog: failed to reset after programming\n"); return -1; } diff --git a/device.c b/device.c index 5847eed..3d2a9c2 100644 --- a/device.c +++ b/device.c @@ -17,26 +17,10 @@ */ #include -#include #include -#include -#include -#include #include "device.h" #include "util.h" -static const struct device *msp430_dev; - -void device_set(const struct device *dev) -{ - msp430_dev = dev; -} - -const struct device *device_get(void) -{ - return msp430_dev; -} - /* This table of device IDs is sourced mainly from the MSP430 Memory * Programming User's Guide (SLAU265). * @@ -80,7 +64,7 @@ static struct { {0xF46F, "F471xx"} }; -int find_device_id(u_int16_t id, char *out, int max_len) +int device_id_text(u_int16_t id, char *out, int max_len) { int i = 0; int len; diff --git a/device.h b/device.h index 0864ca8..8367931 100644 --- a/device.h +++ b/device.h @@ -1,4 +1,4 @@ -/* MSPDebug - debugging tool for the eZ430 +/* MSPDebug - debugging tool for MSP430 MCUs * Copyright (C) 2009, 2010 Daniel Beer * * This program is free software; you can redistribute it and/or modify @@ -20,15 +20,14 @@ #define DEVICE_H_ #include -#include "transport.h" -#define DEVICE_NUM_REGS 16 +struct device; +typedef struct device *device_t; typedef enum { DEVICE_CTL_RESET, DEVICE_CTL_RUN, DEVICE_CTL_HALT, - DEVICE_CTL_RUN_BP, DEVICE_CTL_STEP, DEVICE_CTL_ERASE } device_ctl_t; @@ -40,35 +39,33 @@ typedef enum { DEVICE_STATUS_ERROR } device_status_t; +#define DEVICE_NUM_REGS 16 + struct device { - void (*close)(void); - int (*control)(device_ctl_t action); - device_status_t (*wait)(int blocking); - int (*breakpoint)(u_int16_t addr); - int (*getregs)(u_int16_t *regs); - int (*setregs)(const u_int16_t *regs); - int (*readmem)(u_int16_t addr, u_int8_t *mem, int len); - int (*writemem)(u_int16_t addr, const u_int8_t *mem, int len); + /* Close the connection to the device and destroy the driver object */ + void (*destroy)(device_t dev); + + /* Read/write memory */ + int (*readmem)(device_t dev, u_int16_t addr, + u_int8_t *mem, int len); + int (*writemem)(device_t dev, u_int16_t addr, + const u_int8_t *mem, int len); + + /* Read/write registers */ + int (*getregs)(device_t dev, u_int16_t *regs); + int (*setregs)(device_t dev, const u_int16_t *regs); + + /* Breakpoint control */ + int (*breakpoint)(device_t dev, int enabled, u_int16_t addr); + + /* CPU control */ + int (*ctl)(device_t dev, device_ctl_t op); + + /* Wait a little while for the CPU to change state */ + device_status_t (*poll)(device_t dev); }; -/* MSP430 FET protocol implementation. */ -#define FET_PROTO_SPYBIWIRE 0x01 -#define FET_PROTO_RF2500 0x02 - -const struct device *fet_open(const struct fet_transport *transport, - int proto_flags, int vcc_mv); - -/* MSP430 FET Bootloader implementation. */ -const struct device *bsl_open(const char *device); - -/* Dummy/simulation implementation. */ -const struct device *sim_open(void); - /* Look up a device ID. Returns 0 on success or -1 if none found */ -int find_device_id(u_int16_t id, char *out, int max_len); - -/* Set/get the active device */ -void device_set(const struct device *dev); -const struct device *device_get(void); +int device_id_text(u_int16_t id, char *out, int max_len); #endif diff --git a/elf32.c b/elf32.c index 66aa43b..793cdda 100644 --- a/elf32.c +++ b/elf32.c @@ -126,7 +126,8 @@ static u_int32_t file_to_phys(u_int32_t v) return v; } -static int feed_section(FILE *in, int offset, int size, imgfunc_t cb) +static int feed_section(FILE *in, int offset, int size, imgfunc_t cb, + void *user_data) { u_int8_t buf[1024]; u_int16_t addr = file_to_phys(offset); @@ -145,7 +146,7 @@ static int feed_section(FILE *in, int offset, int size, imgfunc_t cb) return -1; } - if (cb(addr, buf, len) < 0) + if (cb(user_data, addr, buf, len) < 0) return -1; size -= len; @@ -173,7 +174,7 @@ static int read_all(FILE *in) return 0; } -int elf32_extract(FILE *in, imgfunc_t cb) +int elf32_extract(FILE *in, imgfunc_t cb, void *user_data) { int i; @@ -184,7 +185,8 @@ int elf32_extract(FILE *in, imgfunc_t cb) Elf32_Shdr *s = &file_shdrs[i]; if (s->sh_type == SHT_PROGBITS && s->sh_flags & SHF_ALLOC && - feed_section(in, s->sh_offset, s->sh_size, cb) < 0) + feed_section(in, s->sh_offset, s->sh_size, + cb, user_data) < 0) return -1; } diff --git a/fet.c b/fet.c index b9cf659..14f1f08 100644 --- a/fet.c +++ b/fet.c @@ -21,16 +21,42 @@ */ #include +#include #include #include #include #include #include "util.h" -#include "device.h" +#include "fet.h" -static const struct fet_transport *fet_transport; -static int fet_is_rf2500; +#define MAX_PARAMS 16 + +struct fet_device { + struct device base; + + const struct fet_transport *fet_transport; + int is_rf2500; + int version; + int have_breakpoint; + + u_int16_t code_left[65536]; + + u_int8_t fet_buf[65538]; + int fet_len; + + /* Recieved packet is parsed into this struct */ + struct { + int command_code; + int state; + + int argc; + u_int32_t argv[MAX_PARAMS]; + + u_int8_t *data; + int datalen; + } fet_reply; +}; /********************************************************************** * FET command codes. @@ -97,13 +123,11 @@ static int fet_is_rf2500; * Checksum calculation */ -static u_int16_t code_left[65536]; - /* Initialise the code table. The code table is a function which takes * us from one checksum position code to the next. */ -static void init_codes(void) +static void init_codes(struct fet_device *dev) { int i; @@ -113,7 +137,7 @@ static void init_codes(void) if (i & 0x8000) right ^= 0x0811; - code_left[right] = i; + dev->code_left[right] = i; } } @@ -121,14 +145,15 @@ static void init_codes(void) * needs to be stored in little-endian format at the end of the payload. */ -static u_int16_t calc_checksum(const u_int8_t *data, int len) +static u_int16_t calc_checksum(struct fet_device *dev, + const u_int8_t *data, int len) { int i; u_int16_t cksum = 0xffff; u_int16_t code = 0x8408; for (i = len * 8; i; i--) - cksum = code_left[cksum]; + cksum = dev->code_left[cksum]; for (i = len - 1; i >= 0; i--) { int j; @@ -137,7 +162,7 @@ static u_int16_t calc_checksum(const u_int8_t *data, int len) for (j = 0; j < 8; j++) { if (c & 0x80) cksum ^= code; - code = code_left[code]; + code = dev->code_left[code]; c <<= 1; } } @@ -156,11 +181,11 @@ static u_int16_t calc_checksum(const u_int8_t *data, int len) * * No checksums are included. */ -static int send_rf2500_data(const u_int8_t *data, int len) +static int send_rf2500_data(struct fet_device *dev, + const u_int8_t *data, int len) { int offset = 0; - assert (fet_transport != NULL); while (len) { u_int8_t pbuf[63]; int plen = len > 59 ? 59 : len; @@ -170,7 +195,7 @@ static int send_rf2500_data(const u_int8_t *data, int len) pbuf[2] = offset >> 8; pbuf[3] = plen; memcpy(pbuf + 4, data, plen); - if (fet_transport->send(pbuf, plen + 4) < 0) + if (dev->fet_transport->send(pbuf, plen + 4) < 0) return -1; data += plen; @@ -181,23 +206,6 @@ static int send_rf2500_data(const u_int8_t *data, int len) return 0; } -static u_int8_t fet_buf[65538]; -static int fet_len; - -#define MAX_PARAMS 16 - -/* Recieved packet is parsed into this struct */ -static struct { - int command_code; - int state; - - int argc; - u_int32_t argv[MAX_PARAMS]; - - u_int8_t *data; - int datalen; -} fet_reply; - #define BUFFER_BYTE(b, x) ((int)((u_int8_t *)(b))[x]) #define BUFFER_WORD(b, x) ((BUFFER_BYTE(b, x + 1) << 8) | BUFFER_BYTE(b, x)) #define BUFFER_LONG(b, x) ((BUFFER_WORD(b, x + 2) << 16) | BUFFER_WORD(b, x)) @@ -274,10 +282,10 @@ static const char *error_strings[] = "Invalid error number", // 53 }; -static int parse_packet(int plen) +static int parse_packet(struct fet_device *dev, int plen) { - u_int16_t c = calc_checksum(fet_buf + 2, plen - 2); - u_int16_t r = BUFFER_WORD(fet_buf, plen); + u_int16_t c = calc_checksum(dev, dev->fet_buf + 2, plen - 2); + u_int16_t r = BUFFER_WORD(dev->fet_buf, plen); int i = 2; int type; int error; @@ -291,10 +299,10 @@ static int parse_packet(int plen) if (plen < 6) goto too_short; - fet_reply.command_code = fet_buf[i++]; - type = fet_buf[i++]; - fet_reply.state = fet_buf[i++]; - error = fet_buf[i++]; + dev->fet_reply.command_code = dev->fet_buf[i++]; + type = dev->fet_buf[i++]; + dev->fet_reply.state = dev->fet_buf[i++]; + error = dev->fet_buf[i++]; if (error) { fprintf(stderr, "fet: FET returned error code %d\n", @@ -317,23 +325,23 @@ static int parse_packet(int plen) if (i + 2 > plen) goto too_short; - fet_reply.argc = BUFFER_WORD(fet_buf, i); + dev->fet_reply.argc = BUFFER_WORD(dev->fet_buf, i); i += 2; - if (fet_reply.argc >= MAX_PARAMS) { + if (dev->fet_reply.argc >= MAX_PARAMS) { fprintf(stderr, "fet: too many params: %d\n", - fet_reply.argc); + dev->fet_reply.argc); return -1; } - for (j = 0; j < fet_reply.argc; j++) { + for (j = 0; j < dev->fet_reply.argc; j++) { if (i + 4 > plen) goto too_short; - fet_reply.argv[j] = BUFFER_LONG(fet_buf, i); + dev->fet_reply.argv[j] = BUFFER_LONG(dev->fet_buf, i); i += 4; } } else { - fet_reply.argc = 0; + dev->fet_reply.argc = 0; } /* Extract a pointer to the data */ @@ -341,16 +349,16 @@ static int parse_packet(int plen) if (i + 4 > plen) goto too_short; - fet_reply.datalen = BUFFER_LONG(fet_buf, i); + dev->fet_reply.datalen = BUFFER_LONG(dev->fet_buf, i); i += 4; - if (i + fet_reply.datalen > plen) + if (i + dev->fet_reply.datalen > plen) goto too_short; - fet_reply.data = fet_buf + i; + dev->fet_reply.data = dev->fet_buf + i; } else { - fet_reply.data = NULL; - fet_reply.datalen = 0; + dev->fet_reply.data = NULL; + dev->fet_reply.datalen = 0; } return 0; @@ -361,37 +369,37 @@ too_short: return -1; } -static int recv_packet(void) +static int recv_packet(struct fet_device *dev) { - int plen = BUFFER_WORD(fet_buf, 0); - - assert (fet_transport != NULL); + int plen = BUFFER_WORD(dev->fet_buf, 0); /* If there's a packet still here from last time, get rid of it */ - if (fet_len >= plen + 2) { - memmove(fet_buf, fet_buf + plen + 2, fet_len - plen - 2); - fet_len -= plen + 2; + if (dev->fet_len >= plen + 2) { + memmove(dev->fet_buf, dev->fet_buf + plen + 2, + dev->fet_len - plen - 2); + dev->fet_len -= plen + 2; } /* Keep adding data to the buffer until we have a complete packet */ for (;;) { int len; - plen = BUFFER_WORD(fet_buf, 0); - if (fet_len >= plen + 2) - return parse_packet(plen); + plen = BUFFER_WORD(dev->fet_buf, 0); + if (dev->fet_len >= plen + 2) + return parse_packet(dev, plen); - len = fet_transport->recv(fet_buf + fet_len, - sizeof(fet_buf) - fet_len); + len = dev->fet_transport->recv(dev->fet_buf + dev->fet_len, + sizeof(dev->fet_buf) - + dev->fet_len); if (len < 0) return -1; - fet_len += len; + dev->fet_len += len; } return -1; } -static int send_command(int command_code, +static int send_command(struct fet_device *dev, int command_code, const u_int32_t *params, int nparams, const u_int8_t *extra, int exlen) { @@ -404,7 +412,6 @@ static int send_command(int command_code, int j; assert (len + exlen + 2 <= sizeof(datapkt)); - assert (fet_transport != NULL); /* Command code and packet type */ datapkt[len++] = command_code; @@ -445,7 +452,7 @@ static int send_command(int command_code, } /* Checksum */ - cksum = calc_checksum(datapkt, len); + cksum = calc_checksum(dev, datapkt, len); datapkt[len++] = cksum & 0xff; datapkt[len++] = cksum >> 8; @@ -467,10 +474,11 @@ static int send_command(int command_code, assert (i < sizeof(buf)); - return fet_transport->send(buf, i); + return dev->fet_transport->send(buf, i); } -static int xfer(int command_code, const u_int8_t *data, int datalen, +static int xfer(struct fet_device *dev, + int command_code, const u_int8_t *data, int datalen, int nparams, ...) { u_int32_t params[MAX_PARAMS]; @@ -484,22 +492,23 @@ static int xfer(int command_code, const u_int8_t *data, int datalen, params[i] = va_arg(ap, unsigned int); va_end(ap); - if (data && fet_is_rf2500) { + if (data && dev->is_rf2500) { assert (nparams + 1 <= MAX_PARAMS); params[nparams++] = datalen; - if (send_rf2500_data(data, datalen) < 0) + if (send_rf2500_data(dev, data, datalen) < 0) return -1; - if (send_command(command_code, params, nparams, NULL, 0) < 0) + if (send_command(dev, command_code, params, nparams, + NULL, 0) < 0) return -1; - } else if (send_command(command_code, params, nparams, + } else if (send_command(dev, command_code, params, nparams, data, datalen) < 0) return -1; - if (recv_packet() < 0) + if (recv_packet(dev) < 0) return -1; - if (fet_reply.command_code != command_code) { + if (dev->fet_reply.command_code != command_code) { fprintf(stderr, "fet: reply type mismatch\n"); return -1; } @@ -511,38 +520,36 @@ static int xfer(int command_code, const u_int8_t *data, int datalen, * MSP430 high-level control functions */ -static int fet_version; - -static int do_identify(void) +static int do_identify(struct fet_device *dev) { char idtext[64]; - if (fet_version < 20300000) { - if (xfer(C_IDENTIFY, NULL, 0, 2, 70, 0) < 0) + if (dev->version < 20300000) { + if (xfer(dev, C_IDENTIFY, NULL, 0, 2, 70, 0) < 0) return -1; - if (!fet_reply.data) { + if (!dev->fet_reply.data) { fprintf(stderr, "fet: missing info\n"); return -1; } - memcpy(idtext, fet_reply.data + 4, 32); + memcpy(idtext, dev->fet_reply.data + 4, 32); idtext[32] = 0; } else { u_int16_t id; - if (xfer(0x28, NULL, 0, 2, 0, 0) < 0) { + if (xfer(dev, 0x28, NULL, 0, 2, 0, 0) < 0) { fprintf(stderr, "fet: command 0x28 failed\n"); return -1; } - if (fet_reply.datalen < 2) { + if (dev->fet_reply.datalen < 2) { fprintf(stderr, "fet: missing info\n"); return -1; } - id = (fet_reply.data[0] << 8) | fet_reply.data[1]; - if (find_device_id(id, idtext, sizeof(idtext)) < 0) { + id = (dev->fet_reply.data[0] << 8) | dev->fet_reply.data[1]; + if (device_id_text(id, idtext, sizeof(idtext)) < 0) { printf("Unknown device ID: 0x%04x\n", id); return 0; } @@ -552,30 +559,9 @@ static int do_identify(void) return 0; } -static void fet_close(void) +static int do_run(struct fet_device *dev, int type) { - if (xfer(C_RUN, NULL, 0, 2, FET_RUN_FREE, 1) < 0) - fprintf(stderr, "fet: failed to restart CPU\n"); - - if (xfer(C_CLOSE, NULL, 0, 1, 0) < 0) - fprintf(stderr, "fet: close command failed\n"); - - fet_transport->close(); - fet_transport = NULL; -} - -static int do_reset(void) { - if (xfer(C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 0) { - fprintf(stderr, "fet: reset failed\n"); - return -1; - } - - return 0; -} - -static int do_run(int type) -{ - if (xfer(C_RUN, NULL, 0, 2, type, 0) < 0) { + if (xfer(dev, C_RUN, NULL, 0, 2, type, 0) < 0) { fprintf(stderr, "fet: failed to restart CPU\n"); return -1; } @@ -583,34 +569,24 @@ static int do_run(int type) return 0; } -static int do_halt(void) +static int do_erase(struct fet_device *dev) { - if (xfer(C_STATE, NULL, 0, 1, 1) < 0) { - fprintf(stderr, "fet: failed to halt CPU\n"); - return -1; - } - - return 0; -} - -static int do_erase(void) -{ - if (xfer(C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 0) { + if (xfer(dev, C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 0) { fprintf(stderr, "fet: reset before erase failed\n"); return -1; } - if (xfer(C_CONFIGURE, NULL, 0, 2, 2, 0x26) < 0) { + if (xfer(dev, C_CONFIGURE, NULL, 0, 2, 2, 0x26) < 0) { fprintf(stderr, "fet: config (1) failed\n"); return -1; } - if (xfer(C_CONFIGURE, NULL, 0, 2, 5, 0) < 0) { + if (xfer(dev, C_CONFIGURE, NULL, 0, 2, 5, 0) < 0) { fprintf(stderr, "fet: config (2) failed\n"); return -1; } - if (xfer(C_ERASE, NULL, 0, 3, FET_ERASE_MAIN, 0x8000, 2) < 0) { + if (xfer(dev, C_ERASE, NULL, 0, 3, FET_ERASE_MAIN, 0x8000, 2) < 0) { fprintf(stderr, "fet: erase command failed\n"); return -1; } @@ -618,124 +594,105 @@ static int do_erase(void) return 0; } -static device_status_t fet_wait(int blocking) +static device_status_t fet_poll(device_t dev_base) { - do { - /* Without this delay, breakpoints can get lost. */ - if (usleep(500000) < 0) - return DEVICE_STATUS_INTR; + struct fet_device *dev = (struct fet_device *)dev_base; - if (xfer(C_STATE, NULL, 0, 1, 0) < 0) { - fprintf(stderr, "fet: polling failed\n"); - return DEVICE_STATUS_ERROR; - } + /* Without this delay, breakpoints can get lost. */ + if (usleep(500000) < 0) + return DEVICE_STATUS_INTR; - if (!(fet_reply.argv[0] & FET_POLL_RUNNING)) - return DEVICE_STATUS_HALTED; - } while (blocking); + if (xfer(dev, C_STATE, NULL, 0, 1, 0) < 0) { + fprintf(stderr, "fet: polling failed\n"); + return DEVICE_STATUS_ERROR; + } + + if (!(dev->fet_reply.argv[0] & FET_POLL_RUNNING)) + return DEVICE_STATUS_HALTED; return DEVICE_STATUS_RUNNING; } -static int fet_control(device_ctl_t action) +static int fet_ctl(device_t dev_base, device_ctl_t action) { + struct fet_device *dev = (struct fet_device *)dev_base; + switch (action) { case DEVICE_CTL_RESET: - return do_reset(); + if (xfer(dev, C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 0) { + fprintf(stderr, "fet: reset failed\n"); + return -1; + } + break; case DEVICE_CTL_RUN: - return do_run(FET_RUN_FREE); - - case DEVICE_CTL_RUN_BP: - return do_run(FET_RUN_BREAKPOINT); + return do_run(dev, dev->have_breakpoint ? + FET_RUN_BREAKPOINT : FET_RUN_FREE); case DEVICE_CTL_HALT: - return do_halt(); + if (xfer(dev, C_STATE, NULL, 0, 1, 1) < 0) { + fprintf(stderr, "fet: failed to halt CPU\n"); + return -1; + } + break; case DEVICE_CTL_STEP: - if (do_run(FET_RUN_STEP) < 0) + if (do_run(dev, FET_RUN_STEP) < 0) return -1; - if (fet_wait(1) < 0) - return -1; - return 0; + + for (;;) { + device_status_t status = fet_poll(dev_base); + + if (status == DEVICE_STATUS_ERROR || + status == DEVICE_STATUS_INTR) + return -1; + + if (status == DEVICE_STATUS_HALTED) + break; + } + break; case DEVICE_CTL_ERASE: - return do_erase(); + return do_erase(dev); } return 0; } -static int fet_breakpoint(u_int16_t addr) +static void fet_destroy(device_t dev_base) { - if (xfer(C_BREAKPOINT, NULL, 0, 2, 0, addr) < 0) { - fprintf(stderr, "fet: set breakpoint failed\n"); - return -1; - } + struct fet_device *dev = (struct fet_device *)dev_base; - return 0; + if (xfer(dev, C_RUN, NULL, 0, 2, FET_RUN_FREE, 1) < 0) + fprintf(stderr, "fet: failed to restart CPU\n"); + + if (xfer(dev, C_CLOSE, NULL, 0, 1, 0) < 0) + fprintf(stderr, "fet: close command failed\n"); + + dev->fet_transport->close(); + free(dev); } -static int fet_getregs(u_int16_t *regs) +int fet_readmem(device_t dev_base, u_int16_t addr, u_int8_t *buffer, int count) { - int i; + struct fet_device *dev = (struct fet_device *)dev_base; - if (xfer(C_READREGISTERS, NULL, 0, 0) < 0) - return -1; - - if (fet_reply.datalen < DEVICE_NUM_REGS * 4) { - fprintf(stderr, "fet: short reply (%d bytes)\n", - fet_reply.datalen); - return -1; - } - - for (i = 0; i < DEVICE_NUM_REGS; i++) - regs[i] = BUFFER_WORD(fet_reply.data, i * 4); - - return 0; -} - -static int fet_setregs(const u_int16_t *regs) -{ - u_int8_t buf[DEVICE_NUM_REGS * 4];; - int i; - int ret; - - memset(buf, 0, sizeof(buf)); - - for (i = 0; i < DEVICE_NUM_REGS; i++) { - buf[i * 4] = regs[i] & 0xff; - buf[i * 4 + 1] = regs[i] >> 8; - } - - ret = xfer(C_WRITEREGISTERS, buf, sizeof(buf), 1, 0xffff); - - if (ret < 0) { - fprintf(stderr, "fet: context set failed\n"); - return -1; - } - - return 0; -} - -int fet_readmem(u_int16_t addr, u_int8_t *buffer, int count) -{ while (count) { int plen = count > 128 ? 128 : count; - if (xfer(C_READMEMORY, NULL, 0, 2, addr, plen) < 0) { + if (xfer(dev, C_READMEMORY, NULL, 0, 2, addr, plen) < 0) { fprintf(stderr, "fet: failed to read " "from 0x%04x\n", addr); return -1; } - if (fet_reply.datalen < plen) { + if (dev->fet_reply.datalen < plen) { fprintf(stderr, "fet: short data: " - "%d bytes\n", fet_reply.datalen); + "%d bytes\n", dev->fet_reply.datalen); return -1; } - memcpy(buffer, fet_reply.data, plen); + memcpy(buffer, dev->fet_reply.data, plen); buffer += plen; count -= plen; addr += plen; @@ -744,13 +701,16 @@ int fet_readmem(u_int16_t addr, u_int8_t *buffer, int count) return 0; } -int fet_writemem(u_int16_t addr, const u_int8_t *buffer, int count) +int fet_writemem(device_t dev_base, u_int16_t addr, + const u_int8_t *buffer, int count) { + struct fet_device *dev = (struct fet_device *)dev_base; + while (count) { int plen = count > 128 ? 128 : count; int ret; - ret = xfer(C_WRITEMEMORY, buffer, plen, 1, addr); + ret = xfer(dev, C_WRITEMEMORY, buffer, plen, 1, addr); if (ret < 0) { fprintf(stderr, "fet: failed to write to 0x%04x\n", @@ -766,16 +726,67 @@ int fet_writemem(u_int16_t addr, const u_int8_t *buffer, int count) return 0; } -const static struct device fet_device = { - .close = fet_close, - .control = fet_control, - .wait = fet_wait, - .breakpoint = fet_breakpoint, - .getregs = fet_getregs, - .setregs = fet_setregs, - .readmem = fet_readmem, - .writemem = fet_writemem -}; +static int fet_getregs(device_t dev_base, u_int16_t *regs) +{ + struct fet_device *dev = (struct fet_device *)dev_base; + int i; + + if (xfer(dev, C_READREGISTERS, NULL, 0, 0) < 0) + return -1; + + if (dev->fet_reply.datalen < DEVICE_NUM_REGS * 4) { + fprintf(stderr, "fet: short reply (%d bytes)\n", + dev->fet_reply.datalen); + return -1; + } + + for (i = 0; i < DEVICE_NUM_REGS; i++) + regs[i] = BUFFER_WORD(dev->fet_reply.data, i * 4); + + return 0; +} + +static int fet_setregs(device_t dev_base, const u_int16_t *regs) +{ + struct fet_device *dev = (struct fet_device *)dev_base; + u_int8_t buf[DEVICE_NUM_REGS * 4];; + int i; + int ret; + + memset(buf, 0, sizeof(buf)); + + for (i = 0; i < DEVICE_NUM_REGS; i++) { + buf[i * 4] = regs[i] & 0xff; + buf[i * 4 + 1] = regs[i] >> 8; + } + + ret = xfer(dev, C_WRITEREGISTERS, buf, sizeof(buf), 1, 0xffff); + + if (ret < 0) { + fprintf(stderr, "fet: context set failed\n"); + return -1; + } + + return 0; +} + +static int fet_breakpoint(device_t dev_base, int enabled, u_int16_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; + } + + return 0; +} #define MAGIC_DATA_SIZE 0x4a #define MAGIC_PARAM_COUNT 3 @@ -873,25 +884,26 @@ const static struct magic_record magic_table[] = { } }; -static int do_magic(void) +static int do_magic(struct fet_device *dev) { int i; for (i = 0; i < ARRAY_LEN(magic_table); i++) { const struct magic_record *r = &magic_table[i]; - if (fet_version >= r->min_version) { + if (dev->version >= r->min_version) { printf("Sending magic messages for >= %d\n", r->min_version); if ((r->flags & MAGIC_SEND_2B) && - xfer(0x2b, r->data_2b, MAGIC_DATA_SIZE, 0) < 0) { + xfer(dev, 0x2b, r->data_2b, + MAGIC_DATA_SIZE, 0) < 0) { fprintf(stderr, "fet: command 0x2b failed\n"); return -1; } if ((r->flags & MAGIC_SEND_29) && - xfer(0x29, r->data_29, MAGIC_DATA_SIZE, + xfer(dev, 0x29, r->data_29, MAGIC_DATA_SIZE, 3, r->param_29[0], r->param_29[1], r->param_29[2]) < 0) { fprintf(stderr, "fet: command 0x29 failed\n"); @@ -905,55 +917,78 @@ static int do_magic(void) return 0; } -const struct device *fet_open(const struct fet_transport *tr, - int proto_flags, int vcc_mv) +device_t fet_open(const struct fet_transport *tr, + int proto_flags, int vcc_mv) { - fet_transport = tr; - fet_is_rf2500 = proto_flags & FET_PROTO_RF2500; - init_codes(); + struct fet_device *dev = malloc(sizeof(*dev)); - if (xfer(C_INITIALIZE, NULL, 0, 0) < 0) { - fprintf(stderr, "fet: open failed\n"); + if (!dev) { + perror("fet: failed to allocate memory"); return NULL; } - fet_version = fet_reply.argv[0]; - printf("FET protocol version is %d\n", fet_version); + 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.breakpoint = fet_breakpoint; + dev->base.ctl = fet_ctl; + dev->base.poll = fet_poll; - if (xfer(0x27, NULL, 0, 1, 4) < 0) { + dev->fet_transport = tr; + dev->is_rf2500 = proto_flags & FET_PROTO_RF2500; + dev->have_breakpoint = 0; + + init_codes(dev); + dev->fet_len = 0; + + if (xfer(dev, C_INITIALIZE, NULL, 0, 0) < 0) { + fprintf(stderr, "fet: open failed\n"); + goto fail; + } + + dev->version = dev->fet_reply.argv[0]; + printf("FET protocol version is %d\n", dev->version); + + if (xfer(dev, 0x27, NULL, 0, 1, 4) < 0) { fprintf(stderr, "fet: init failed\n"); - return NULL; + goto fail; } /* configure: Spy-Bi-Wire or JTAG */ - if (xfer(C_CONFIGURE, NULL, 0, + if (xfer(dev, C_CONFIGURE, NULL, 0, 2, 8, (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0) < 0) { fprintf(stderr, "fet: configure failed\n"); - return NULL; + goto fail; } printf("Configured for %s\n", (proto_flags & FET_PROTO_SPYBIWIRE) ? "Spy-Bi-Wire" : "JTAG"); /* set VCC */ - if (xfer(C_VCC, NULL, 0, 1, vcc_mv) < 0) { + if (xfer(dev, C_VCC, NULL, 0, 1, vcc_mv) < 0) { fprintf(stderr, "fet: set VCC failed\n"); - return NULL; + goto fail; } printf("Set Vcc: %d mV\n", vcc_mv); /* Identify the chip */ - if (do_identify() < 0) { + if (do_identify(dev) < 0) { fprintf(stderr, "fet: identify failed\n"); - return NULL; + goto fail; } /* Send the magic required by RF2500 and Chronos FETs */ - if (do_magic() < 0) { + if (do_magic(dev) < 0) { fprintf(stderr, "fet: init magic failed\n"); - return NULL; + goto fail; } - return &fet_device; + return (device_t)dev; + + fail: + free(dev); + return NULL; } diff --git a/fet.h b/fet.h new file mode 100644 index 0000000..56f9206 --- /dev/null +++ b/fet.h @@ -0,0 +1,32 @@ +/* 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 + */ + +#ifndef FET_H_ +#define FET_H_ + +#include "device.h" +#include "transport.h" + +/* MSP430 FET protocol implementation. */ +#define FET_PROTO_SPYBIWIRE 0x01 +#define FET_PROTO_RF2500 0x02 + +device_t fet_open(const struct fet_transport *transport, + int proto_flags, int vcc_mv); + +#endif diff --git a/gdb.c b/gdb.c index 7ddc7b6..7eefbde 100644 --- a/gdb.c +++ b/gdb.c @@ -35,43 +35,47 @@ * GDB IO routines */ -static int gdb_socket; -static int gdb_errno; +struct gdb_data { + int sock; + int error; -static char gdb_xbuf[1024]; -static int gdb_head; -static int gdb_tail; + char xbuf[1024]; + int head; + int tail; -static char gdb_outbuf[1024]; -static int gdb_outlen; + char outbuf[1024]; + int outlen; -static void gdb_printf(const char *fmt, ...) + device_t device; +}; + +static void gdb_printf(struct gdb_data *data, const char *fmt, ...) { va_list ap; int len; va_start(ap, fmt); - len = vsnprintf(gdb_outbuf + gdb_outlen, - sizeof(gdb_outbuf) - gdb_outlen, + len = vsnprintf(data->outbuf + data->outlen, + sizeof(data->outbuf) - data->outlen, fmt, ap); va_end(ap); - gdb_outlen += len; + data->outlen += len; } -static int gdb_flush(void) +static int gdb_flush(struct gdb_data *data) { - if (send(gdb_socket, gdb_outbuf, gdb_outlen, 0) < 0) { - gdb_errno = errno; + if (send(data->sock, data->outbuf, data->outlen, 0) < 0) { + data->error = errno; perror("gdb: send"); return -1; } - gdb_outlen = 0; + data->outlen = 0; return 0; } -static int gdb_read(int blocking) +static int gdb_read(struct gdb_data *data, int blocking) { fd_set r; int len; @@ -81,21 +85,21 @@ static int gdb_read(int blocking) }; FD_ZERO(&r); - FD_SET(gdb_socket, &r); + FD_SET(data->sock, &r); - if (select(gdb_socket + 1, &r, NULL, NULL, + if (select(data->sock + 1, &r, NULL, NULL, blocking ? NULL : &to) < 0) { perror("gdb: select"); return -1; } - if (!FD_ISSET(gdb_socket, &r)) + if (!FD_ISSET(data->sock, &r)) return 0; - len = recv(gdb_socket, gdb_xbuf, sizeof(gdb_xbuf), 0); + len = recv(data->sock, data->xbuf, sizeof(data->xbuf), 0); if (len < 0) { - gdb_errno = errno; + data->error = errno; perror("gdb: recv"); return -1; } @@ -105,46 +109,46 @@ static int gdb_read(int blocking) return -1; } - gdb_head = 0; - gdb_tail = len; + data->head = 0; + data->tail = len; return len; } -static int gdb_peek(void) +static int gdb_peek(struct gdb_data *data) { - if (gdb_head == gdb_tail && gdb_read(0) < 0) + if (data->head == data->tail && gdb_read(data, 0) < 0) return -1; - return gdb_head != gdb_tail; + return data->head != data->tail; } -static int gdb_getc(void) +static int gdb_getc(struct gdb_data *data) { int c; /* If the buffer is empty, receive some more data */ - if (gdb_head == gdb_tail && gdb_read(1) < 0) + if (data->head == data->tail && gdb_read(data, 1) < 0) return -1; - c = gdb_xbuf[gdb_head]; - gdb_head++; + c = data->xbuf[data->head]; + data->head++; return c; } -static int gdb_flush_ack(void) +static int gdb_flush_ack(struct gdb_data *data) { int c; do { - gdb_outbuf[gdb_outlen] = 0; + data->outbuf[data->outlen] = 0; #ifdef DEBUG_GDB - printf("-> %s\n", gdb_outbuf); + printf("-> %s\n", data->outbuf); #endif - if (gdb_flush() < 0) + if (gdb_flush(data) < 0) return -1; - c = gdb_getc(); + c = gdb_getc(data); if (c < 0) return -1; } while (c != '+'); @@ -152,29 +156,29 @@ static int gdb_flush_ack(void) return 0; } -static void gdb_packet_start(void) +static void gdb_packet_start(struct gdb_data *data) { - gdb_printf("$"); + gdb_printf(data, "$"); } -static void gdb_packet_end(void) +static void gdb_packet_end(struct gdb_data *data) { int i; int c = 0; - for (i = 1; i < gdb_outlen; i++) - c = (c + gdb_outbuf[i]) & 0xff; - gdb_printf("#%02x", c); + for (i = 1; i < data->outlen; i++) + c = (c + data->outbuf[i]) & 0xff; + gdb_printf(data, "#%02x", c); } -static int gdb_send_hex(const char *text) +static int gdb_send_hex(struct gdb_data *data, const char *text) { - gdb_packet_start(); + gdb_packet_start(data); while (*text) - gdb_printf("%02x", *(text++)); - gdb_packet_end(); + gdb_printf(data, "%02x", *(text++)); + gdb_packet_end(data); - return gdb_flush_ack(); + return gdb_flush_ack(data); } static int hexval(int c) @@ -189,35 +193,35 @@ static int hexval(int c) return 0; } -static int gdb_send(const char *msg) +static int gdb_send(struct gdb_data *data, const char *msg) { - gdb_packet_start(); - gdb_printf("%s", msg); - gdb_packet_end(); - return gdb_flush_ack(); + gdb_packet_start(data); + gdb_printf(data, "%s", msg); + gdb_packet_end(data); + return gdb_flush_ack(data); } /************************************************************************ * GDB server */ -static int read_registers(void) +static int read_registers(struct gdb_data *data) { u_int16_t regs[DEVICE_NUM_REGS]; int i; printf("Reading registers\n"); - if (device_get()->getregs(regs) < 0) - return gdb_send("E00"); + if (data->device->getregs(data->device, regs) < 0) + return gdb_send(data, "E00"); - gdb_packet_start(); + gdb_packet_start(data); for (i = 0; i < DEVICE_NUM_REGS; i++) - gdb_printf("%02x%02x", regs[i] & 0xff, regs[i] >> 8); - gdb_packet_end(); - return gdb_flush_ack(); + gdb_printf(data, "%02x%02x", regs[i] & 0xff, regs[i] >> 8); + gdb_packet_end(data); + return gdb_flush_ack(data); } -static int monitor_command(char *buf) +static int monitor_command(struct gdb_data *data, char *buf) { char cmd[128]; int len = 0; @@ -229,24 +233,24 @@ static int monitor_command(char *buf) if (!strcasecmp(cmd, "reset")) { printf("Resetting device\n"); - if (device_get()->control(DEVICE_CTL_RESET) < 0) - return gdb_send_hex("Reset failed\n"); + if (data->device->ctl(data->device, DEVICE_CTL_RESET) < 0) + return gdb_send_hex(data, "Reset failed\n"); } else if (!strcasecmp(cmd, "erase")) { printf("Erasing device\n"); - if (device_get()->control(DEVICE_CTL_ERASE) < 0) - return gdb_send_hex("Erase failed\n"); + if (data->device->ctl(data->device, DEVICE_CTL_ERASE) < 0) + return gdb_send_hex(data, "Erase failed\n"); } - return gdb_send("OK"); + return gdb_send(data, "OK"); } -static int write_registers(char *buf) +static int write_registers(struct gdb_data *data, char *buf) { u_int16_t regs[DEVICE_NUM_REGS]; int i; if (strlen(buf) < DEVICE_NUM_REGS * 4) - return gdb_send("E00"); + return gdb_send(data, "E00"); printf("Writing registers\n"); for (i = 0; i < DEVICE_NUM_REGS; i++) { @@ -257,13 +261,13 @@ static int write_registers(char *buf) buf += 4; } - if (device_get()->setregs(regs) < 0) - return gdb_send("E00"); + if (data->device->setregs(data->device, regs) < 0) + return gdb_send(data, "E00"); - return gdb_send("OK"); + return gdb_send(data, "OK"); } -static int read_memory(char *text) +static int read_memory(struct gdb_data *data, char *text) { char *length_text = strchr(text, ','); int length, addr; @@ -272,7 +276,7 @@ static int read_memory(char *text) if (!length_text) { fprintf(stderr, "gdb: malformed memory read request\n"); - return gdb_send("E00"); + return gdb_send(data, "E00"); } *(length_text++) = 0; @@ -285,18 +289,18 @@ static int read_memory(char *text) printf("Reading %d bytes from 0x%04x\n", length, addr); - if (device_get()->readmem(addr, buf, length) < 0) - return gdb_send("E00"); + if (data->device->readmem(data->device, addr, buf, length) < 0) + return gdb_send(data, "E00"); - gdb_packet_start(); + gdb_packet_start(data); for (i = 0; i < length; i++) - gdb_printf("%02x", buf[i]); - gdb_packet_end(); + gdb_printf(data, "%02x", buf[i]); + gdb_packet_end(data); - return gdb_flush_ack(); + return gdb_flush_ack(data); } -static int write_memory(char *text) +static int write_memory(struct gdb_data *data, char *text) { char *data_text = strchr(text, ':'); char *length_text = strchr(text, ','); @@ -306,7 +310,7 @@ static int write_memory(char *text) if (!(data_text && length_text)) { fprintf(stderr, "gdb: malformed memory write request\n"); - return gdb_send("E00"); + return gdb_send(data, "E00"); } *(data_text++) = 0; @@ -323,75 +327,76 @@ static int write_memory(char *text) if (buflen != length) { fprintf(stderr, "gdb: length mismatch\n"); - return gdb_send("E00"); + return gdb_send(data, "E00"); } printf("Writing %d bytes to 0x%04x\n", buflen, addr); - if (device_get()->writemem(addr, buf, buflen) < 0) - return gdb_send("E00"); + if (data->device->writemem(data->device, addr, buf, buflen) < 0) + return gdb_send(data, "E00"); - return gdb_send("OK"); + return gdb_send(data, "OK"); } -static int run_set_pc(char *buf) +static int run_set_pc(struct gdb_data *data, char *buf) { u_int16_t regs[DEVICE_NUM_REGS]; if (!*buf) return 0; - if (device_get()->getregs(regs) < 0) + if (data->device->getregs(data->device, regs) < 0) return -1; regs[0] = strtoul(buf, NULL, 16); - return device_get()->setregs(regs); + return data->device->setregs(data->device, regs); } -static int run_final_status(void) +static int run_final_status(struct gdb_data *data) { u_int16_t regs[DEVICE_NUM_REGS]; int i; - if (device_get()->getregs(regs) < 0) - return gdb_send("E00"); + if (data->device->getregs(data->device, regs) < 0) + return gdb_send(data, "E00"); - gdb_packet_start(); - gdb_printf("T00"); + gdb_packet_start(data); + gdb_printf(data, "T00"); for (i = 0; i < 16; i++) - gdb_printf("%02x:%02x%02x;", i, regs[i] & 0xff, regs[i] >> 8); - gdb_packet_end(); + gdb_printf(data, "%02x:%02x%02x;", i, + regs[i] & 0xff, regs[i] >> 8); + gdb_packet_end(data); - return gdb_flush_ack(); + return gdb_flush_ack(data); } -static int single_step(char *buf) +static int single_step(struct gdb_data *data, char *buf) { printf("Single stepping\n"); - if (run_set_pc(buf) < 0 || - device_get()->control(DEVICE_CTL_STEP) < 0) - gdb_send("E00"); + if (run_set_pc(data, buf) < 0 || + data->device->ctl(data->device, DEVICE_CTL_STEP) < 0) + gdb_send(data, "E00"); - return run_final_status(); + return run_final_status(data); } -static int run(char *buf) +static int run(struct gdb_data *data, char *buf) { printf("Running\n"); - if (run_set_pc(buf) < 0 || - device_get()->control(DEVICE_CTL_RUN) < 0) { - gdb_send("E00"); - return run_final_status(); + if (run_set_pc(data, buf) < 0 || + data->device->ctl(data->device, DEVICE_CTL_RUN) < 0) { + gdb_send(data, "E00"); + return run_final_status(data); } for (;;) { - device_status_t status = device_get()->wait(0); + device_status_t status = data->device->poll(data->device); if (status == DEVICE_STATUS_ERROR) { - gdb_send("E00"); - return run_final_status(); + gdb_send(data, "E00"); + return run_final_status(data); } if (status == DEVICE_STATUS_HALTED) { @@ -402,8 +407,8 @@ static int run(char *buf) if (status == DEVICE_STATUS_INTR) goto out; - while (gdb_peek()) { - int c = gdb_getc(); + while (gdb_peek(data)) { + int c = gdb_getc(data); if (c < 0) return -1; @@ -416,47 +421,47 @@ static int run(char *buf) } out: - if (device_get()->control(DEVICE_CTL_HALT) < 0) - gdb_send("E00"); + if (data->device->ctl(data->device, DEVICE_CTL_HALT) < 0) + gdb_send(data, "E00"); - return run_final_status(); + return run_final_status(data); } -static int process_gdb_command(char *buf, int len) +static int process_gdb_command(struct gdb_data *data, char *buf, int len) { switch (buf[0]) { case '?': /* Return target halt reason */ - return gdb_send("T00"); + return gdb_send(data, "T00"); case 'g': /* Read registers */ - return read_registers(); + return read_registers(data); case 'G': /* Write registers */ - return write_registers(buf + 1); + return write_registers(data, buf + 1); case 'q': /* Query */ if (!strncmp(buf, "qRcmd,", 6)) - return monitor_command(buf + 6); + return monitor_command(data, buf + 6); break; case 'm': /* Read memory */ - return read_memory(buf + 1); + return read_memory(data, buf + 1); case 'M': /* Write memory */ - return write_memory(buf + 1); + return write_memory(data, buf + 1); case 'c': /* Continue */ - return run(buf + 1); + return run(data, buf + 1); case 's': /* Single step */ - return single_step(buf + 1); + return single_step(data, buf + 1); } /* For unknown/unsupported packets, return an empty reply */ - return gdb_send(""); + return gdb_send(data, ""); } -static void gdb_reader_loop(void) +static void gdb_reader_loop(struct gdb_data *data) { for (;;) { char buf[1024]; @@ -467,14 +472,14 @@ static void gdb_reader_loop(void) /* Wait for packet start */ do { - c = gdb_getc(); + c = gdb_getc(data); if (c < 0) return; } while (c != '$'); /* Read packet payload */ while (len + 1 < sizeof(buf)) { - c = gdb_getc(); + c = gdb_getc(data); if (c < 0) return; if (c == '#') @@ -486,11 +491,11 @@ static void gdb_reader_loop(void) buf[len] = 0; /* Read packet checksum */ - c = gdb_getc(); + c = gdb_getc(data); if (c < 0) return; cksum_recv = hexval(c); - c = gdb_getc(); + c = gdb_getc(data); if (c < 0) return; cksum_recv = (cksum_recv << 4) | hexval(c); @@ -503,29 +508,30 @@ static void gdb_reader_loop(void) fprintf(stderr, "gdb: bad checksum (calc = 0x%02x, " "recv = 0x%02x)\n", cksum_calc, cksum_recv); fprintf(stderr, "gdb: packet data was: %s\n", buf); - gdb_printf("-"); - if (gdb_flush() < 0) + gdb_printf(data, "-"); + if (gdb_flush(data) < 0) return; continue; } /* Send acknowledgement */ - gdb_printf("+"); - if (gdb_flush() < 0) + gdb_printf(data, "+"); + if (gdb_flush(data) < 0) return; - if (len && process_gdb_command(buf, len) < 0) + if (len && process_gdb_command(data, buf, len) < 0) return; } } -static int gdb_server(int port) +static int gdb_server(device_t device, int port) { int sock; int client; struct sockaddr_in addr; socklen_t len; int arg; + struct gdb_data data; sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { @@ -567,15 +573,16 @@ static int gdb_server(int port) printf("Client connected from %s:%d\n", inet_ntoa(addr.sin_addr), htons(addr.sin_port)); - gdb_socket = client; - gdb_errno = 0; - gdb_head = 0; - gdb_tail = 0; - gdb_outlen = 0; + data.sock = client; + data.error = 0; + data.head = 0; + data.tail = 0; + data.outlen = 0; + data.device = device; - gdb_reader_loop(); + gdb_reader_loop(&data); - return gdb_errno ? -1 : 0; + return data.error ? -1 : 0; } static int cmd_gdb(cproc_t cp, char **arg) @@ -591,7 +598,7 @@ static int cmd_gdb(cproc_t cp, char **arg) return -1; } - return gdb_server(port); + return gdb_server(cproc_device(cp), port); } static const struct cproc_command command_gdb = { diff --git a/ihex.c b/ihex.c index 5384275..a67c68f 100644 --- a/ihex.c +++ b/ihex.c @@ -27,7 +27,8 @@ int ihex_check(FILE *in) return fgetc(in) == ':'; } -static int feed_line(FILE *in, u_int8_t *data, int nbytes, imgfunc_t cb) +static int feed_line(FILE *in, u_int8_t *data, int nbytes, imgfunc_t cb, + void *user_data) { u_int8_t cksum = 0; int i; @@ -46,11 +47,12 @@ static int feed_line(FILE *in, u_int8_t *data, int nbytes, imgfunc_t cb) return -1; } - return cb(((u_int16_t)data[1]) << 8 | ((u_int16_t)data[2]), + return cb(user_data, + ((u_int16_t)data[1]) << 8 | ((u_int16_t)data[2]), data + 4, nbytes - 5); } -int ihex_extract(FILE *in, imgfunc_t cb) +int ihex_extract(FILE *in, imgfunc_t cb, void *user_data) { char buf[128]; int lno = 0; @@ -83,7 +85,7 @@ int ihex_extract(FILE *in, imgfunc_t cb) } /* Handle the line */ - if (feed_line(in, data, nbytes, cb) < 0) { + if (feed_line(in, data, nbytes, cb, user_data) < 0) { fprintf(stderr, "ihex: error on line %d\n", lno); return -1; } diff --git a/main.c b/main.c index 9796ef2..2561d89 100644 --- a/main.c +++ b/main.c @@ -33,6 +33,78 @@ #include "sym.h" #include "devcmd.h" +#include "sim.h" +#include "bsl.h" +#include "fet.h" + +static void io_prefix(const char *prefix, u_int16_t pc, + u_int16_t addr, int is_byte) +{ + char name[64]; + + if (!stab_nearest(pc, name, sizeof(name), &pc)) { + printf("%s", name); + if (pc) + printf("+0x%x", pc); + } else { + printf("0x%04x", pc); + } + + printf(": IO %s.%c: 0x%04x", prefix, is_byte ? 'B' : 'W', addr); + if (!stab_nearest(addr, name, sizeof(name), &addr)) { + printf(" (%s", name); + if (addr) + printf("+0x%x", addr); + printf(")"); + } +} + +static int fetch_io(void *user_data, u_int16_t pc, + u_int16_t addr, int is_byte, u_int16_t *data_ret) +{ + io_prefix("READ", pc, addr, is_byte); + + for (;;) { + char text[128]; + int len; + int data; + + printf("? "); + fflush(stdout); + if (!fgets(text, sizeof(text), stdin)) { + printf("\nAborted IO request\n"); + return -1; + } + + len = strlen(text); + while (len && isspace(text[len - 1])) + len--; + text[len] = 0; + + if (!len) + return 0; + + if (!stab_exp(text, &data)) { + if (data_ret) + *data_ret = data; + return 0; + } + } + + return 0; +} + +static void store_io(void *user_data, u_int16_t pc, + u_int16_t addr, int is_byte, u_int16_t data) +{ + io_prefix("WRITE", pc, addr, is_byte); + + if (is_byte) + printf(" => 0x%02x\n", data & 0xff); + else + printf(" => 0x%04x\n", data); +} + static void usage(const char *progname) { fprintf(stderr, @@ -155,14 +227,14 @@ static int parse_cmdline_args(int argc, char **argv, return 0; } -const struct device *setup_device(const struct cmdline_args *args) +device_t setup_device(const struct cmdline_args *args) { - const struct device *msp430_dev = NULL; + device_t msp430_dev = NULL; const struct fet_transport *trans = NULL; /* Open a device */ if (args->mode == MODE_SIM) { - msp430_dev = sim_open(); + msp430_dev = sim_open(fetch_io, store_io, NULL); } else if (args->mode == MODE_UIF_BSL) { msp430_dev = bsl_open(args->bsl_device); } else if (args->mode == MODE_RF2500 || args->mode == MODE_UIF) { @@ -192,13 +264,36 @@ const struct device *setup_device(const struct cmdline_args *args) return NULL; } - device_set(msp430_dev); return msp430_dev; } +cproc_t setup_cproc(const struct cmdline_args *args) +{ + device_t msp430_dev = setup_device(args); + cproc_t cp; + + if (!msp430_dev) + return NULL; + + cp = cproc_new(msp430_dev); + if (!cp) { + msp430_dev->destroy(msp430_dev); + return NULL; + } + + if (sym_register(cp) < 0 || + devcmd_register(cp) < 0 || + gdb_register(cp) < 0 || + rtools_register(cp) < 0) { + cproc_destroy(cp); + return NULL; + } + + return cp; +} + int main(int argc, char **argv) { - const struct device *msp430_dev; struct cmdline_args args = {0}; cproc_t cp; int ret = 0; @@ -218,22 +313,9 @@ int main(int argc, char **argv) if (stab_init() < 0) return -1; - msp430_dev = setup_device(&args); - if (!msp430_dev) { - stab_exit(); - return -1; - } - - cp = cproc_new(); - if (!cp || - sym_register(cp) < 0 || - devcmd_register(cp) < 0 || - gdb_register(cp) < 0 || - rtools_register(cp) < 0) { + cp = setup_cproc(&args); + if (!cp) { perror("couldn't set up command parser"); - if (cp) - cproc_destroy(cp); - msp430_dev->close(); stab_exit(); return -1; } @@ -254,7 +336,6 @@ int main(int argc, char **argv) } cproc_destroy(cp); - msp430_dev->close(); stab_exit(); return ret; diff --git a/rtools.c b/rtools.c index 5c04615..6af106b 100644 --- a/rtools.c +++ b/rtools.c @@ -320,7 +320,7 @@ static int do_isearch(cproc_t cp, int addr, int len, const struct isearch_query *q) { u_int8_t *mbuf; - const struct device *dev = device_get(); + device_t dev = cproc_device(cp); int i; if (len <= 0 || len > 0x10000 || @@ -337,7 +337,7 @@ static int do_isearch(cproc_t cp, return -1; } - if (dev->readmem(addr, mbuf, len) < 0) { + if (dev->readmem(dev, addr, mbuf, len) < 0) { fprintf(stderr, "isearch: couldn't read device memory\n"); free(mbuf); return -1; diff --git a/sim.c b/sim.c index 770bef0..8e9b53d 100644 --- a/sim.c +++ b/sim.c @@ -23,105 +23,40 @@ #include "device.h" #include "dis.h" #include "util.h" -#include "stab.h" +#include "sim.h" #define MEM_SIZE 65536 - -static u_int8_t *memory; -static u_int16_t sim_regs[DEVICE_NUM_REGS]; - -#define MEM_GETB(offset) (memory[offset]) -#define MEM_SETB(offset, value) (memory[offset] = (value)) -#define MEM_GETW(offset) \ - (memory[offset] | (memory[(offset + 1) & 0xffff] << 8)) -#define MEM_SETW(offset, value) \ - do { \ - memory[offset] = (value) & 0xff; \ - memory[(offset + 1) & 0xffff] = (value) >> 8; \ - } while (0); - #define MEM_IO_END 0x200 -/* PC at the start of the current instruction */ -static u_int16_t current_insn; +struct sim_device { + struct device base; -static void io_prefix(const char *prefix, u_int16_t addr, int is_byte) -{ - char name[64]; - u_int16_t pc = current_insn; + sim_fetch_func_t fetch_func; + sim_store_func_t store_func; + void *user_data; - if (!stab_nearest(pc, name, sizeof(name), &pc)) { - printf("%s", name); - if (pc) - printf("+0x%x", pc); - } else { - printf("0x%04x", pc); - } + u_int8_t memory[MEM_SIZE]; + u_int16_t regs[DEVICE_NUM_REGS]; - printf(": IO %s.%c: 0x%04x", prefix, is_byte ? 'B' : 'W', addr); - if (!stab_nearest(addr, name, sizeof(name), &addr)) { - printf(" (%s", name); - if (addr) - printf("+0x%x", addr); - printf(")"); - } -} + int running; + u_int16_t current_insn; + int have_breakpoint; + u_int16_t breakpoint_addr; +}; -static int fetch_io(u_int16_t addr, int is_byte, u_int32_t *data_ret) -{ - io_prefix("READ", addr, is_byte); +#define MEM_GETB(dev, offset) ((dev)->memory[offset]) +#define MEM_SETB(dev, offset, value) ((dev)->memory[offset] = (value)) +#define MEM_GETW(dev, offset) \ + ((dev)->memory[offset] | \ + ((dev)->memory[(offset + 1) & 0xffff] << 8)) +#define MEM_SETW(dev, offset, value) \ + do { \ + (dev)->memory[offset] = (value) & 0xff; \ + (dev)->memory[(offset + 1) & 0xffff] = (value) >> 8; \ + } while (0); - for (;;) { - char text[128]; - int len; - int data; - - printf("? "); - fflush(stdout); - if (!fgets(text, sizeof(text), stdin)) { - printf("\nAborted IO request\n"); - return -1; - } - - len = strlen(text); - while (len && isspace(text[len - 1])) - len--; - text[len] = 0; - - if (!len) { - if (data_ret) { - if (is_byte) - *data_ret = MEM_GETB(addr); - else - *data_ret = MEM_GETW(addr); - } - return 0; - } - - if (!stab_exp(text, &data)) { - if (data_ret) - *data_ret = data; - return 0; - } - } - - return 0; -} - -static void store_io(u_int16_t addr, int is_byte, u_int16_t data) -{ - io_prefix("WRITE", addr, is_byte); - - if (is_byte) { - printf(" => 0x%02x\n", data & 0xff); - MEM_SETB(addr, data & 0xff); - } else { - printf(" => 0x%04x\n", data); - MEM_SETW(addr, data); - } -} - -static int fetch_operand(int amode, int reg, int is_byte, +static int fetch_operand(struct sim_device *dev, + int amode, int reg, int is_byte, u_int16_t *addr_ret, u_int32_t *data_ret) { u_int16_t addr = 0; @@ -135,7 +70,7 @@ static int fetch_operand(int amode, int reg, int is_byte, return 0; } if (data_ret) - *data_ret = sim_regs[reg] & mask; + *data_ret = dev->regs[reg] & mask; return 0; case MSP430_AMODE_INDEXED: @@ -145,11 +80,11 @@ static int fetch_operand(int amode, int reg, int is_byte, return 0; } - addr = MEM_GETW(sim_regs[MSP430_REG_PC]); - sim_regs[MSP430_REG_PC] += 2; + addr = MEM_GETW(dev, dev->regs[MSP430_REG_PC]); + dev->regs[MSP430_REG_PC] += 2; if (reg != MSP430_REG_SR) - addr += sim_regs[reg]; + addr += dev->regs[reg]; break; case MSP430_AMODE_INDIRECT: @@ -164,7 +99,7 @@ static int fetch_operand(int amode, int reg, int is_byte, *data_ret = 2; return 0; } - addr = sim_regs[reg]; + addr = dev->regs[reg]; break; case MSP430_AMODE_INDIRECT_INC: @@ -178,8 +113,8 @@ static int fetch_operand(int amode, int reg, int is_byte, *data_ret = mask; return 0; } - addr = sim_regs[reg]; - sim_regs[reg] += 2; + addr = dev->regs[reg]; + dev->regs[reg] += 2; break; } @@ -187,31 +122,42 @@ static int fetch_operand(int amode, int reg, int is_byte, *addr_ret = addr; if (data_ret) { - if (addr < MEM_IO_END) - return fetch_io(addr, is_byte, data_ret); + *data_ret = MEM_GETW(dev, addr) & mask; - *data_ret = MEM_GETW(addr) & mask; + if (addr < MEM_IO_END && dev->fetch_func) { + u_int16_t data16 = *data_ret; + int ret; + + ret = dev->fetch_func(dev->user_data, + dev->current_insn, + addr, is_byte, &data16); + *data_ret = data16; + return ret; + } } return 0; } -static void store_operand(int amode, int reg, int is_byte, +static void store_operand(struct sim_device *dev, + int amode, int reg, int is_byte, u_int16_t addr, u_int16_t data) { - if (amode == MSP430_AMODE_REGISTER) - sim_regs[reg] = data; - else if (addr < MEM_IO_END) - store_io(addr, is_byte, data); - else if (is_byte) - MEM_SETB(addr, data); + if (is_byte) + MEM_SETB(dev, addr, data); else - MEM_SETW(addr, data); + MEM_SETW(dev, addr, data); + + if (amode == MSP430_AMODE_REGISTER) + dev->regs[reg] = data; + else if (addr < MEM_IO_END && dev->store_func) + dev->store_func(dev->user_data, dev->current_insn, + addr, is_byte, data); } #define ARITH_BITS (MSP430_SR_V | MSP430_SR_N | MSP430_SR_Z | MSP430_SR_C) -static int step_double(u_int16_t ins) +static int step_double(struct sim_device *dev, u_int16_t ins) { u_int16_t opcode = ins & 0xf000; int sreg = (ins >> 8) & 0xf; @@ -226,9 +172,9 @@ static int step_double(u_int16_t ins) u_int32_t msb = is_byte ? 0x80 : 0x8000; u_int32_t mask = is_byte ? 0xff : 0xffff; - if (fetch_operand(amode_src, sreg, is_byte, NULL, &src_data) < 0) + if (fetch_operand(dev, amode_src, sreg, is_byte, NULL, &src_data) < 0) return -1; - if (fetch_operand(amode_dst, dreg, is_byte, &dst_addr, + if (fetch_operand(dev, amode_dst, dreg, is_byte, &dst_addr, opcode == MSP430_OP_MOV ? NULL : &dst_data) < 0) return -1; @@ -244,7 +190,7 @@ static int step_double(u_int16_t ins) case MSP430_OP_ADD: case MSP430_OP_ADDC: if (opcode == MSP430_OP_ADDC || opcode == MSP430_OP_SUBC) - res_data = (sim_regs[MSP430_REG_SR] & + res_data = (dev->regs[MSP430_REG_SR] & MSP430_SR_C) ? 1 : 0; else if (opcode == MSP430_OP_SUB || opcode == MSP430_OP_CMP) res_data = 1; @@ -254,42 +200,42 @@ static int step_double(u_int16_t ins) res_data += src_data; res_data += dst_data; - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; if (!(res_data & mask)) - sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; + dev->regs[MSP430_REG_SR] |= MSP430_SR_Z; if (res_data & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; if (res_data & (msb << 1)) - sim_regs[MSP430_REG_SR] |= MSP430_SR_C; + dev->regs[MSP430_REG_SR] |= MSP430_SR_C; if (!((src_data ^ dst_data) & msb) && (src_data ^ dst_data) & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_V; + dev->regs[MSP430_REG_SR] |= MSP430_SR_V; break; case MSP430_OP_DADD: res_data = src_data + dst_data; - if (sim_regs[MSP430_REG_SR] & MSP430_SR_C) + if (dev->regs[MSP430_REG_SR] & MSP430_SR_C) res_data++; - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; if (!(res_data & mask)) - sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; + dev->regs[MSP430_REG_SR] |= MSP430_SR_Z; if (res_data == 1) - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; if ((is_byte && res_data > 99) || (!is_byte && res_data > 9999)) - sim_regs[MSP430_REG_SR] |= MSP430_SR_C; + dev->regs[MSP430_REG_SR] |= MSP430_SR_C; break; case MSP430_OP_BIT: case MSP430_OP_AND: res_data = src_data & dst_data; - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; - sim_regs[MSP430_REG_SR] |= + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] |= (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z; if (res_data & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; break; case MSP430_OP_BIC: @@ -302,29 +248,30 @@ static int step_double(u_int16_t ins) case MSP430_OP_XOR: res_data = dst_data ^ src_data; - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; - sim_regs[MSP430_REG_SR] |= + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] |= (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z; if (res_data & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; if (src_data & dst_data & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_V; + dev->regs[MSP430_REG_SR] |= MSP430_SR_V; break; default: fprintf(stderr, "sim: invalid double-operand opcode: " "0x%04x (PC = 0x%04x)\n", - opcode, current_insn); + opcode, dev->current_insn); return -1; } if (opcode != MSP430_OP_CMP && opcode != MSP430_OP_BIT) - store_operand(amode_dst, dreg, is_byte, dst_addr, res_data); + store_operand(dev, amode_dst, dreg, is_byte, + dst_addr, res_data); return 0; } -static int step_single(u_int16_t ins) +static int step_single(struct sim_device *dev, u_int16_t ins) { u_int16_t opcode = ins & 0xff80; int is_byte = ins & 0x0040; @@ -336,7 +283,7 @@ static int step_single(u_int16_t ins) u_int32_t src_data; u_int32_t res_data; - if (fetch_operand(amode, reg, is_byte, &src_addr, &src_data) < 0) + if (fetch_operand(dev, amode, reg, is_byte, &src_addr, &src_data) < 0) return -1; switch (opcode) { @@ -344,19 +291,19 @@ static int step_single(u_int16_t ins) case MSP430_OP_RRA: res_data = (src_data >> 1) & ~msb; if (opcode == MSP430_OP_RRC) { - if (sim_regs[MSP430_REG_SR] & MSP430_SR_C) + if (dev->regs[MSP430_REG_SR] & MSP430_SR_C) res_data |= msb; } else { res_data |= src_data & msb; } - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; if (!(res_data & mask)) - sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; + dev->regs[MSP430_REG_SR] |= MSP430_SR_Z; if (res_data & msb) - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; if (src_data & 1) - sim_regs[MSP430_REG_SR] |= MSP430_SR_C; + dev->regs[MSP430_REG_SR] |= MSP430_SR_C; break; case MSP430_OP_SWPB: @@ -365,53 +312,56 @@ static int step_single(u_int16_t ins) case MSP430_OP_SXT: res_data = src_data & 0xff; - sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; + dev->regs[MSP430_REG_SR] &= ~ARITH_BITS; if (src_data & 0x80) { res_data |= 0xff00; - sim_regs[MSP430_REG_SR] |= MSP430_SR_N; + dev->regs[MSP430_REG_SR] |= MSP430_SR_N; } - sim_regs[MSP430_REG_SR] |= + dev->regs[MSP430_REG_SR] |= (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z; break; case MSP430_OP_PUSH: - sim_regs[MSP430_REG_SP] -= 2; - MEM_SETW(sim_regs[MSP430_REG_SP], src_data); + dev->regs[MSP430_REG_SP] -= 2; + MEM_SETW(dev, dev->regs[MSP430_REG_SP], src_data); break; case MSP430_OP_CALL: - sim_regs[MSP430_REG_SP] -= 2; - MEM_SETW(sim_regs[MSP430_REG_SP], sim_regs[MSP430_REG_PC]); - sim_regs[MSP430_REG_PC] = src_data; + dev->regs[MSP430_REG_SP] -= 2; + MEM_SETW(dev, dev->regs[MSP430_REG_SP], + dev->regs[MSP430_REG_PC]); + dev->regs[MSP430_REG_PC] = src_data; break; case MSP430_OP_RETI: - sim_regs[MSP430_REG_SR] = MEM_GETW(sim_regs[MSP430_REG_SP]); - sim_regs[MSP430_REG_SP] += 2; - sim_regs[MSP430_REG_PC] = MEM_GETW(sim_regs[MSP430_REG_SP]); - sim_regs[MSP430_REG_SP] += 2; + dev->regs[MSP430_REG_SR] = + MEM_GETW(dev, dev->regs[MSP430_REG_SP]); + dev->regs[MSP430_REG_SP] += 2; + dev->regs[MSP430_REG_PC] = + MEM_GETW(dev, dev->regs[MSP430_REG_SP]); + dev->regs[MSP430_REG_SP] += 2; break; default: fprintf(stderr, "sim: unknown single-operand opcode: 0x%04x " - "(PC = 0x%04x)\n", opcode, current_insn); + "(PC = 0x%04x)\n", opcode, dev->current_insn); return -1; } if (opcode != MSP430_OP_PUSH && opcode != MSP430_OP_CALL && opcode != MSP430_OP_RETI) - store_operand(amode, reg, is_byte, src_addr, res_data); + store_operand(dev, amode, reg, is_byte, src_addr, res_data); return 0; } -static int step_jump(u_int16_t ins) +static int step_jump(struct sim_device *dev, u_int16_t ins) { u_int16_t opcode = ins & 0xfc00; u_int16_t pc_offset = (ins & 0x03ff) << 1; - u_int16_t sr = sim_regs[MSP430_REG_SR]; + u_int16_t sr = dev->regs[MSP430_REG_SR]; if (pc_offset & 0x0400) pc_offset |= 0xff800; @@ -453,32 +403,32 @@ static int step_jump(u_int16_t ins) } if (sr) - sim_regs[MSP430_REG_PC] += pc_offset; + dev->regs[MSP430_REG_PC] += pc_offset; return 0; } -static int step_cpu(void) +static int step_cpu(struct sim_device *dev) { u_int16_t ins; int ret; /* Fetch the instruction */ - current_insn = sim_regs[MSP430_REG_PC]; - ins = MEM_GETW(current_insn); - sim_regs[MSP430_REG_PC] += 2; + dev->current_insn = dev->regs[MSP430_REG_PC]; + ins = MEM_GETW(dev, dev->current_insn); + dev->regs[MSP430_REG_PC] += 2; /* Handle different instruction types */ if ((ins & 0xf000) >= 0x4000) - ret = step_double(ins); + ret = step_double(dev, ins); else if ((ins & 0xf000) >= 0x2000) - ret = step_jump(ins); + ret = step_jump(dev, ins); else - ret = step_single(ins); + ret = step_single(dev, ins); /* If things went wrong, restart at the current instruction */ if (ret < 0) - sim_regs[MSP430_REG_PC] = current_insn; + dev->regs[MSP430_REG_PC] = dev->current_insn; return ret; } @@ -487,161 +437,155 @@ static int step_cpu(void) * Device interface */ -static enum { - RUN_HALTED = 0, - RUN_FREE, - RUN_TO_BREAKPOINT -} run_mode; - -static u_int16_t run_breakpoint; - -static void sim_close(void) +static void sim_destroy(device_t dev_base) { - if (memory) { - free(memory); - memory = NULL; - } + free(dev_base); } -static int sim_control(device_ctl_t action) +static int sim_readmem(device_t dev_base, u_int16_t addr, + u_int8_t *mem, int len) { - switch (action) { + struct sim_device *dev = (struct sim_device *)dev_base; + + if (addr + len > MEM_SIZE) + len = MEM_SIZE - addr; + + memcpy(mem, dev->memory + addr, len); + return 0; +} + +static int sim_writemem(device_t dev_base, u_int16_t addr, + const u_int8_t *mem, int len) +{ + struct sim_device *dev = (struct sim_device *)dev_base; + + if (addr + len > MEM_SIZE) + len = MEM_SIZE - addr; + + memcpy(dev->memory + addr, mem, len); + return 0; +} + +static int sim_getregs(device_t dev_base, u_int16_t *regs) +{ + struct sim_device *dev = (struct sim_device *)dev_base; + + memcpy(regs, dev->regs, sizeof(dev->regs)); + return 0; +} + +static int sim_setregs(device_t dev_base, const u_int16_t *regs) +{ + struct sim_device *dev = (struct sim_device *)dev_base; + + memcpy(dev->regs, regs, sizeof(dev->regs)); + return 0; +} + +static int sim_breakpoint(device_t dev_base, int enabled, u_int16_t addr) +{ + struct sim_device *dev = (struct sim_device *)dev_base; + + dev->have_breakpoint = enabled; + dev->breakpoint_addr = addr; + return 0; +} + +static int sim_ctl(device_t dev_base, device_ctl_t op) +{ + struct sim_device *dev = (struct sim_device *)dev_base; + + switch (op) { case DEVICE_CTL_RESET: - memset(sim_regs, 0, sizeof(sim_regs)); - sim_regs[MSP430_REG_PC] = MEM_GETW(0xfffe); + memset(dev->regs, 0, sizeof(dev->regs)); + dev->regs[MSP430_REG_PC] = MEM_GETW(dev, 0xfffe); return 0; case DEVICE_CTL_ERASE: - memset(memory, 0xff, MEM_SIZE); + memset(dev->memory, 0xff, MEM_SIZE); return 0; case DEVICE_CTL_HALT: - run_mode = RUN_HALTED; + dev->running = 0; return 0; case DEVICE_CTL_STEP: - return step_cpu(); - - case DEVICE_CTL_RUN_BP: - run_mode = RUN_TO_BREAKPOINT; - ctrlc_reset(); - return 0; + return step_cpu(dev); case DEVICE_CTL_RUN: - run_mode = RUN_FREE; - ctrlc_reset(); + dev->running = 1; return 0; } - return -1; + return 0; } -static int run_burst(void) +static device_status_t sim_poll(device_t dev_base) { - int i = 1000000; + struct sim_device *dev = (struct sim_device *)dev_base; + int count = 1000000; - while (i--) { - if (run_mode == RUN_TO_BREAKPOINT && - sim_regs[MSP430_REG_PC] == run_breakpoint) { + ctrlc_reset(); + while (dev->running && count > 0) { + if (dev->have_breakpoint && + dev->regs[MSP430_REG_PC] == dev->breakpoint_addr) { printf("Breakpoint reached\n"); - run_mode = RUN_HALTED; - return 0; + dev->running = 0; + break; } - if (sim_regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) { - run_mode = RUN_HALTED; + if (dev->regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) { printf("CPU disabled\n"); - return 0; + dev->running = 0; + break; } - if (step_cpu() < 0) { - run_mode = RUN_HALTED; - return -1; + if (step_cpu(dev) < 0) { + dev->running = 0; + return DEVICE_STATUS_ERROR; } + + if (ctrlc_check()) + return DEVICE_STATUS_INTR; + + count--; } - return 1; + return dev->running ? DEVICE_STATUS_RUNNING : DEVICE_STATUS_HALTED; } -static device_status_t sim_wait(int blocking) +device_t sim_open(sim_fetch_func_t fetch_func, + sim_store_func_t store_func, + void *user_data) { - if (run_mode != RUN_HALTED) { - do { - int ret = run_burst(); + struct sim_device *dev = malloc(sizeof(*dev)); - if (ret < 0) - return DEVICE_STATUS_ERROR; - if (!ret) - return DEVICE_STATUS_HALTED; - - if (ctrlc_check()) { - ctrlc_reset(); - return DEVICE_STATUS_INTR; - } - } while (blocking); - - return DEVICE_STATUS_RUNNING; - } - - return DEVICE_STATUS_HALTED; -} - -static int sim_breakpoint(u_int16_t addr) -{ - run_breakpoint = addr; - return 0; -} - -static int sim_getregs(u_int16_t *regs) -{ - memcpy(regs, sim_regs, sizeof(sim_regs)); - return 0; -} - -static int sim_setregs(const u_int16_t *regs) -{ - memcpy(sim_regs, regs, sizeof(sim_regs)); - return 0; -} - -static int sim_readmem(u_int16_t addr, u_int8_t *mem, int len) -{ - if (addr + len > MEM_SIZE) - len = MEM_SIZE - addr; - - memcpy(mem, memory + addr, len); - return 0; -} - -static int sim_writemem(u_int16_t addr, const u_int8_t *mem, int len) -{ - if (addr + len > MEM_SIZE) - len = MEM_SIZE - addr; - - memcpy(memory + addr, mem, len); - return 0; -} - -static const struct device sim_device = { - .close = sim_close, - .control = sim_control, - .wait = sim_wait, - .breakpoint = sim_breakpoint, - .getregs = sim_getregs, - .setregs = sim_setregs, - .readmem = sim_readmem, - .writemem = sim_writemem -}; - -const struct device *sim_open(void) -{ - memory = malloc(MEM_SIZE); - if (!memory) { - perror("sim: can't allocate memory"); + if (!dev) { + perror("can't allocate memory for simulation"); return NULL; } - memset(memory, 0xff, MEM_SIZE); + 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.ctl = sim_ctl; + dev->base.poll = sim_poll; + + dev->fetch_func = fetch_func; + dev->store_func = store_func; + dev->user_data = user_data; + + memset(dev->memory, 0xff, sizeof(dev->memory)); + memset(dev->regs, 0xff, sizeof(dev->regs)); + + dev->running = 0; + dev->current_insn = 0; + dev->have_breakpoint = 0; + dev->breakpoint_addr = 0; + printf("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE); - return &sim_device; + return (device_t)dev; } diff --git a/sim.h b/sim.h new file mode 100644 index 0000000..f2592c7 --- /dev/null +++ b/sim.h @@ -0,0 +1,40 @@ +/* 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 + */ + +#ifndef SIM_H_ +#define SIM_H_ + +#include "device.h" + +/* These function pointers should be supplied in order to allow + * the simulator to perform IO operations. If they're left blank, IO + * addresses just map to RAM. + */ +typedef int (*sim_fetch_func_t)(void *user_data, + u_int16_t pc, u_int16_t addr, + int is_byte, u_int16_t *data); + +typedef void (*sim_store_func_t)(void *user_data, + u_int16_t pc, u_int16_t addr, + int is_byte, u_int16_t data); + +/* Dummy/simulation implementation. */ +device_t sim_open(sim_fetch_func_t fetch, sim_store_func_t store, + void *user_data); + +#endif