From 7e309acdc5c4b8f562155e448a718771cc0207c0 Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Sat, 10 Apr 2010 14:35:36 +1200 Subject: [PATCH] Separated device commands. --- Makefile | 2 +- bsl.c | 10 +- devcmd.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++ devcmd.h | 25 ++ device.c | 692 ++++++------------------------------------------------- device.h | 10 +- dis.c | 28 +-- dis.h | 6 +- fet.c | 34 +-- gdb.c | 26 +-- main.c | 17 +- rtools.c | 2 +- sym.h | 2 - util.c | 60 ----- util.h | 2 - 15 files changed, 822 insertions(+), 747 deletions(-) create mode 100644 devcmd.c create mode 100644 devcmd.h diff --git a/Makefile b/Makefile index 9fe4b62..8a3c168 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ install: mspdebug mspdebug.man .SUFFIXES: .c .o mspdebug: main.o fet.o rf2500.o dis.o uif.o ihex.o elf32.o stab.o util.o \ - bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o sym.o + bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o sym.o devcmd.o $(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/bsl.c b/bsl.c index 48719bd..c02f170 100644 --- a/bsl.c +++ b/bsl.c @@ -307,6 +307,9 @@ static int enter_via_fet(void) const struct device *bsl_open(const char *device) { + 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", @@ -330,7 +333,12 @@ const struct device *bsl_open(const char *device) return NULL; } - print_devid((reply_buf[4] << 8) | reply_buf[5]); + id = (reply_buf[4] << 8) | reply_buf[5]; + if (find_device_id(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; } diff --git a/devcmd.c b/devcmd.c new file mode 100644 index 0000000..e51cd4d --- /dev/null +++ b/devcmd.c @@ -0,0 +1,653 @@ +/* MSPDebug - debugging tool for the eZ430 + * 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 +#include +#include +#include +#include +#include +#include "device.h" +#include "binfile.h" +#include "stab.h" +#include "util.h" +#include "dis.h" + +#define REG_COLUMNS 4 +#define REG_ROWS ((DEVICE_NUM_REGS + REG_COLUMNS - 1) / REG_COLUMNS) + +static void show_regs(u_int16_t *regs) +{ + int i; + + for (i = 0; i < REG_ROWS; i++) { + int j; + + printf(" "); + for (j = 0; j < REG_COLUMNS; j++) { + int k = j * REG_ROWS + i; + + if (k < DEVICE_NUM_REGS) + printf("(r%02d: %04x) ", k, regs[k]); + } + printf("\n"); + } +} + +static int cmd_regs(char **arg) +{ + u_int16_t regs[DEVICE_NUM_REGS]; + u_int8_t code[16]; + + if (device_get()->getregs(regs) < 0) + return -1; + show_regs(regs); + + /* Try to disassemble the instruction at PC */ + if (device_get()->readmem(regs[0], code, sizeof(code)) < 0) + return 0; + + disassemble(regs[0], (u_int8_t *)code, sizeof(code)); + return 0; +} + +static struct command command_regs = { + .name = "regs", + .func = cmd_regs, + .help = + "regs\n" + " Read and display the current register contents.\n" +}; + +static int cmd_md(char **arg) +{ + char *off_text = get_arg(arg); + char *len_text = get_arg(arg); + int offset = 0; + int length = 0x40; + + if (!off_text) { + fprintf(stderr, "md: offset must be specified\n"); + return -1; + } + + if (addr_exp(off_text, &offset) < 0) { + fprintf(stderr, "md: can't parse offset: %s\n", off_text); + return -1; + } + + if (len_text) { + if (addr_exp(len_text, &length) < 0) { + fprintf(stderr, "md: can't parse length: %s\n", + len_text); + return -1; + } + } else if (offset + length > 0x10000) { + length = 0x10000 - offset; + } + + if (offset < 0 || length <= 0 || (offset + length) > 0x10000) { + fprintf(stderr, "md: memory out of range\n"); + return -1; + } + + while (length) { + u_int8_t buf[128]; + int blen = length > sizeof(buf) ? sizeof(buf) : length; + + if (device_get()->readmem(offset, buf, blen) < 0) + return -1; + hexdump(offset, buf, blen); + + offset += blen; + length -= blen; + } + + return 0; +} + +static struct command command_md = { + .name = "md", + .func = cmd_md, + .help = + "md
[length]\n" + " Read the specified number of bytes from memory at the given\n" + " address, and display a hexdump.\n" +}; + +static int cmd_mw(char **arg) +{ + char *off_text = get_arg(arg); + char *byte_text; + int offset = 0; + int length = 0; + u_int8_t buf[1024]; + + if (!off_text) { + fprintf(stderr, "md: offset must be specified\n"); + return -1; + } + + if (addr_exp(off_text, &offset) < 0) { + fprintf(stderr, "md: can't parse offset: %s\n", off_text); + return -1; + } + + while ((byte_text = get_arg(arg))) { + if (length >= sizeof(buf)) { + fprintf(stderr, "md: maximum length exceeded\n"); + return -1; + } + + buf[length++] = strtoul(byte_text, NULL, 16); + } + + if (!length) + return 0; + + if (offset < 0 || (offset + length) > 0x10000) { + fprintf(stderr, "md: memory out of range\n"); + return -1; + } + + if (device_get()->writemem(offset, buf, length) < 0) + return -1; + + return 0; +} + +static struct command command_mw = { + .name = "mw", + .func = cmd_mw, + .help = + "mw
bytes ...\n" + " Write a sequence of bytes to a memory address. Byte values are\n" + " two-digit hexadecimal numbers.\n" +}; + +static int cmd_reset(char **arg) +{ + return device_get()->control(DEVICE_CTL_RESET); +} + +static struct command command_reset = { + .name = "reset", + .func = cmd_reset, + .help = + "reset\n" + " Reset (and halt) the CPU.\n" +}; + +static int cmd_erase(char **arg) +{ + if (device_get()->control(DEVICE_CTL_HALT) < 0) + return -1; + + printf("Erasing...\n"); + return device_get()->control(DEVICE_CTL_ERASE); +} + +static struct command command_erase = { + .name = "erase", + .func = cmd_erase, + .help = + "erase\n" + " Erase the device under test.\n" +}; + +static int cmd_step(char **arg) +{ + char *count_text = get_arg(arg); + int count = 1; + + if (count_text) + count = atoi(count_text); + + while (count > 0) { + if (device_get()->control(DEVICE_CTL_STEP) < 0) + return -1; + count--; + } + + return cmd_regs(NULL); +} + +static struct command command_step = { + .name = "step", + .func = cmd_step, + .help = + "step [count]\n" + " Single-step the CPU, and display the register state.\n" +}; + +static int cmd_run(char **arg) +{ + char *bp_text = get_arg(arg); + int bp_addr; + device_status_t status; + + if (bp_text) { + if (addr_exp(bp_text, &bp_addr) < 0) { + fprintf(stderr, "run: can't parse breakpoint: %s\n", + bp_text); + return -1; + } + + device_get()->breakpoint(bp_addr); + } + + if (device_get()->control(bp_text ? + DEVICE_CTL_RUN_BP : DEVICE_CTL_RUN) < 0) + return -1; + + if (bp_text) + printf("Running to 0x%04x.", bp_addr); + else + printf("Running."); + printf(" Press Ctrl+C to interrupt...\n"); + + status = device_get()->wait(1); + if (status == DEVICE_STATUS_INTR) + printf("\n"); + + if (device_get()->control(DEVICE_CTL_HALT) < 0) + return -1; + + return cmd_regs(NULL); +} + +static struct command command_run = { + .name = "run", + .func = cmd_run, + .help = + "run [breakpoint]\n" + " Run the CPU until either a specified breakpoint occurs or the\n" + " command is interrupted.\n" +}; + +static int cmd_set(char **arg) +{ + char *reg_text = get_arg(arg); + char *val_text = get_arg(arg); + int reg; + int value = 0; + u_int16_t regs[DEVICE_NUM_REGS]; + + if (!(reg_text && val_text)) { + fprintf(stderr, "set: must specify a register and a value\n"); + return -1; + } + + while (*reg_text && !isdigit(*reg_text)) + reg_text++; + reg = atoi(reg_text); + + if (addr_exp(val_text, &value) < 0) { + fprintf(stderr, "set: can't parse value: %s\n", val_text); + return -1; + } + + if (reg < 0 || reg >= DEVICE_NUM_REGS) { + fprintf(stderr, "set: register out of range: %d\n", reg); + return -1; + } + + if (device_get()->getregs(regs) < 0) + return -1; + regs[reg] = value; + if (device_get()->setregs(regs) < 0) + return -1; + + show_regs(regs); + return 0; +} + +static struct command command_set = { + .name = "set", + .func = cmd_set, + .help = + "set \n" + " Change the value of a CPU register.\n" +}; + +static int cmd_dis(char **arg) +{ + char *off_text = get_arg(arg); + char *len_text = get_arg(arg); + int offset = 0; + int length = 0x40; + u_int8_t buf[4096]; + + if (!off_text) { + fprintf(stderr, "dis: offset must be specified\n"); + return -1; + } + + if (addr_exp(off_text, &offset) < 0) { + fprintf(stderr, "dis: can't parse offset: %s\n", off_text); + return -1; + } + + if (len_text) { + if (addr_exp(len_text, &length) < 0) { + fprintf(stderr, "dis: can't parse length: %s\n", + len_text); + return -1; + } + } else if (offset + length > 0x10000) { + length = 0x10000 - offset; + } + + if (offset < 0 || length <= 0 || length > sizeof(buf) || + (offset + length) > 0x10000) { + fprintf(stderr, "dis: memory out of range\n"); + return -1; + } + + if (device_get()->readmem(offset, buf, length) < 0) + return -1; + + disassemble(offset, (u_int8_t *)buf, length); + return 0; +} + +static struct command command_dis = { + .name = "dis", + .func = cmd_dis, + .help = + "dis
[length]\n" + " Disassemble a section of memory.\n" +}; + +static FILE *hexout_file; +static u_int16_t hexout_addr; +static u_int8_t hexout_buf[16]; +static int hexout_len; + +static int hexout_start(const char *filename) +{ + hexout_file = fopen(filename, "w"); + if (!hexout_file) { + perror("hexout: couldn't open output file"); + return -1; + } + + return 0; +} + +static int hexout_flush(void) +{ + int i; + int cksum = 0; + + if (!hexout_len) + return 0; + + if (fprintf(hexout_file, ":%02X%04X00", hexout_len, hexout_addr) < 0) + goto fail; + cksum += hexout_len; + cksum += hexout_addr & 0xff; + cksum += hexout_addr >> 8; + + for (i = 0; i < hexout_len; i++) { + if (fprintf(hexout_file, "%02X", hexout_buf[i]) < 0) + goto fail; + cksum += hexout_buf[i]; + } + + if (fprintf(hexout_file, "%02X\n", ~(cksum - 1) & 0xff) < 0) + goto fail; + + hexout_len = 0; + return 0; + +fail: + perror("hexout: can't write HEX data"); + return -1; +} + +static int hexout_feed(u_int16_t addr, const u_int8_t *buf, int len) +{ + while (len) { + int count; + + if ((hexout_addr + hexout_len != addr || + hexout_len >= sizeof(hexout_buf)) && + hexout_flush() < 0) + return -1; + + if (!hexout_len) + hexout_addr = addr; + + count = sizeof(hexout_buf) - hexout_len; + if (count > len) + count = len; + + memcpy(hexout_buf + hexout_len, buf, count); + hexout_len += count; + + addr += count; + buf += count; + len -= count; + } + + return 0; +} + +static int cmd_hexout(char **arg) +{ + char *off_text = get_arg(arg); + char *len_text = get_arg(arg); + char *filename = *arg; + int off; + int length; + + if (!(off_text && len_text && *filename)) { + fprintf(stderr, "hexout: need offset, length and filename\n"); + return -1; + } + + if (addr_exp(off_text, &off) < 0 || + addr_exp(len_text, &length) < 0) + return -1; + + if (hexout_start(filename) < 0) + return -1; + + while (length) { + u_int8_t buf[128]; + int count = length; + + if (count > sizeof(buf)) + count = sizeof(buf); + + printf("Reading %d bytes from 0x%04x...\n", count, off); + if (device_get()->readmem(off, buf, count) < 0) { + perror("hexout: can't read memory"); + goto fail; + } + + if (hexout_feed(off, buf, count) < 0) + goto fail; + + length -= count; + off += count; + } + + if (hexout_flush() < 0) + goto fail; + if (fclose(hexout_file) < 0) { + perror("hexout: error on close"); + return -1; + } + + return 0; + +fail: + fclose(hexout_file); + unlink(filename); + return -1; +} + +static struct command command_hexout = { + .name = "hexout", + .func = cmd_hexout, + .help = + "hexout
\n" + " Save a region of memory into a HEX file.\n" +}; + +static u_int8_t prog_buf[128]; +static u_int16_t prog_addr; +static int prog_len; +static int prog_have_erased; + +static void prog_init(void) +{ + prog_len = 0; + prog_have_erased = 0; +} + +static int prog_flush(void) +{ + 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_have_erased) { + printf("Erasing...\n"); + if (device_get()->control(DEVICE_CTL_ERASE) < 0) + return -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) + return -1; + + 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) +{ + /* Flush if this section is discontiguous */ + if (prog_len && prog_addr + prog_len != addr && prog_flush() < 0) + return -1; + + 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; + + if (count > len) + count = len; + + if (!count) { + if (prog_flush() < 0) + return -1; + } else { + memcpy(prog_buf + prog_len, data, count); + prog_len += count; + data += count; + len -= count; + } + } + + return 0; +} + +static int cmd_prog(char **arg) +{ + FILE *in; + int result = 0; + + if (modify_prompt(MODIFY_SYMS)) + return 0; + + in = fopen(*arg, "r"); + if (!in) { + fprintf(stderr, "prog: %s: %s\n", *arg, strerror(errno)); + return -1; + } + + if (device_get()->control(DEVICE_CTL_HALT) < 0) { + fclose(in); + return -1; + } + + prog_init(); + + if (elf32_check(in)) { + result = elf32_extract(in, prog_feed); + stab_clear(); + elf32_syms(in, stab_set); + } else if (ihex_check(in)) { + result = ihex_extract(in, prog_feed); + } else { + fprintf(stderr, "prog: %s: unknown file type\n", *arg); + } + + fclose(in); + + if (prog_flush() < 0) + return -1; + + if (device_get()->control(DEVICE_CTL_RESET) < 0) { + fprintf(stderr, "prog: failed to reset after programming\n"); + return -1; + } + + modify_clear(MODIFY_SYMS); + return result; +} + +static struct command command_prog = { + .name = "prog", + .func = cmd_prog, + .help = + "prog \n" + " Erase the device and flash the data contained in a binary file.\n" + " This command also loads symbols from the file, if available.\n" +}; + +void devcmd_init(void) +{ + register_command(&command_md); + register_command(&command_mw); + register_command(&command_reset); + register_command(&command_erase); + register_command(&command_regs); + register_command(&command_run); + register_command(&command_step); + register_command(&command_set); + register_command(&command_dis); + register_command(&command_hexout); + register_command(&command_prog); +} diff --git a/devcmd.h b/devcmd.h new file mode 100644 index 0000000..c5a3815 --- /dev/null +++ b/devcmd.h @@ -0,0 +1,25 @@ +/* MSPDebug - debugging tool for the eZ430 + * 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 DEVCMD_H_ +#define DEVCMD_H_ + +/* Register device commands */ +void devcmd_init(void); + +#endif diff --git a/device.c b/device.c index 45277e6..91a2377 100644 --- a/device.c +++ b/device.c @@ -30,639 +30,79 @@ static const struct device *msp430_dev; -#define REG_COLUMNS 4 -#define REG_ROWS ((DEVICE_NUM_REGS + REG_COLUMNS - 1) / REG_COLUMNS) - -static void show_regs(u_int16_t *regs) -{ - int i; - - for (i = 0; i < REG_ROWS; i++) { - int j; - - printf(" "); - for (j = 0; j < REG_COLUMNS; j++) { - int k = j * REG_ROWS + i; - - if (k < DEVICE_NUM_REGS) - printf("(r%02d: %04x) ", k, regs[k]); - } - printf("\n"); - } -} - -static int cmd_regs(char **arg) -{ - u_int16_t regs[DEVICE_NUM_REGS]; - u_int8_t code[16]; - - if (msp430_dev->getregs(regs) < 0) - return -1; - show_regs(regs); - - /* Try to disassemble the instruction at PC */ - if (msp430_dev->readmem(regs[0], code, sizeof(code)) < 0) - return 0; - - disassemble(regs[0], (u_int8_t *)code, sizeof(code)); - return 0; -} - -static struct command command_regs = { - .name = "regs", - .func = cmd_regs, - .help = - "regs\n" - " Read and display the current register contents.\n" -}; - -static int cmd_md(char **arg) -{ - char *off_text = get_arg(arg); - char *len_text = get_arg(arg); - int offset = 0; - int length = 0x40; - - if (!off_text) { - fprintf(stderr, "md: offset must be specified\n"); - return -1; - } - - if (addr_exp(off_text, &offset) < 0) { - fprintf(stderr, "md: can't parse offset: %s\n", off_text); - return -1; - } - - if (len_text) { - if (addr_exp(len_text, &length) < 0) { - fprintf(stderr, "md: can't parse length: %s\n", - len_text); - return -1; - } - } else if (offset + length > 0x10000) { - length = 0x10000 - offset; - } - - if (offset < 0 || length <= 0 || (offset + length) > 0x10000) { - fprintf(stderr, "md: memory out of range\n"); - return -1; - } - - while (length) { - u_int8_t buf[128]; - int blen = length > sizeof(buf) ? sizeof(buf) : length; - - if (msp430_dev->readmem(offset, buf, blen) < 0) - return -1; - hexdump(offset, buf, blen); - - offset += blen; - length -= blen; - } - - return 0; -} - -static struct command command_md = { - .name = "md", - .func = cmd_md, - .help = - "md
[length]\n" - " Read the specified number of bytes from memory at the given\n" - " address, and display a hexdump.\n" -}; - -static int cmd_mw(char **arg) -{ - char *off_text = get_arg(arg); - char *byte_text; - int offset = 0; - int length = 0; - u_int8_t buf[1024]; - - if (!off_text) { - fprintf(stderr, "md: offset must be specified\n"); - return -1; - } - - if (addr_exp(off_text, &offset) < 0) { - fprintf(stderr, "md: can't parse offset: %s\n", off_text); - return -1; - } - - while ((byte_text = get_arg(arg))) { - if (length >= sizeof(buf)) { - fprintf(stderr, "md: maximum length exceeded\n"); - return -1; - } - - buf[length++] = strtoul(byte_text, NULL, 16); - } - - if (!length) - return 0; - - if (offset < 0 || (offset + length) > 0x10000) { - fprintf(stderr, "md: memory out of range\n"); - return -1; - } - - if (msp430_dev->writemem(offset, buf, length) < 0) - return -1; - - return 0; -} - -static struct command command_mw = { - .name = "mw", - .func = cmd_mw, - .help = - "mw
bytes ...\n" - " Write a sequence of bytes to a memory address. Byte values are\n" - " two-digit hexadecimal numbers.\n" -}; - -static int cmd_reset(char **arg) -{ - return msp430_dev->control(DEVICE_CTL_RESET); -} - -static struct command command_reset = { - .name = "reset", - .func = cmd_reset, - .help = - "reset\n" - " Reset (and halt) the CPU.\n" -}; - -static int cmd_erase(char **arg) -{ - if (msp430_dev->control(DEVICE_CTL_HALT) < 0) - return -1; - - printf("Erasing...\n"); - return msp430_dev->control(DEVICE_CTL_ERASE); -} - -static struct command command_erase = { - .name = "erase", - .func = cmd_erase, - .help = - "erase\n" - " Erase the device under test.\n" -}; - -static int cmd_step(char **arg) -{ - char *count_text = get_arg(arg); - int count = 1; - - if (count_text) - count = atoi(count_text); - - while (count > 0) { - if (msp430_dev->control(DEVICE_CTL_STEP) < 0) - return -1; - count--; - } - - return cmd_regs(NULL); -} - -static struct command command_step = { - .name = "step", - .func = cmd_step, - .help = - "step [count]\n" - " Single-step the CPU, and display the register state.\n" -}; - -static int cmd_run(char **arg) -{ - char *bp_text = get_arg(arg); - int bp_addr; - device_status_t status; - - if (bp_text) { - if (addr_exp(bp_text, &bp_addr) < 0) { - fprintf(stderr, "run: can't parse breakpoint: %s\n", - bp_text); - return -1; - } - - msp430_dev->breakpoint(bp_addr); - } - - if (msp430_dev->control(bp_text ? - DEVICE_CTL_RUN_BP : DEVICE_CTL_RUN) < 0) - return -1; - - if (bp_text) - printf("Running to 0x%04x.", bp_addr); - else - printf("Running."); - printf(" Press Ctrl+C to interrupt...\n"); - - status = msp430_dev->wait(1); - if (status == DEVICE_STATUS_INTR) - printf("\n"); - - if (msp430_dev->control(DEVICE_CTL_HALT) < 0) - return -1; - - return cmd_regs(NULL); -} - -static struct command command_run = { - .name = "run", - .func = cmd_run, - .help = - "run [breakpoint]\n" - " Run the CPU until either a specified breakpoint occurs or the\n" - " command is interrupted.\n" -}; - -static int cmd_set(char **arg) -{ - char *reg_text = get_arg(arg); - char *val_text = get_arg(arg); - int reg; - int value = 0; - u_int16_t regs[DEVICE_NUM_REGS]; - - if (!(reg_text && val_text)) { - fprintf(stderr, "set: must specify a register and a value\n"); - return -1; - } - - while (*reg_text && !isdigit(*reg_text)) - reg_text++; - reg = atoi(reg_text); - - if (addr_exp(val_text, &value) < 0) { - fprintf(stderr, "set: can't parse value: %s\n", val_text); - return -1; - } - - if (reg < 0 || reg >= DEVICE_NUM_REGS) { - fprintf(stderr, "set: register out of range: %d\n", reg); - return -1; - } - - if (msp430_dev->getregs(regs) < 0) - return -1; - regs[reg] = value; - if (msp430_dev->setregs(regs) < 0) - return -1; - - show_regs(regs); - return 0; -} - -static struct command command_set = { - .name = "set", - .func = cmd_set, - .help = - "set \n" - " Change the value of a CPU register.\n" -}; - -static int cmd_dis(char **arg) -{ - char *off_text = get_arg(arg); - char *len_text = get_arg(arg); - int offset = 0; - int length = 0x40; - u_int8_t buf[4096]; - - if (!off_text) { - fprintf(stderr, "dis: offset must be specified\n"); - return -1; - } - - if (addr_exp(off_text, &offset) < 0) { - fprintf(stderr, "dis: can't parse offset: %s\n", off_text); - return -1; - } - - if (len_text) { - if (addr_exp(len_text, &length) < 0) { - fprintf(stderr, "dis: can't parse length: %s\n", - len_text); - return -1; - } - } else if (offset + length > 0x10000) { - length = 0x10000 - offset; - } - - if (offset < 0 || length <= 0 || length > sizeof(buf) || - (offset + length) > 0x10000) { - fprintf(stderr, "dis: memory out of range\n"); - return -1; - } - - if (msp430_dev->readmem(offset, buf, length) < 0) - return -1; - - disassemble(offset, (u_int8_t *)buf, length); - return 0; -} - -static struct command command_dis = { - .name = "dis", - .func = cmd_dis, - .help = - "dis
[length]\n" - " Disassemble a section of memory.\n" -}; - -static FILE *hexout_file; -static u_int16_t hexout_addr; -static u_int8_t hexout_buf[16]; -static int hexout_len; - -static int hexout_start(const char *filename) -{ - hexout_file = fopen(filename, "w"); - if (!hexout_file) { - perror("hexout: couldn't open output file"); - return -1; - } - - return 0; -} - -static int hexout_flush(void) -{ - int i; - int cksum = 0; - - if (!hexout_len) - return 0; - - if (fprintf(hexout_file, ":%02X%04X00", hexout_len, hexout_addr) < 0) - goto fail; - cksum += hexout_len; - cksum += hexout_addr & 0xff; - cksum += hexout_addr >> 8; - - for (i = 0; i < hexout_len; i++) { - if (fprintf(hexout_file, "%02X", hexout_buf[i]) < 0) - goto fail; - cksum += hexout_buf[i]; - } - - if (fprintf(hexout_file, "%02X\n", ~(cksum - 1) & 0xff) < 0) - goto fail; - - hexout_len = 0; - return 0; - -fail: - perror("hexout: can't write HEX data"); - return -1; -} - -static int hexout_feed(u_int16_t addr, const u_int8_t *buf, int len) -{ - while (len) { - int count; - - if ((hexout_addr + hexout_len != addr || - hexout_len >= sizeof(hexout_buf)) && - hexout_flush() < 0) - return -1; - - if (!hexout_len) - hexout_addr = addr; - - count = sizeof(hexout_buf) - hexout_len; - if (count > len) - count = len; - - memcpy(hexout_buf + hexout_len, buf, count); - hexout_len += count; - - addr += count; - buf += count; - len -= count; - } - - return 0; -} - -static int cmd_hexout(char **arg) -{ - char *off_text = get_arg(arg); - char *len_text = get_arg(arg); - char *filename = *arg; - int off; - int length; - - if (!(off_text && len_text && *filename)) { - fprintf(stderr, "hexout: need offset, length and filename\n"); - return -1; - } - - if (addr_exp(off_text, &off) < 0 || - addr_exp(len_text, &length) < 0) - return -1; - - if (hexout_start(filename) < 0) - return -1; - - while (length) { - u_int8_t buf[128]; - int count = length; - - if (count > sizeof(buf)) - count = sizeof(buf); - - printf("Reading %d bytes from 0x%04x...\n", count, off); - if (msp430_dev->readmem(off, buf, count) < 0) { - perror("hexout: can't read memory"); - goto fail; - } - - if (hexout_feed(off, buf, count) < 0) - goto fail; - - length -= count; - off += count; - } - - if (hexout_flush() < 0) - goto fail; - if (fclose(hexout_file) < 0) { - perror("hexout: error on close"); - return -1; - } - - return 0; - -fail: - fclose(hexout_file); - unlink(filename); - return -1; -} - -static struct command command_hexout = { - .name = "hexout", - .func = cmd_hexout, - .help = - "hexout
\n" - " Save a region of memory into a HEX file.\n" -}; - -static u_int8_t prog_buf[128]; -static u_int16_t prog_addr; -static int prog_len; -static int prog_have_erased; - -static void prog_init(void) -{ - prog_len = 0; - prog_have_erased = 0; -} - -static int prog_flush(void) -{ - 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_have_erased) { - printf("Erasing...\n"); - if (device_active()->control(DEVICE_CTL_ERASE) < 0) - return -1; - prog_have_erased = 1; - } - - printf("Writing %3d bytes to %04x...\n", wlen, prog_addr); - if (device_active()->writemem(prog_addr, prog_buf, wlen) < 0) - return -1; - - 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) -{ - /* Flush if this section is discontiguous */ - if (prog_len && prog_addr + prog_len != addr && prog_flush() < 0) - return -1; - - 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; - - if (count > len) - count = len; - - if (!count) { - if (prog_flush() < 0) - return -1; - } else { - memcpy(prog_buf + prog_len, data, count); - prog_len += count; - data += count; - len -= count; - } - } - - return 0; -} - -static int cmd_prog(char **arg) -{ - FILE *in; - int result = 0; - - if (modify_prompt(MODIFY_SYMS)) - return 0; - - in = fopen(*arg, "r"); - if (!in) { - fprintf(stderr, "prog: %s: %s\n", *arg, strerror(errno)); - return -1; - } - - if (device_active()->control(DEVICE_CTL_HALT) < 0) { - fclose(in); - return -1; - } - - prog_init(); - - if (elf32_check(in)) { - result = elf32_extract(in, prog_feed); - stab_clear(); - elf32_syms(in, stab_set); - } else if (ihex_check(in)) { - result = ihex_extract(in, prog_feed); - } else { - fprintf(stderr, "prog: %s: unknown file type\n", *arg); - } - - fclose(in); - - if (prog_flush() < 0) - return -1; - - if (device_active()->control(DEVICE_CTL_RESET) < 0) { - fprintf(stderr, "prog: failed to reset after programming\n"); - return -1; - } - - modify_clear(MODIFY_SYMS); - return result; -} - -static struct command command_prog = { - .name = "prog", - .func = cmd_prog, - .help = - "prog \n" - " Erase the device and flash the data contained in a binary file.\n" - " This command also loads symbols from the file, if available.\n" -}; - -void device_init(const struct device *dev) +void device_set(const struct device *dev) { msp430_dev = dev; - - register_command(&command_md); - register_command(&command_mw); - register_command(&command_reset); - register_command(&command_erase); - register_command(&command_regs); - register_command(&command_run); - register_command(&command_step); - register_command(&command_set); - register_command(&command_dis); - register_command(&command_hexout); - register_command(&command_prog); } -const struct device *device_active(void) +const struct device *device_get(void) { return msp430_dev; } -void device_exit(void) +/* This table of device IDs is sourced mainly from the MSP430 Memory + * Programming User's Guide (SLAU265). + * + * The table should be kept sorted by device ID. + */ + +static struct { + u_int16_t id; + const char *id_text; +} id_table[] = { + {0x1132, "F1122"}, + {0x1132, "F1132"}, + {0x1232, "F1222"}, + {0x1232, "F1232"}, + {0xF112, "F11x"}, /* obsolete */ + {0xF112, "F11x1"}, /* obsolete */ + {0xF112, "F11x1A"}, /* obsolete */ + {0xF123, "F122"}, + {0xF123, "F123x"}, + {0xF143, "F14x"}, + {0xF149, "F13x"}, + {0xF149, "F14x1"}, + {0xF149, "F149"}, + {0xF169, "F16x"}, + {0xF16C, "F161x"}, + {0xF201, "F20x3"}, + {0xF213, "F21x1"}, + {0xF227, "F22xx"}, + {0xF249, "F24x"}, + {0xF26F, "F261x"}, + {0xF413, "F41x"}, + {0xF427, "FE42x"}, + {0xF427, "FW42x"}, + {0xF427, "F415"}, + {0xF427, "F417"}, + {0xF427, "F42x0"}, + {0xF439, "FG43x"}, + {0xF449, "F43x"}, + {0xF449, "F44x"}, + {0xF46F, "FG46xx"}, + {0xF46F, "F471xx"} +}; + +int find_device_id(u_int16_t id, char *out, int max_len) { - if (msp430_dev) - msp430_dev->close(); + int i = 0; + int len; + + while (i < ARRAY_LEN(id_table) && id_table[i].id != id) + i++; + + if (i >= ARRAY_LEN(id_table)) + return -1; + + len = snprintf(out, max_len, "MSP430%s", id_table[i++].id_text); + out += len; + max_len -= len; + + while (id_table[i].id == id) { + len = snprintf(out, max_len, "MSP430%s", id_table[i++].id_text); + out += len; + max_len -= len; + } + + return 0; } diff --git a/device.h b/device.h index be21ba6..0864ca8 100644 --- a/device.h +++ b/device.h @@ -64,9 +64,11 @@ const struct device *bsl_open(const char *device); /* Dummy/simulation implementation. */ const struct device *sim_open(void); -/* Register device commands */ -void device_init(const struct device *dev); -void device_exit(void); -const struct device *device_active(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); #endif diff --git a/dis.c b/dis.c index c5b6f99..a61403e 100644 --- a/dis.c +++ b/dis.c @@ -697,6 +697,20 @@ static void dis_format(const struct msp430_instruction *insn) insn->dst_reg); } +int dis_opcode_by_name(const char *name, msp430_op_t *op) +{ + int i; + + for (i = 0; i < ARRAY_LEN(opcode_names); i++) + if (!strcasecmp(name, opcode_names[i].mnemonic)) { + if (op) + *op = opcode_names[i].op; + return 0; + } + + return -1; +} + void disassemble(u_int16_t offset, u_int8_t *data, int length) { int first_line = 1; @@ -746,17 +760,3 @@ void disassemble(u_int16_t offset, u_int8_t *data, int length) data += count; } } - -int dis_opcode_by_name(const char *name, msp430_op_t *op) -{ - int i; - - for (i = 0; i < ARRAY_LEN(opcode_names); i++) - if (!strcasecmp(name, opcode_names[i].mnemonic)) { - if (op) - *op = opcode_names[i].op; - return 0; - } - - return -1; -} diff --git a/dis.h b/dis.h index 1a232d7..0d435bf 100644 --- a/dis.h +++ b/dis.h @@ -205,10 +205,10 @@ struct msp430_instruction { int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len, struct msp430_instruction *insn); -/* Print a disassembly on stdout */ -void disassemble(u_int16_t offset, u_int8_t *buf, int length); - /* Look up an opcode by name. Returns 0 if successful, -1 otherwise. */ int dis_opcode_by_name(const char *name, msp430_op_t *op); +/* Print a disassembly on stdout */ +void disassemble(u_int16_t offset, u_int8_t *buf, int length); + #endif diff --git a/fet.c b/fet.c index a193e7e..c249ea3 100644 --- a/fet.c +++ b/fet.c @@ -515,9 +515,9 @@ static int fet_version; static int do_identify(void) { - if (fet_version < 20300000) { - char idtext[64]; + char idtext[64]; + if (fet_version < 20300000) { if (xfer(C_IDENTIFY, NULL, 0, 2, 70, 0) < 0) return -1; @@ -528,19 +528,27 @@ static int do_identify(void) memcpy(idtext, fet_reply.data + 4, 32); idtext[32] = 0; - printf("Device: %s\n", idtext); - return 0; + } else { + u_int16_t id; + + if (xfer(0x28, NULL, 0, 2, 0, 0) < 0) { + fprintf(stderr, "fet: command 0x28 failed\n"); + return -1; + } + + if (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) { + printf("Unknown device ID: 0x%04x\n", id); + return 0; + } } - if (xfer(0x28, NULL, 0, 2, 0, 0) < 0) - return -1; - - if (fet_reply.datalen < 2) { - fprintf(stderr, "fet: missing info\n"); - return -1; - } - - print_devid((fet_reply.data[0] << 8) | fet_reply.data[1]); + printf("Device: %s\n", idtext); return 0; } diff --git a/gdb.c b/gdb.c index ca06e0f..497a360 100644 --- a/gdb.c +++ b/gdb.c @@ -207,7 +207,7 @@ static int read_registers(void) int i; printf("Reading registers\n"); - if (device_active()->getregs(regs) < 0) + if (device_get()->getregs(regs) < 0) return gdb_send("E00"); gdb_packet_start(); @@ -229,11 +229,11 @@ static int monitor_command(char *buf) if (!strcasecmp(cmd, "reset")) { printf("Resetting device\n"); - if (device_active()->control(DEVICE_CTL_RESET) < 0) + if (device_get()->control(DEVICE_CTL_RESET) < 0) return gdb_send_hex("Reset failed\n"); } else if (!strcasecmp(cmd, "erase")) { printf("Erasing device\n"); - if (device_active()->control(DEVICE_CTL_ERASE) < 0) + if (device_get()->control(DEVICE_CTL_ERASE) < 0) return gdb_send_hex("Erase failed\n"); } @@ -257,7 +257,7 @@ static int write_registers(char *buf) buf += 4; } - if (device_active()->setregs(regs) < 0) + if (device_get()->setregs(regs) < 0) return gdb_send("E00"); return gdb_send("OK"); @@ -285,7 +285,7 @@ static int read_memory(char *text) printf("Reading %d bytes from 0x%04x\n", length, addr); - if (device_active()->readmem(addr, buf, length) < 0) + if (device_get()->readmem(addr, buf, length) < 0) return gdb_send("E00"); gdb_packet_start(); @@ -328,7 +328,7 @@ static int write_memory(char *text) printf("Writing %d bytes to 0x%04x\n", buflen, addr); - if (device_active()->writemem(addr, buf, buflen) < 0) + if (device_get()->writemem(addr, buf, buflen) < 0) return gdb_send("E00"); return gdb_send("OK"); @@ -341,11 +341,11 @@ static int run_set_pc(char *buf) if (!*buf) return 0; - if (device_active()->getregs(regs) < 0) + if (device_get()->getregs(regs) < 0) return -1; regs[0] = strtoul(buf, NULL, 16); - return device_active()->setregs(regs); + return device_get()->setregs(regs); } static int run_final_status(void) @@ -353,7 +353,7 @@ static int run_final_status(void) u_int16_t regs[DEVICE_NUM_REGS]; int i; - if (device_active()->getregs(regs) < 0) + if (device_get()->getregs(regs) < 0) return gdb_send("E00"); gdb_packet_start(); @@ -370,7 +370,7 @@ static int single_step(char *buf) printf("Single stepping\n"); if (run_set_pc(buf) < 0 || - device_active()->control(DEVICE_CTL_STEP) < 0) + device_get()->control(DEVICE_CTL_STEP) < 0) gdb_send("E00"); return run_final_status(); @@ -381,13 +381,13 @@ static int run(char *buf) printf("Running\n"); if (run_set_pc(buf) < 0 || - device_active()->control(DEVICE_CTL_RUN) < 0) { + device_get()->control(DEVICE_CTL_RUN) < 0) { gdb_send("E00"); return run_final_status(); } for (;;) { - device_status_t status = device_active()->wait(0); + device_status_t status = device_get()->wait(0); if (status == DEVICE_STATUS_ERROR) { gdb_send("E00"); @@ -416,7 +416,7 @@ static int run(char *buf) } out: - if (device_active()->control(DEVICE_CTL_HALT) < 0) + if (device_get()->control(DEVICE_CTL_HALT) < 0) gdb_send("E00"); return run_final_status(); diff --git a/main.c b/main.c index 94d9867..b2e5135 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,7 @@ #include "gdb.h" #include "rtools.h" #include "sym.h" +#include "devcmd.h" static void usage(const char *progname) { @@ -160,11 +161,6 @@ int main(int argc, char **argv) if (stab_init() < 0) return -1; - parse_init(); - sym_init(); - gdb_init(); - rtools_init(); - /* Open a device */ if (mode == MODE_SIM) { msp430_dev = sim_open(); @@ -194,7 +190,14 @@ int main(int argc, char **argv) return -1; } - device_init(msp430_dev); + /* Initialise parsing */ + device_set(msp430_dev); + parse_init(); + sym_init(); + devcmd_init(); + gdb_init(); + rtools_init(); + if (!no_rc) process_rc_file(); @@ -210,7 +213,7 @@ int main(int argc, char **argv) reader_loop(); } - device_exit(); + msp430_dev->close(); stab_exit(); return ret; diff --git a/rtools.c b/rtools.c index 956ed3c..ec4bf17 100644 --- a/rtools.c +++ b/rtools.c @@ -316,7 +316,7 @@ static int isearch_match(const struct msp430_instruction *insn, static int do_isearch(int addr, int len, const struct isearch_query *q) { u_int8_t *mbuf; - const struct device *dev = device_active(); + const struct device *dev = device_get(); int i; if (len <= 0 || len > 0x10000 || diff --git a/sym.h b/sym.h index 3eff294..5561709 100644 --- a/sym.h +++ b/sym.h @@ -19,8 +19,6 @@ #ifndef SYM_H_ #define SYM_H_ -#include - /* Register symbol-table manipulation commands */ void sym_init(void); diff --git a/util.c b/util.c index 9f44d7a..e35039b 100644 --- a/util.c +++ b/util.c @@ -536,66 +536,6 @@ void hexdump(int addr, const u_int8_t *data, int len) } } -/* This table of device IDs is sourced mainly from the MSP430 Memory - * Programming User's Guide (SLAU265). - * - * The table should be kept sorted by device ID. - */ - -static struct { - u_int16_t id; - const char *id_text; -} id_table[] = { - {0x1132, "F1122"}, - {0x1132, "F1132"}, - {0x1232, "F1222"}, - {0x1232, "F1232"}, - {0xF112, "F11x"}, /* obsolete */ - {0xF112, "F11x1"}, /* obsolete */ - {0xF112, "F11x1A"}, /* obsolete */ - {0xF123, "F122"}, - {0xF123, "F123x"}, - {0xF143, "F14x"}, - {0xF149, "F13x"}, - {0xF149, "F14x1"}, - {0xF149, "F149"}, - {0xF169, "F16x"}, - {0xF16C, "F161x"}, - {0xF201, "F20x3"}, - {0xF213, "F21x1"}, - {0xF227, "F22xx"}, - {0xF249, "F24x"}, - {0xF26F, "F261x"}, - {0xF413, "F41x"}, - {0xF427, "FE42x"}, - {0xF427, "FW42x"}, - {0xF427, "F415"}, - {0xF427, "F417"}, - {0xF427, "F42x0"}, - {0xF439, "FG43x"}, - {0xF449, "F43x"}, - {0xF449, "F44x"}, - {0xF46F, "FG46xx"}, - {0xF46F, "F471xx"} -}; - -void print_devid(u_int16_t id) -{ - int i = 0; - - while (i < ARRAY_LEN(id_table) && id_table[i].id != id) - i++; - - if (i < ARRAY_LEN(id_table)) { - printf("Device: MSP430%s", id_table[i++].id_text); - while (id_table[i].id == id) - printf("/MSP430%s", id_table[i++].id_text); - printf("\n"); - } else { - printf("Unknown device ID: 0x%04x\n", id); - } -} - int read_with_timeout(int fd, u_int8_t *data, int max_len) { int r; diff --git a/util.h b/util.h index 48b3f92..4d0ced1 100644 --- a/util.h +++ b/util.h @@ -121,8 +121,6 @@ void hexdump(int addr, const u_int8_t *data, int len); #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0])) -void print_devid(const u_int16_t id); - int open_serial(const char *device, int rate); int read_with_timeout(int fd, u_int8_t *data, int len); int write_all(int fd, const u_int8_t *data, int len);