Device drivers are now objects.

This commit is contained in:
Daniel Beer 2010-04-30 16:01:03 +12:00
parent 1f98eb4339
commit 204aa31291
17 changed files with 1093 additions and 867 deletions

View File

@ -23,18 +23,19 @@
#include <sys/types.h> #include <sys/types.h>
/* Callback for binary image data */ /* 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 */ /* Callback for symbol data */
typedef int (*symfunc_t)(const char *name, int value); typedef int (*symfunc_t)(const char *name, int value);
/* Intel HEX file support */ /* Intel HEX file support */
int ihex_check(FILE *in); 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 */ /* ELF32 file support */
int elf32_check(FILE *in); 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); int elf32_syms(FILE *in, symfunc_t cb);
/* *.map file support */ /* *.map file support */

182
bsl.c
View File

@ -17,6 +17,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
@ -25,20 +26,26 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "device.h" #include "bsl.h"
#include "util.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_HDR 0x80
#define DATA_ACK 0x90 #define DATA_ACK 0x90
#define DATA_NAK 0xA0 #define DATA_NAK 0xA0
static int bsl_ack(void) static int bsl_ack(struct bsl_device *dev)
{ {
u_int8_t reply; 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"); fprintf(stderr, "bsl: failed to receive reply\n");
return -1; return -1;
} }
@ -56,25 +63,26 @@ static int bsl_ack(void)
return 0; return 0;
} }
static int bsl_sync(void) static int bsl_sync(struct bsl_device *dev)
{ {
static const u_int8_t c = DATA_HDR; static const u_int8_t c = DATA_HDR;
int tries = 2; int tries = 2;
if (tcflush(serial_fd, TCIFLUSH) < 0) { if (tcflush(dev->serial_fd, TCIFLUSH) < 0) {
perror("bsl: tcflush"); perror("bsl: tcflush");
return -1; return -1;
} }
while (tries--) while (tries--)
if (!(write_all(serial_fd, &c, 1) || bsl_ack())) if (!(write_all(dev->serial_fd, &c, 1) || bsl_ack(dev)))
return 0; return 0;
fprintf(stderr, "bsl: sync failed\n"); fprintf(stderr, "bsl: sync failed\n");
return -1; 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) const u_int8_t *data, int len)
{ {
u_int8_t pktbuf[256]; 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 + 4] = cklow;
pktbuf[pktlen + 5] = ckhigh; 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 verify_checksum(struct bsl_device *dev)
static int reply_len;
static int verify_checksum(void)
{ {
u_int8_t cklow = 0xff; u_int8_t cklow = 0xff;
u_int8_t ckhigh = 0xff; u_int8_t ckhigh = 0xff;
int i; int i;
for (i = 0; i < dev->reply_len; i += 2)
for (i = 0; i < reply_len; i += 2) cklow ^= dev->reply_buf[i];
cklow ^= reply_buf[i]; for (i = 1; i < dev->reply_len; i += 2)
for (i = 1; i < reply_len; i += 2) ckhigh ^= dev->reply_buf[i];
ckhigh ^= reply_buf[i];
if (cklow || ckhigh) { if (cklow || ckhigh) {
fprintf(stderr, "bsl: checksum invalid (%02x %02x)\n", fprintf(stderr, "bsl: checksum invalid (%02x %02x)\n",
@ -135,47 +139,50 @@ static int verify_checksum(void)
return 0; return 0;
} }
static int fetch_reply(void) static int fetch_reply(struct bsl_device *dev)
{ {
reply_len = 0; dev->reply_len = 0;
for (;;) { for (;;) {
int r = read_with_timeout(serial_fd, reply_buf + reply_len, int r = read_with_timeout(dev->serial_fd,
sizeof(reply_buf) - reply_len); dev->reply_buf + dev->reply_len,
sizeof(dev->reply_buf) -
dev->reply_len);
if (r < 0) if (r < 0)
return -1; return -1;
reply_len += r; dev->reply_len += r;
if (reply_buf[0] == DATA_ACK) { if (dev->reply_buf[0] == DATA_ACK) {
return 0; return 0;
} else if (reply_buf[0] == DATA_HDR) { } else if (dev->reply_buf[0] == DATA_HDR) {
if (reply_len >= 6 && if (dev->reply_len >= 6 &&
reply_len == reply_buf[2] + 6) dev->reply_len == dev->reply_buf[2] + 6)
return verify_checksum(); return verify_checksum(dev);
} else if (reply_buf[0] == DATA_NAK) { } else if (dev->reply_buf[0] == DATA_NAK) {
fprintf(stderr, "bsl: received NAK\n"); fprintf(stderr, "bsl: received NAK\n");
return -1; return -1;
} else { } else {
fprintf(stderr, "bsl: unknown reply type: %02x\n", fprintf(stderr, "bsl: unknown reply type: %02x\n",
reply_buf[0]); dev->reply_buf[0]);
return -1; return -1;
} }
if (reply_len >= sizeof(reply_buf)) { if (dev->reply_len >= sizeof(dev->reply_buf)) {
fprintf(stderr, "bsl: reply buffer overflow\n"); fprintf(stderr, "bsl: reply buffer overflow\n");
return -1; 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) int len)
{ {
if (bsl_sync() < 0 || if (bsl_sync(dev) < 0 ||
send_command(command_code, addr, txdata, len) < 0 || send_command(dev, command_code, addr, txdata, len) < 0 ||
fetch_reply() < 0) { fetch_reply(dev) < 0) {
fprintf(stderr, "bsl: failed on command 0x%02x " fprintf(stderr, "bsl: failed on command 0x%02x "
"(addr = 0x%04x, len = 0x%04x)\n", "(addr = 0x%04x, len = 0x%04x)\n",
command_code, addr, len); 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_RX_DATA 0x3a
#define CMD_RESET 0x3b #define CMD_RESET 0x3b
static void bsl_close(void) static void bsl_destroy(device_t dev_base)
{ {
bsl_xfer(CMD_RESET, 0, NULL, 0); struct bsl_device *dev = (struct bsl_device *)dev_base;
close(serial_fd);
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"); fprintf(stderr, "bsl: CPU control is not implemented\n");
return -1; return -1;
} }
static device_status_t bsl_wait(int blocking) static device_status_t bsl_poll(device_t dev_base)
{ {
return DEVICE_STATUS_HALTED; 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"); fprintf(stderr, "bsl: breakpoints are not implemented\n");
return -1; 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"); fprintf(stderr, "bsl: register fetch is not implemented\n");
return -1; 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"); fprintf(stderr, "bsl: register store is not implemented\n");
return -1; 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"); fprintf(stderr, "bsl: memory write is not implemented\n");
return -1; 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) { while (len) {
int count = len; int count = len;
if (count > 128) if (count > 128)
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"); fprintf(stderr, "bsl: failed to read memory\n");
return -1; return -1;
} }
if (count > reply_buf[2]) if (count > dev->reply_buf[2])
count = reply_buf[2]; count = dev->reply_buf[2];
memcpy(mem, reply_buf + 4, count); memcpy(mem, dev->reply_buf + 4, count);
mem += count; mem += count;
len -= count; len -= count;
} }
@ -255,27 +269,15 @@ static int bsl_readmem(u_int16_t addr, u_int8_t *mem, int len)
return 0; return 0;
} }
const static struct device bsl_device = { static int enter_via_fet(struct bsl_device *dev)
.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 <sys/ioctl.h>
static int enter_via_fet(void)
{ {
u_int8_t buf[16]; u_int8_t buf[16];
u_int8_t *data = buf; u_int8_t *data = buf;
int len = 8; int len = 8;
/* Enter bootloader command */ /* 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 " fprintf(stderr, "bsl: couldn't write bootloader transition "
"command\n"); "command\n");
return -1; return -1;
@ -283,7 +285,7 @@ static int enter_via_fet(void)
/* Wait for reply */ /* Wait for reply */
while (len) { while (len) {
int r = read_with_timeout(serial_fd, data, len); int r = read_with_timeout(dev->serial_fd, data, len);
if (r < 0) { if (r < 0) {
fprintf(stderr, "bsl: couldn't read bootloader " fprintf(stderr, "bsl: couldn't read bootloader "
@ -305,40 +307,62 @@ static int enter_via_fet(void)
return 0; 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]; char idtext[64];
u_int16_t id; u_int16_t id;
serial_fd = open_serial(device, B460800); if (!dev) {
if (serial_fd < 0) { perror("bsl: can't allocate memory");
fprintf(stderr, "bsl: can't open %s: %s\n",
device, strerror(errno));
return NULL; 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; return NULL;
usleep(500000); usleep(500000);
/* Show chip info */ /* 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"); 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"); fprintf(stderr, "bsl: missing chip info\n");
return NULL; goto fail;
} }
id = (reply_buf[4] << 8) | reply_buf[5]; id = (dev->reply_buf[4] << 8) | dev->reply_buf[5];
if (find_device_id(id, idtext, sizeof(idtext)) < 0) if (device_id_text(id, idtext, sizeof(idtext)) < 0)
printf("Unknown device ID: 0x%04x\n", id); printf("Unknown device ID: 0x%04x\n", id);
else else
printf("Device: %s\n", idtext); printf("Device: %s\n", idtext);
printf("BSL version is %x.%02x\n", reply_buf[14], reply_buf[15]); printf("BSL version is %x.%02x\n", dev->reply_buf[14],
return &bsl_device; dev->reply_buf[15]);
return (device_t)dev;
fail:
close(dev->serial_fd);
free(dev);
return NULL;
} }

27
bsl.h Normal file
View File

@ -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

12
cproc.c
View File

@ -40,6 +40,8 @@ struct cproc {
int modify_flags; int modify_flags;
int in_reader_loop; int in_reader_loop;
device_t device;
}; };
static struct cproc_option *find_option(cproc_t cp, const char *name) 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)); cproc_t cp = malloc(sizeof(*cp));
@ -328,6 +330,8 @@ cproc_t cproc_new(void)
memset(cp, 0, sizeof(*cp)); memset(cp, 0, sizeof(*cp));
cp->device = dev;
vector_init(&cp->command_list, sizeof(struct cproc_command)); vector_init(&cp->command_list, sizeof(struct cproc_command));
vector_init(&cp->option_list, sizeof(struct cproc_option)); vector_init(&cp->option_list, sizeof(struct cproc_option));
@ -346,11 +350,17 @@ cproc_t cproc_new(void)
void cproc_destroy(cproc_t cp) void cproc_destroy(cproc_t cp)
{ {
cp->device->destroy(cp->device);
vector_destroy(&cp->command_list); vector_destroy(&cp->command_list);
vector_destroy(&cp->option_list); vector_destroy(&cp->option_list);
free(cp); 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 cproc_register_commands(cproc_t cp, const struct cproc_command *cmd,
int count) int count)
{ {

11
cproc.h
View File

@ -19,6 +19,8 @@
#ifndef CPROC_H_ #ifndef CPROC_H_
#define CPROC_H_ #define CPROC_H_
#include "device.h"
/* Command processor. /* Command processor.
* *
* This contains a list of all defined commands and options, plus modification * 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 /* Create/destroy a command processor. The init function returns 0 if
* successful, or -1 if an error occurs. * 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); 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 /* Register commands and options with the command processor. These functions
* return 0 on success or -1 if an error occurs (failure to allocate memory). * return 0 on success or -1 if an error occurs (failure to allocate memory).
*/ */

133
devcmd.c
View File

@ -32,15 +32,16 @@
static int cmd_regs(cproc_t cp, char **arg) static int cmd_regs(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
u_int16_t regs[DEVICE_NUM_REGS]; u_int16_t regs[DEVICE_NUM_REGS];
u_int8_t code[16]; u_int8_t code[16];
if (device_get()->getregs(regs) < 0) if (dev->getregs(dev, regs) < 0)
return -1; return -1;
cproc_regs(cp, regs); cproc_regs(cp, regs);
/* Try to disassemble the instruction at PC */ /* 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; return 0;
cproc_disassemble(cp, regs[0], (u_int8_t *)code, sizeof(code)); 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) static int cmd_md(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *off_text = get_arg(arg); char *off_text = get_arg(arg);
char *len_text = get_arg(arg); char *len_text = get_arg(arg);
int offset = 0; int offset = 0;
@ -83,7 +85,7 @@ static int cmd_md(cproc_t cp, char **arg)
u_int8_t buf[128]; u_int8_t buf[128];
int blen = length > sizeof(buf) ? sizeof(buf) : length; 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; return -1;
cproc_hexdump(cp, offset, buf, blen); 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) static int cmd_mw(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *off_text = get_arg(arg); char *off_text = get_arg(arg);
char *byte_text; char *byte_text;
int offset = 0; int offset = 0;
@ -129,7 +132,7 @@ static int cmd_mw(cproc_t cp, char **arg)
return -1; return -1;
} }
if (device_get()->writemem(offset, buf, length) < 0) if (dev->writemem(dev, offset, buf, length) < 0)
return -1; return -1;
return 0; return 0;
@ -137,20 +140,25 @@ static int cmd_mw(cproc_t cp, char **arg)
static int cmd_reset(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) 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; return -1;
printf("Erasing...\n"); 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) static int cmd_step(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *count_text = get_arg(arg); char *count_text = get_arg(arg);
int count = 1; int count = 1;
@ -158,7 +166,7 @@ static int cmd_step(cproc_t cp, char **arg)
count = atoi(count_text); count = atoi(count_text);
while (count > 0) { while (count > 0) {
if (device_get()->control(DEVICE_CTL_STEP) < 0) if (dev->ctl(dev, DEVICE_CTL_STEP) < 0)
return -1; return -1;
count--; count--;
} }
@ -168,6 +176,7 @@ static int cmd_step(cproc_t cp, char **arg)
static int cmd_run(cproc_t cp, char **arg) static int cmd_run(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *bp_text = get_arg(arg); char *bp_text = get_arg(arg);
int bp_addr; int bp_addr;
device_status_t status; device_status_t status;
@ -179,11 +188,12 @@ static int cmd_run(cproc_t cp, char **arg)
return -1; 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 ? if (dev->ctl(dev, DEVICE_CTL_RUN) < 0)
DEVICE_CTL_RUN_BP : DEVICE_CTL_RUN) < 0)
return -1; return -1;
if (bp_text) if (bp_text)
@ -192,11 +202,17 @@ static int cmd_run(cproc_t cp, char **arg)
printf("Running."); printf("Running.");
printf(" Press Ctrl+C to interrupt...\n"); 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) if (status == DEVICE_STATUS_INTR)
printf("\n"); 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 -1;
return cmd_regs(cp, NULL); 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) static int cmd_set(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *reg_text = get_arg(arg); char *reg_text = get_arg(arg);
char *val_text = get_arg(arg); char *val_text = get_arg(arg);
int reg; int reg;
@ -229,10 +246,10 @@ static int cmd_set(cproc_t cp, char **arg)
return -1; return -1;
} }
if (device_get()->getregs(regs) < 0) if (dev->getregs(dev, regs) < 0)
return -1; return -1;
regs[reg] = value; regs[reg] = value;
if (device_get()->setregs(regs) < 0) if (dev->setregs(dev, regs) < 0)
return -1; return -1;
cproc_regs(cp, regs); 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) static int cmd_dis(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *off_text = get_arg(arg); char *off_text = get_arg(arg);
char *len_text = get_arg(arg); char *len_text = get_arg(arg);
int offset = 0; int offset = 0;
@ -273,7 +291,7 @@ static int cmd_dis(cproc_t cp, char **arg)
return -1; return -1;
} }
if (device_get()->readmem(offset, buf, length) < 0) if (dev->readmem(dev, offset, buf, length) < 0)
return -1; return -1;
cproc_disassemble(cp, offset, (u_int8_t *)buf, length); 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) static int cmd_hexout(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
char *off_text = get_arg(arg); char *off_text = get_arg(arg);
char *len_text = get_arg(arg); char *len_text = get_arg(arg);
char *filename = *arg; char *filename = *arg;
@ -383,7 +402,7 @@ static int cmd_hexout(cproc_t cp, char **arg)
count = sizeof(buf); count = sizeof(buf);
printf("Reading %d bytes from 0x%04x...\n", count, off); 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"); perror("hexout: can't read memory");
goto fail; goto fail;
} }
@ -410,69 +429,79 @@ fail:
return -1; return -1;
} }
static u_int8_t prog_buf[128]; struct prog_data {
static u_int16_t prog_addr; device_t dev;
static int prog_len;
static int prog_have_erased;
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->dev = dev;
prog_have_erased = 0; prog->len = 0;
prog->have_erased = 0;
} }
static int prog_flush(void) static int prog_flush(struct prog_data *prog)
{ {
while (prog_len) { while (prog->len) {
int wlen = prog_len; int wlen = prog->len;
/* Writing across this address seems to cause a hang */ /* Writing across this address seems to cause a hang */
if (prog_addr < 0x999a && wlen + prog_addr > 0x999a) if (prog->addr < 0x999a && wlen + prog->addr > 0x999a)
wlen = 0x999a - prog_addr; wlen = 0x999a - prog->addr;
if (!prog_have_erased) { if (!prog->have_erased) {
printf("Erasing...\n"); printf("Erasing...\n");
if (device_get()->control(DEVICE_CTL_ERASE) < 0) if (prog->dev->ctl(prog->dev, DEVICE_CTL_ERASE) < 0)
return -1; return -1;
prog_have_erased = 1; prog->have_erased = 1;
} }
printf("Writing %3d bytes to %04x...\n", wlen, prog_addr); printf("Writing %3d bytes to %04x...\n", wlen, prog->addr);
if (device_get()->writemem(prog_addr, prog_buf, wlen) < 0) if (prog->dev->writemem(prog->dev, prog->addr,
prog->buf, wlen) < 0)
return -1; return -1;
memmove(prog_buf, prog_buf + wlen, prog_len - wlen); memmove(prog->buf, prog->buf + wlen, prog->len - wlen);
prog_len -= wlen; prog->len -= wlen;
prog_addr += wlen; prog->addr += wlen;
} }
return 0; 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 */ /* 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; return -1;
if (!prog_len) if (!prog->len)
prog_addr = addr; prog->addr = addr;
/* Add the buffer in piece by piece, flushing when it gets /* Add the buffer in piece by piece, flushing when it gets
* full. * full.
*/ */
while (len) { while (len) {
int count = sizeof(prog_buf) - prog_len; int count = sizeof(prog->buf) - prog->len;
if (count > len) if (count > len)
count = len; count = len;
if (!count) { if (!count) {
if (prog_flush() < 0) if (prog_flush(prog) < 0)
return -1; return -1;
} else { } else {
memcpy(prog_buf + prog_len, data, count); memcpy(prog->buf + prog->len, data, count);
prog_len += count; prog->len += count;
data += count; data += count;
len -= 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) static int cmd_prog(cproc_t cp, char **arg)
{ {
device_t dev = cproc_device(cp);
FILE *in; FILE *in;
int result = 0; int result = 0;
struct prog_data prog;
if (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS)) if (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS))
return 0; return 0;
@ -495,29 +526,29 @@ static int cmd_prog(cproc_t cp, char **arg)
return -1; return -1;
} }
if (device_get()->control(DEVICE_CTL_HALT) < 0) { if (dev->ctl(dev, DEVICE_CTL_HALT) < 0) {
fclose(in); fclose(in);
return -1; return -1;
} }
prog_init(); prog_init(&prog, dev);
if (elf32_check(in)) { if (elf32_check(in)) {
result = elf32_extract(in, prog_feed); result = elf32_extract(in, prog_feed, &prog);
stab_clear(); stab_clear();
elf32_syms(in, stab_set); elf32_syms(in, stab_set);
} else if (ihex_check(in)) { } else if (ihex_check(in)) {
result = ihex_extract(in, prog_feed); result = ihex_extract(in, prog_feed, &prog);
} else { } else {
fprintf(stderr, "prog: %s: unknown file type\n", *arg); fprintf(stderr, "prog: %s: unknown file type\n", *arg);
} }
fclose(in); fclose(in);
if (prog_flush() < 0) if (prog_flush(&prog) < 0)
return -1; 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"); fprintf(stderr, "prog: failed to reset after programming\n");
return -1; return -1;
} }

View File

@ -17,26 +17,10 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include "device.h" #include "device.h"
#include "util.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 /* This table of device IDs is sourced mainly from the MSP430 Memory
* Programming User's Guide (SLAU265). * Programming User's Guide (SLAU265).
* *
@ -80,7 +64,7 @@ static struct {
{0xF46F, "F471xx"} {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 i = 0;
int len; int len;

View File

@ -1,4 +1,4 @@
/* MSPDebug - debugging tool for the eZ430 /* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009, 2010 Daniel Beer * Copyright (C) 2009, 2010 Daniel Beer
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -20,15 +20,14 @@
#define DEVICE_H_ #define DEVICE_H_
#include <sys/types.h> #include <sys/types.h>
#include "transport.h"
#define DEVICE_NUM_REGS 16 struct device;
typedef struct device *device_t;
typedef enum { typedef enum {
DEVICE_CTL_RESET, DEVICE_CTL_RESET,
DEVICE_CTL_RUN, DEVICE_CTL_RUN,
DEVICE_CTL_HALT, DEVICE_CTL_HALT,
DEVICE_CTL_RUN_BP,
DEVICE_CTL_STEP, DEVICE_CTL_STEP,
DEVICE_CTL_ERASE DEVICE_CTL_ERASE
} device_ctl_t; } device_ctl_t;
@ -40,35 +39,33 @@ typedef enum {
DEVICE_STATUS_ERROR DEVICE_STATUS_ERROR
} device_status_t; } device_status_t;
#define DEVICE_NUM_REGS 16
struct device { struct device {
void (*close)(void); /* Close the connection to the device and destroy the driver object */
int (*control)(device_ctl_t action); void (*destroy)(device_t dev);
device_status_t (*wait)(int blocking);
int (*breakpoint)(u_int16_t addr); /* Read/write memory */
int (*getregs)(u_int16_t *regs); int (*readmem)(device_t dev, u_int16_t addr,
int (*setregs)(const u_int16_t *regs); u_int8_t *mem, int len);
int (*readmem)(u_int16_t addr, u_int8_t *mem, int len); int (*writemem)(device_t dev, u_int16_t addr,
int (*writemem)(u_int16_t addr, const u_int8_t *mem, int len); 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 */ /* 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); int device_id_text(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 #endif

10
elf32.c
View File

@ -126,7 +126,8 @@ static u_int32_t file_to_phys(u_int32_t v)
return 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_int8_t buf[1024];
u_int16_t addr = file_to_phys(offset); 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; return -1;
} }
if (cb(addr, buf, len) < 0) if (cb(user_data, addr, buf, len) < 0)
return -1; return -1;
size -= len; size -= len;
@ -173,7 +174,7 @@ static int read_all(FILE *in)
return 0; return 0;
} }
int elf32_extract(FILE *in, imgfunc_t cb) int elf32_extract(FILE *in, imgfunc_t cb, void *user_data)
{ {
int i; int i;
@ -184,7 +185,8 @@ int elf32_extract(FILE *in, imgfunc_t cb)
Elf32_Shdr *s = &file_shdrs[i]; Elf32_Shdr *s = &file_shdrs[i];
if (s->sh_type == SHT_PROGBITS && s->sh_flags & SHF_ALLOC && 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; return -1;
} }

501
fet.c
View File

@ -21,16 +21,42 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include "util.h" #include "util.h"
#include "device.h" #include "fet.h"
static const struct fet_transport *fet_transport; #define MAX_PARAMS 16
static int fet_is_rf2500;
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. * FET command codes.
@ -97,13 +123,11 @@ static int fet_is_rf2500;
* Checksum calculation * Checksum calculation
*/ */
static u_int16_t code_left[65536];
/* Initialise the code table. The code table is a function which takes /* Initialise the code table. The code table is a function which takes
* us from one checksum position code to the next. * us from one checksum position code to the next.
*/ */
static void init_codes(void) static void init_codes(struct fet_device *dev)
{ {
int i; int i;
@ -113,7 +137,7 @@ static void init_codes(void)
if (i & 0x8000) if (i & 0x8000)
right ^= 0x0811; 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. * 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; int i;
u_int16_t cksum = 0xffff; u_int16_t cksum = 0xffff;
u_int16_t code = 0x8408; u_int16_t code = 0x8408;
for (i = len * 8; i; i--) for (i = len * 8; i; i--)
cksum = code_left[cksum]; cksum = dev->code_left[cksum];
for (i = len - 1; i >= 0; i--) { for (i = len - 1; i >= 0; i--) {
int j; 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++) { for (j = 0; j < 8; j++) {
if (c & 0x80) if (c & 0x80)
cksum ^= code; cksum ^= code;
code = code_left[code]; code = dev->code_left[code];
c <<= 1; c <<= 1;
} }
} }
@ -156,11 +181,11 @@ static u_int16_t calc_checksum(const u_int8_t *data, int len)
* *
* No checksums are included. * 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; int offset = 0;
assert (fet_transport != NULL);
while (len) { while (len) {
u_int8_t pbuf[63]; u_int8_t pbuf[63];
int plen = len > 59 ? 59 : len; 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[2] = offset >> 8;
pbuf[3] = plen; pbuf[3] = plen;
memcpy(pbuf + 4, data, 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; return -1;
data += plen; data += plen;
@ -181,23 +206,6 @@ static int send_rf2500_data(const u_int8_t *data, int len)
return 0; 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_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_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)) #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 "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 c = calc_checksum(dev, dev->fet_buf + 2, plen - 2);
u_int16_t r = BUFFER_WORD(fet_buf, plen); u_int16_t r = BUFFER_WORD(dev->fet_buf, plen);
int i = 2; int i = 2;
int type; int type;
int error; int error;
@ -291,10 +299,10 @@ static int parse_packet(int plen)
if (plen < 6) if (plen < 6)
goto too_short; goto too_short;
fet_reply.command_code = fet_buf[i++]; dev->fet_reply.command_code = dev->fet_buf[i++];
type = fet_buf[i++]; type = dev->fet_buf[i++];
fet_reply.state = fet_buf[i++]; dev->fet_reply.state = dev->fet_buf[i++];
error = fet_buf[i++]; error = dev->fet_buf[i++];
if (error) { if (error) {
fprintf(stderr, "fet: FET returned error code %d\n", fprintf(stderr, "fet: FET returned error code %d\n",
@ -317,23 +325,23 @@ static int parse_packet(int plen)
if (i + 2 > plen) if (i + 2 > plen)
goto too_short; goto too_short;
fet_reply.argc = BUFFER_WORD(fet_buf, i); dev->fet_reply.argc = BUFFER_WORD(dev->fet_buf, i);
i += 2; i += 2;
if (fet_reply.argc >= MAX_PARAMS) { if (dev->fet_reply.argc >= MAX_PARAMS) {
fprintf(stderr, "fet: too many params: %d\n", fprintf(stderr, "fet: too many params: %d\n",
fet_reply.argc); dev->fet_reply.argc);
return -1; return -1;
} }
for (j = 0; j < fet_reply.argc; j++) { for (j = 0; j < dev->fet_reply.argc; j++) {
if (i + 4 > plen) if (i + 4 > plen)
goto too_short; 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; i += 4;
} }
} else { } else {
fet_reply.argc = 0; dev->fet_reply.argc = 0;
} }
/* Extract a pointer to the data */ /* Extract a pointer to the data */
@ -341,16 +349,16 @@ static int parse_packet(int plen)
if (i + 4 > plen) if (i + 4 > plen)
goto too_short; goto too_short;
fet_reply.datalen = BUFFER_LONG(fet_buf, i); dev->fet_reply.datalen = BUFFER_LONG(dev->fet_buf, i);
i += 4; i += 4;
if (i + fet_reply.datalen > plen) if (i + dev->fet_reply.datalen > plen)
goto too_short; goto too_short;
fet_reply.data = fet_buf + i; dev->fet_reply.data = dev->fet_buf + i;
} else { } else {
fet_reply.data = NULL; dev->fet_reply.data = NULL;
fet_reply.datalen = 0; dev->fet_reply.datalen = 0;
} }
return 0; return 0;
@ -361,37 +369,37 @@ too_short:
return -1; return -1;
} }
static int recv_packet(void) static int recv_packet(struct fet_device *dev)
{ {
int plen = BUFFER_WORD(fet_buf, 0); int plen = BUFFER_WORD(dev->fet_buf, 0);
assert (fet_transport != NULL);
/* If there's a packet still here from last time, get rid of it */ /* If there's a packet still here from last time, get rid of it */
if (fet_len >= plen + 2) { if (dev->fet_len >= plen + 2) {
memmove(fet_buf, fet_buf + plen + 2, fet_len - plen - 2); memmove(dev->fet_buf, dev->fet_buf + plen + 2,
fet_len -= plen + 2; dev->fet_len - plen - 2);
dev->fet_len -= plen + 2;
} }
/* Keep adding data to the buffer until we have a complete packet */ /* Keep adding data to the buffer until we have a complete packet */
for (;;) { for (;;) {
int len; int len;
plen = BUFFER_WORD(fet_buf, 0); plen = BUFFER_WORD(dev->fet_buf, 0);
if (fet_len >= plen + 2) if (dev->fet_len >= plen + 2)
return parse_packet(plen); return parse_packet(dev, plen);
len = fet_transport->recv(fet_buf + fet_len, len = dev->fet_transport->recv(dev->fet_buf + dev->fet_len,
sizeof(fet_buf) - fet_len); sizeof(dev->fet_buf) -
dev->fet_len);
if (len < 0) if (len < 0)
return -1; return -1;
fet_len += len; dev->fet_len += len;
} }
return -1; 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_int32_t *params, int nparams,
const u_int8_t *extra, int exlen) const u_int8_t *extra, int exlen)
{ {
@ -404,7 +412,6 @@ static int send_command(int command_code,
int j; int j;
assert (len + exlen + 2 <= sizeof(datapkt)); assert (len + exlen + 2 <= sizeof(datapkt));
assert (fet_transport != NULL);
/* Command code and packet type */ /* Command code and packet type */
datapkt[len++] = command_code; datapkt[len++] = command_code;
@ -445,7 +452,7 @@ static int send_command(int command_code,
} }
/* Checksum */ /* Checksum */
cksum = calc_checksum(datapkt, len); cksum = calc_checksum(dev, datapkt, len);
datapkt[len++] = cksum & 0xff; datapkt[len++] = cksum & 0xff;
datapkt[len++] = cksum >> 8; datapkt[len++] = cksum >> 8;
@ -467,10 +474,11 @@ static int send_command(int command_code,
assert (i < sizeof(buf)); 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, ...) int nparams, ...)
{ {
u_int32_t params[MAX_PARAMS]; 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); params[i] = va_arg(ap, unsigned int);
va_end(ap); va_end(ap);
if (data && fet_is_rf2500) { if (data && dev->is_rf2500) {
assert (nparams + 1 <= MAX_PARAMS); assert (nparams + 1 <= MAX_PARAMS);
params[nparams++] = datalen; params[nparams++] = datalen;
if (send_rf2500_data(data, datalen) < 0) if (send_rf2500_data(dev, data, datalen) < 0)
return -1; 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; return -1;
} else if (send_command(command_code, params, nparams, } else if (send_command(dev, command_code, params, nparams,
data, datalen) < 0) data, datalen) < 0)
return -1; return -1;
if (recv_packet() < 0) if (recv_packet(dev) < 0)
return -1; return -1;
if (fet_reply.command_code != command_code) { if (dev->fet_reply.command_code != command_code) {
fprintf(stderr, "fet: reply type mismatch\n"); fprintf(stderr, "fet: reply type mismatch\n");
return -1; return -1;
} }
@ -511,38 +520,36 @@ static int xfer(int command_code, const u_int8_t *data, int datalen,
* MSP430 high-level control functions * MSP430 high-level control functions
*/ */
static int fet_version; static int do_identify(struct fet_device *dev)
static int do_identify(void)
{ {
char idtext[64]; char idtext[64];
if (fet_version < 20300000) { if (dev->version < 20300000) {
if (xfer(C_IDENTIFY, NULL, 0, 2, 70, 0) < 0) if (xfer(dev, C_IDENTIFY, NULL, 0, 2, 70, 0) < 0)
return -1; return -1;
if (!fet_reply.data) { if (!dev->fet_reply.data) {
fprintf(stderr, "fet: missing info\n"); fprintf(stderr, "fet: missing info\n");
return -1; return -1;
} }
memcpy(idtext, fet_reply.data + 4, 32); memcpy(idtext, dev->fet_reply.data + 4, 32);
idtext[32] = 0; idtext[32] = 0;
} else { } else {
u_int16_t id; 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"); fprintf(stderr, "fet: command 0x28 failed\n");
return -1; return -1;
} }
if (fet_reply.datalen < 2) { if (dev->fet_reply.datalen < 2) {
fprintf(stderr, "fet: missing info\n"); fprintf(stderr, "fet: missing info\n");
return -1; return -1;
} }
id = (fet_reply.data[0] << 8) | fet_reply.data[1]; id = (dev->fet_reply.data[0] << 8) | dev->fet_reply.data[1];
if (find_device_id(id, idtext, sizeof(idtext)) < 0) { if (device_id_text(id, idtext, sizeof(idtext)) < 0) {
printf("Unknown device ID: 0x%04x\n", id); printf("Unknown device ID: 0x%04x\n", id);
return 0; return 0;
} }
@ -552,30 +559,9 @@ static int do_identify(void)
return 0; 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) if (xfer(dev, C_RUN, NULL, 0, 2, type, 0) < 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) {
fprintf(stderr, "fet: failed to restart CPU\n"); fprintf(stderr, "fet: failed to restart CPU\n");
return -1; return -1;
} }
@ -583,34 +569,24 @@ static int do_run(int type)
return 0; return 0;
} }
static int do_halt(void) static int do_erase(struct fet_device *dev)
{ {
if (xfer(C_STATE, NULL, 0, 1, 1) < 0) { if (xfer(dev, C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 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) {
fprintf(stderr, "fet: reset before erase failed\n"); fprintf(stderr, "fet: reset before erase failed\n");
return -1; 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"); fprintf(stderr, "fet: config (1) failed\n");
return -1; 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"); fprintf(stderr, "fet: config (2) failed\n");
return -1; 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"); fprintf(stderr, "fet: erase command failed\n");
return -1; return -1;
} }
@ -618,124 +594,105 @@ static int do_erase(void)
return 0; return 0;
} }
static device_status_t fet_wait(int blocking) static device_status_t fet_poll(device_t dev_base)
{ {
do { struct fet_device *dev = (struct fet_device *)dev_base;
/* Without this delay, breakpoints can get lost. */
if (usleep(500000) < 0)
return DEVICE_STATUS_INTR;
if (xfer(C_STATE, NULL, 0, 1, 0) < 0) { /* Without this delay, breakpoints can get lost. */
fprintf(stderr, "fet: polling failed\n"); if (usleep(500000) < 0)
return DEVICE_STATUS_ERROR; return DEVICE_STATUS_INTR;
}
if (!(fet_reply.argv[0] & FET_POLL_RUNNING)) if (xfer(dev, C_STATE, NULL, 0, 1, 0) < 0) {
return DEVICE_STATUS_HALTED; fprintf(stderr, "fet: polling failed\n");
} while (blocking); return DEVICE_STATUS_ERROR;
}
if (!(dev->fet_reply.argv[0] & FET_POLL_RUNNING))
return DEVICE_STATUS_HALTED;
return DEVICE_STATUS_RUNNING; 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) { switch (action) {
case DEVICE_CTL_RESET: 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: case DEVICE_CTL_RUN:
return do_run(FET_RUN_FREE); return do_run(dev, dev->have_breakpoint ?
FET_RUN_BREAKPOINT : FET_RUN_FREE);
case DEVICE_CTL_RUN_BP:
return do_run(FET_RUN_BREAKPOINT);
case DEVICE_CTL_HALT: 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: case DEVICE_CTL_STEP:
if (do_run(FET_RUN_STEP) < 0) if (do_run(dev, FET_RUN_STEP) < 0)
return -1; return -1;
if (fet_wait(1) < 0)
return -1; for (;;) {
return 0; 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: case DEVICE_CTL_ERASE:
return do_erase(); return do_erase(dev);
} }
return 0; 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) { struct fet_device *dev = (struct fet_device *)dev_base;
fprintf(stderr, "fet: set breakpoint failed\n");
return -1;
}
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) { while (count) {
int plen = count > 128 ? 128 : 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 " fprintf(stderr, "fet: failed to read "
"from 0x%04x\n", addr); "from 0x%04x\n", addr);
return -1; return -1;
} }
if (fet_reply.datalen < plen) { if (dev->fet_reply.datalen < plen) {
fprintf(stderr, "fet: short data: " fprintf(stderr, "fet: short data: "
"%d bytes\n", fet_reply.datalen); "%d bytes\n", dev->fet_reply.datalen);
return -1; return -1;
} }
memcpy(buffer, fet_reply.data, plen); memcpy(buffer, dev->fet_reply.data, plen);
buffer += plen; buffer += plen;
count -= plen; count -= plen;
addr += plen; addr += plen;
@ -744,13 +701,16 @@ int fet_readmem(u_int16_t addr, u_int8_t *buffer, int count)
return 0; 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) { while (count) {
int plen = count > 128 ? 128 : count; int plen = count > 128 ? 128 : count;
int ret; int ret;
ret = xfer(C_WRITEMEMORY, buffer, plen, 1, addr); ret = xfer(dev, C_WRITEMEMORY, buffer, plen, 1, addr);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "fet: failed to write to 0x%04x\n", 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; return 0;
} }
const static struct device fet_device = { static int fet_getregs(device_t dev_base, u_int16_t *regs)
.close = fet_close, {
.control = fet_control, struct fet_device *dev = (struct fet_device *)dev_base;
.wait = fet_wait, int i;
.breakpoint = fet_breakpoint,
.getregs = fet_getregs, if (xfer(dev, C_READREGISTERS, NULL, 0, 0) < 0)
.setregs = fet_setregs, return -1;
.readmem = fet_readmem,
.writemem = fet_writemem 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_DATA_SIZE 0x4a
#define MAGIC_PARAM_COUNT 3 #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; int i;
for (i = 0; i < ARRAY_LEN(magic_table); i++) { for (i = 0; i < ARRAY_LEN(magic_table); i++) {
const struct magic_record *r = &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", printf("Sending magic messages for >= %d\n",
r->min_version); r->min_version);
if ((r->flags & MAGIC_SEND_2B) && 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"); fprintf(stderr, "fet: command 0x2b failed\n");
return -1; return -1;
} }
if ((r->flags & MAGIC_SEND_29) && 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], 3, r->param_29[0], r->param_29[1],
r->param_29[2]) < 0) { r->param_29[2]) < 0) {
fprintf(stderr, "fet: command 0x29 failed\n"); fprintf(stderr, "fet: command 0x29 failed\n");
@ -905,55 +917,78 @@ static int do_magic(void)
return 0; return 0;
} }
const struct device *fet_open(const struct fet_transport *tr, device_t fet_open(const struct fet_transport *tr,
int proto_flags, int vcc_mv) int proto_flags, int vcc_mv)
{ {
fet_transport = tr; struct fet_device *dev = malloc(sizeof(*dev));
fet_is_rf2500 = proto_flags & FET_PROTO_RF2500;
init_codes();
if (xfer(C_INITIALIZE, NULL, 0, 0) < 0) { if (!dev) {
fprintf(stderr, "fet: open failed\n"); perror("fet: failed to allocate memory");
return NULL; return NULL;
} }
fet_version = fet_reply.argv[0]; dev->base.destroy = fet_destroy;
printf("FET protocol version is %d\n", fet_version); 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"); fprintf(stderr, "fet: init failed\n");
return NULL; goto fail;
} }
/* configure: Spy-Bi-Wire or JTAG */ /* 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) { 2, 8, (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0) < 0) {
fprintf(stderr, "fet: configure failed\n"); fprintf(stderr, "fet: configure failed\n");
return NULL; goto fail;
} }
printf("Configured for %s\n", printf("Configured for %s\n",
(proto_flags & FET_PROTO_SPYBIWIRE) ? "Spy-Bi-Wire" : "JTAG"); (proto_flags & FET_PROTO_SPYBIWIRE) ? "Spy-Bi-Wire" : "JTAG");
/* set VCC */ /* 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"); fprintf(stderr, "fet: set VCC failed\n");
return NULL; goto fail;
} }
printf("Set Vcc: %d mV\n", vcc_mv); printf("Set Vcc: %d mV\n", vcc_mv);
/* Identify the chip */ /* Identify the chip */
if (do_identify() < 0) { if (do_identify(dev) < 0) {
fprintf(stderr, "fet: identify failed\n"); fprintf(stderr, "fet: identify failed\n");
return NULL; goto fail;
} }
/* Send the magic required by RF2500 and Chronos FETs */ /* 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"); fprintf(stderr, "fet: init magic failed\n");
return NULL; goto fail;
} }
return &fet_device; return (device_t)dev;
fail:
free(dev);
return NULL;
} }

32
fet.h Normal file
View File

@ -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

289
gdb.c
View File

@ -35,43 +35,47 @@
* GDB IO routines * GDB IO routines
*/ */
static int gdb_socket; struct gdb_data {
static int gdb_errno; int sock;
int error;
static char gdb_xbuf[1024]; char xbuf[1024];
static int gdb_head; int head;
static int gdb_tail; int tail;
static char gdb_outbuf[1024]; char outbuf[1024];
static int gdb_outlen; 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; va_list ap;
int len; int len;
va_start(ap, fmt); va_start(ap, fmt);
len = vsnprintf(gdb_outbuf + gdb_outlen, len = vsnprintf(data->outbuf + data->outlen,
sizeof(gdb_outbuf) - gdb_outlen, sizeof(data->outbuf) - data->outlen,
fmt, ap); fmt, ap);
va_end(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) { if (send(data->sock, data->outbuf, data->outlen, 0) < 0) {
gdb_errno = errno; data->error = errno;
perror("gdb: send"); perror("gdb: send");
return -1; return -1;
} }
gdb_outlen = 0; data->outlen = 0;
return 0; return 0;
} }
static int gdb_read(int blocking) static int gdb_read(struct gdb_data *data, int blocking)
{ {
fd_set r; fd_set r;
int len; int len;
@ -81,21 +85,21 @@ static int gdb_read(int blocking)
}; };
FD_ZERO(&r); 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) { blocking ? NULL : &to) < 0) {
perror("gdb: select"); perror("gdb: select");
return -1; return -1;
} }
if (!FD_ISSET(gdb_socket, &r)) if (!FD_ISSET(data->sock, &r))
return 0; 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) { if (len < 0) {
gdb_errno = errno; data->error = errno;
perror("gdb: recv"); perror("gdb: recv");
return -1; return -1;
} }
@ -105,46 +109,46 @@ static int gdb_read(int blocking)
return -1; return -1;
} }
gdb_head = 0; data->head = 0;
gdb_tail = len; data->tail = len;
return 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 -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; int c;
/* If the buffer is empty, receive some more data */ /* 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; return -1;
c = gdb_xbuf[gdb_head]; c = data->xbuf[data->head];
gdb_head++; data->head++;
return c; return c;
} }
static int gdb_flush_ack(void) static int gdb_flush_ack(struct gdb_data *data)
{ {
int c; int c;
do { do {
gdb_outbuf[gdb_outlen] = 0; data->outbuf[data->outlen] = 0;
#ifdef DEBUG_GDB #ifdef DEBUG_GDB
printf("-> %s\n", gdb_outbuf); printf("-> %s\n", data->outbuf);
#endif #endif
if (gdb_flush() < 0) if (gdb_flush(data) < 0)
return -1; return -1;
c = gdb_getc(); c = gdb_getc(data);
if (c < 0) if (c < 0)
return -1; return -1;
} while (c != '+'); } while (c != '+');
@ -152,29 +156,29 @@ static int gdb_flush_ack(void)
return 0; 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 i;
int c = 0; int c = 0;
for (i = 1; i < gdb_outlen; i++) for (i = 1; i < data->outlen; i++)
c = (c + gdb_outbuf[i]) & 0xff; c = (c + data->outbuf[i]) & 0xff;
gdb_printf("#%02x", c); 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) while (*text)
gdb_printf("%02x", *(text++)); gdb_printf(data, "%02x", *(text++));
gdb_packet_end(); gdb_packet_end(data);
return gdb_flush_ack(); return gdb_flush_ack(data);
} }
static int hexval(int c) static int hexval(int c)
@ -189,35 +193,35 @@ static int hexval(int c)
return 0; return 0;
} }
static int gdb_send(const char *msg) static int gdb_send(struct gdb_data *data, const char *msg)
{ {
gdb_packet_start(); gdb_packet_start(data);
gdb_printf("%s", msg); gdb_printf(data, "%s", msg);
gdb_packet_end(); gdb_packet_end(data);
return gdb_flush_ack(); return gdb_flush_ack(data);
} }
/************************************************************************ /************************************************************************
* GDB server * GDB server
*/ */
static int read_registers(void) static int read_registers(struct gdb_data *data)
{ {
u_int16_t regs[DEVICE_NUM_REGS]; u_int16_t regs[DEVICE_NUM_REGS];
int i; int i;
printf("Reading registers\n"); printf("Reading registers\n");
if (device_get()->getregs(regs) < 0) if (data->device->getregs(data->device, regs) < 0)
return gdb_send("E00"); return gdb_send(data, "E00");
gdb_packet_start(); gdb_packet_start(data);
for (i = 0; i < DEVICE_NUM_REGS; i++) for (i = 0; i < DEVICE_NUM_REGS; i++)
gdb_printf("%02x%02x", regs[i] & 0xff, regs[i] >> 8); gdb_printf(data, "%02x%02x", regs[i] & 0xff, regs[i] >> 8);
gdb_packet_end(); gdb_packet_end(data);
return gdb_flush_ack(); return gdb_flush_ack(data);
} }
static int monitor_command(char *buf) static int monitor_command(struct gdb_data *data, char *buf)
{ {
char cmd[128]; char cmd[128];
int len = 0; int len = 0;
@ -229,24 +233,24 @@ static int monitor_command(char *buf)
if (!strcasecmp(cmd, "reset")) { if (!strcasecmp(cmd, "reset")) {
printf("Resetting device\n"); printf("Resetting device\n");
if (device_get()->control(DEVICE_CTL_RESET) < 0) if (data->device->ctl(data->device, DEVICE_CTL_RESET) < 0)
return gdb_send_hex("Reset failed\n"); return gdb_send_hex(data, "Reset failed\n");
} else if (!strcasecmp(cmd, "erase")) { } else if (!strcasecmp(cmd, "erase")) {
printf("Erasing device\n"); printf("Erasing device\n");
if (device_get()->control(DEVICE_CTL_ERASE) < 0) if (data->device->ctl(data->device, DEVICE_CTL_ERASE) < 0)
return gdb_send_hex("Erase failed\n"); 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]; u_int16_t regs[DEVICE_NUM_REGS];
int i; int i;
if (strlen(buf) < DEVICE_NUM_REGS * 4) if (strlen(buf) < DEVICE_NUM_REGS * 4)
return gdb_send("E00"); return gdb_send(data, "E00");
printf("Writing registers\n"); printf("Writing registers\n");
for (i = 0; i < DEVICE_NUM_REGS; i++) { for (i = 0; i < DEVICE_NUM_REGS; i++) {
@ -257,13 +261,13 @@ static int write_registers(char *buf)
buf += 4; buf += 4;
} }
if (device_get()->setregs(regs) < 0) if (data->device->setregs(data->device, regs) < 0)
return gdb_send("E00"); 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, ','); char *length_text = strchr(text, ',');
int length, addr; int length, addr;
@ -272,7 +276,7 @@ static int read_memory(char *text)
if (!length_text) { if (!length_text) {
fprintf(stderr, "gdb: malformed memory read request\n"); fprintf(stderr, "gdb: malformed memory read request\n");
return gdb_send("E00"); return gdb_send(data, "E00");
} }
*(length_text++) = 0; *(length_text++) = 0;
@ -285,18 +289,18 @@ static int read_memory(char *text)
printf("Reading %d bytes from 0x%04x\n", length, addr); printf("Reading %d bytes from 0x%04x\n", length, addr);
if (device_get()->readmem(addr, buf, length) < 0) if (data->device->readmem(data->device, addr, buf, length) < 0)
return gdb_send("E00"); return gdb_send(data, "E00");
gdb_packet_start(); gdb_packet_start(data);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
gdb_printf("%02x", buf[i]); gdb_printf(data, "%02x", buf[i]);
gdb_packet_end(); 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 *data_text = strchr(text, ':');
char *length_text = strchr(text, ','); char *length_text = strchr(text, ',');
@ -306,7 +310,7 @@ static int write_memory(char *text)
if (!(data_text && length_text)) { if (!(data_text && length_text)) {
fprintf(stderr, "gdb: malformed memory write request\n"); fprintf(stderr, "gdb: malformed memory write request\n");
return gdb_send("E00"); return gdb_send(data, "E00");
} }
*(data_text++) = 0; *(data_text++) = 0;
@ -323,75 +327,76 @@ static int write_memory(char *text)
if (buflen != length) { if (buflen != length) {
fprintf(stderr, "gdb: length mismatch\n"); 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); printf("Writing %d bytes to 0x%04x\n", buflen, addr);
if (device_get()->writemem(addr, buf, buflen) < 0) if (data->device->writemem(data->device, addr, buf, buflen) < 0)
return gdb_send("E00"); 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]; u_int16_t regs[DEVICE_NUM_REGS];
if (!*buf) if (!*buf)
return 0; return 0;
if (device_get()->getregs(regs) < 0) if (data->device->getregs(data->device, regs) < 0)
return -1; return -1;
regs[0] = strtoul(buf, NULL, 16); 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]; u_int16_t regs[DEVICE_NUM_REGS];
int i; int i;
if (device_get()->getregs(regs) < 0) if (data->device->getregs(data->device, regs) < 0)
return gdb_send("E00"); return gdb_send(data, "E00");
gdb_packet_start(); gdb_packet_start(data);
gdb_printf("T00"); gdb_printf(data, "T00");
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
gdb_printf("%02x:%02x%02x;", i, regs[i] & 0xff, regs[i] >> 8); gdb_printf(data, "%02x:%02x%02x;", i,
gdb_packet_end(); 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"); printf("Single stepping\n");
if (run_set_pc(buf) < 0 || if (run_set_pc(data, buf) < 0 ||
device_get()->control(DEVICE_CTL_STEP) < 0) data->device->ctl(data->device, DEVICE_CTL_STEP) < 0)
gdb_send("E00"); 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"); printf("Running\n");
if (run_set_pc(buf) < 0 || if (run_set_pc(data, buf) < 0 ||
device_get()->control(DEVICE_CTL_RUN) < 0) { data->device->ctl(data->device, DEVICE_CTL_RUN) < 0) {
gdb_send("E00"); gdb_send(data, "E00");
return run_final_status(); return run_final_status(data);
} }
for (;;) { for (;;) {
device_status_t status = device_get()->wait(0); device_status_t status = data->device->poll(data->device);
if (status == DEVICE_STATUS_ERROR) { if (status == DEVICE_STATUS_ERROR) {
gdb_send("E00"); gdb_send(data, "E00");
return run_final_status(); return run_final_status(data);
} }
if (status == DEVICE_STATUS_HALTED) { if (status == DEVICE_STATUS_HALTED) {
@ -402,8 +407,8 @@ static int run(char *buf)
if (status == DEVICE_STATUS_INTR) if (status == DEVICE_STATUS_INTR)
goto out; goto out;
while (gdb_peek()) { while (gdb_peek(data)) {
int c = gdb_getc(); int c = gdb_getc(data);
if (c < 0) if (c < 0)
return -1; return -1;
@ -416,47 +421,47 @@ static int run(char *buf)
} }
out: out:
if (device_get()->control(DEVICE_CTL_HALT) < 0) if (data->device->ctl(data->device, DEVICE_CTL_HALT) < 0)
gdb_send("E00"); 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]) { switch (buf[0]) {
case '?': /* Return target halt reason */ case '?': /* Return target halt reason */
return gdb_send("T00"); return gdb_send(data, "T00");
case 'g': /* Read registers */ case 'g': /* Read registers */
return read_registers(); return read_registers(data);
case 'G': /* Write registers */ case 'G': /* Write registers */
return write_registers(buf + 1); return write_registers(data, buf + 1);
case 'q': /* Query */ case 'q': /* Query */
if (!strncmp(buf, "qRcmd,", 6)) if (!strncmp(buf, "qRcmd,", 6))
return monitor_command(buf + 6); return monitor_command(data, buf + 6);
break; break;
case 'm': /* Read memory */ case 'm': /* Read memory */
return read_memory(buf + 1); return read_memory(data, buf + 1);
case 'M': /* Write memory */ case 'M': /* Write memory */
return write_memory(buf + 1); return write_memory(data, buf + 1);
case 'c': /* Continue */ case 'c': /* Continue */
return run(buf + 1); return run(data, buf + 1);
case 's': /* Single step */ case 's': /* Single step */
return single_step(buf + 1); return single_step(data, buf + 1);
} }
/* For unknown/unsupported packets, return an empty reply */ /* 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 (;;) { for (;;) {
char buf[1024]; char buf[1024];
@ -467,14 +472,14 @@ static void gdb_reader_loop(void)
/* Wait for packet start */ /* Wait for packet start */
do { do {
c = gdb_getc(); c = gdb_getc(data);
if (c < 0) if (c < 0)
return; return;
} while (c != '$'); } while (c != '$');
/* Read packet payload */ /* Read packet payload */
while (len + 1 < sizeof(buf)) { while (len + 1 < sizeof(buf)) {
c = gdb_getc(); c = gdb_getc(data);
if (c < 0) if (c < 0)
return; return;
if (c == '#') if (c == '#')
@ -486,11 +491,11 @@ static void gdb_reader_loop(void)
buf[len] = 0; buf[len] = 0;
/* Read packet checksum */ /* Read packet checksum */
c = gdb_getc(); c = gdb_getc(data);
if (c < 0) if (c < 0)
return; return;
cksum_recv = hexval(c); cksum_recv = hexval(c);
c = gdb_getc(); c = gdb_getc(data);
if (c < 0) if (c < 0)
return; return;
cksum_recv = (cksum_recv << 4) | hexval(c); 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, " fprintf(stderr, "gdb: bad checksum (calc = 0x%02x, "
"recv = 0x%02x)\n", cksum_calc, cksum_recv); "recv = 0x%02x)\n", cksum_calc, cksum_recv);
fprintf(stderr, "gdb: packet data was: %s\n", buf); fprintf(stderr, "gdb: packet data was: %s\n", buf);
gdb_printf("-"); gdb_printf(data, "-");
if (gdb_flush() < 0) if (gdb_flush(data) < 0)
return; return;
continue; continue;
} }
/* Send acknowledgement */ /* Send acknowledgement */
gdb_printf("+"); gdb_printf(data, "+");
if (gdb_flush() < 0) if (gdb_flush(data) < 0)
return; return;
if (len && process_gdb_command(buf, len) < 0) if (len && process_gdb_command(data, buf, len) < 0)
return; return;
} }
} }
static int gdb_server(int port) static int gdb_server(device_t device, int port)
{ {
int sock; int sock;
int client; int client;
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t len; socklen_t len;
int arg; int arg;
struct gdb_data data;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) { if (sock < 0) {
@ -567,15 +573,16 @@ static int gdb_server(int port)
printf("Client connected from %s:%d\n", printf("Client connected from %s:%d\n",
inet_ntoa(addr.sin_addr), htons(addr.sin_port)); inet_ntoa(addr.sin_addr), htons(addr.sin_port));
gdb_socket = client; data.sock = client;
gdb_errno = 0; data.error = 0;
gdb_head = 0; data.head = 0;
gdb_tail = 0; data.tail = 0;
gdb_outlen = 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) 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 -1;
} }
return gdb_server(port); return gdb_server(cproc_device(cp), port);
} }
static const struct cproc_command command_gdb = { static const struct cproc_command command_gdb = {

10
ihex.c
View File

@ -27,7 +27,8 @@ int ihex_check(FILE *in)
return fgetc(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; u_int8_t cksum = 0;
int i; int i;
@ -46,11 +47,12 @@ static int feed_line(FILE *in, u_int8_t *data, int nbytes, imgfunc_t cb)
return -1; 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); 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]; char buf[128];
int lno = 0; int lno = 0;
@ -83,7 +85,7 @@ int ihex_extract(FILE *in, imgfunc_t cb)
} }
/* Handle the line */ /* 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); fprintf(stderr, "ihex: error on line %d\n", lno);
return -1; return -1;
} }

123
main.c
View File

@ -33,6 +33,78 @@
#include "sym.h" #include "sym.h"
#include "devcmd.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) static void usage(const char *progname)
{ {
fprintf(stderr, fprintf(stderr,
@ -155,14 +227,14 @@ static int parse_cmdline_args(int argc, char **argv,
return 0; 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; const struct fet_transport *trans = NULL;
/* Open a device */ /* Open a device */
if (args->mode == MODE_SIM) { 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) { } else if (args->mode == MODE_UIF_BSL) {
msp430_dev = bsl_open(args->bsl_device); msp430_dev = bsl_open(args->bsl_device);
} else if (args->mode == MODE_RF2500 || args->mode == MODE_UIF) { } 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; return NULL;
} }
device_set(msp430_dev);
return 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) int main(int argc, char **argv)
{ {
const struct device *msp430_dev;
struct cmdline_args args = {0}; struct cmdline_args args = {0};
cproc_t cp; cproc_t cp;
int ret = 0; int ret = 0;
@ -218,22 +313,9 @@ int main(int argc, char **argv)
if (stab_init() < 0) if (stab_init() < 0)
return -1; return -1;
msp430_dev = setup_device(&args); cp = setup_cproc(&args);
if (!msp430_dev) { if (!cp) {
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) {
perror("couldn't set up command parser"); perror("couldn't set up command parser");
if (cp)
cproc_destroy(cp);
msp430_dev->close();
stab_exit(); stab_exit();
return -1; return -1;
} }
@ -254,7 +336,6 @@ int main(int argc, char **argv)
} }
cproc_destroy(cp); cproc_destroy(cp);
msp430_dev->close();
stab_exit(); stab_exit();
return ret; return ret;

View File

@ -320,7 +320,7 @@ static int do_isearch(cproc_t cp,
int addr, int len, const struct isearch_query *q) int addr, int len, const struct isearch_query *q)
{ {
u_int8_t *mbuf; u_int8_t *mbuf;
const struct device *dev = device_get(); device_t dev = cproc_device(cp);
int i; int i;
if (len <= 0 || len > 0x10000 || if (len <= 0 || len > 0x10000 ||
@ -337,7 +337,7 @@ static int do_isearch(cproc_t cp,
return -1; 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"); fprintf(stderr, "isearch: couldn't read device memory\n");
free(mbuf); free(mbuf);
return -1; return -1;

504
sim.c
View File

@ -23,105 +23,40 @@
#include "device.h" #include "device.h"
#include "dis.h" #include "dis.h"
#include "util.h" #include "util.h"
#include "stab.h" #include "sim.h"
#define MEM_SIZE 65536 #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 #define MEM_IO_END 0x200
/* PC at the start of the current instruction */ struct sim_device {
static u_int16_t current_insn; struct device base;
static void io_prefix(const char *prefix, u_int16_t addr, int is_byte) sim_fetch_func_t fetch_func;
{ sim_store_func_t store_func;
char name[64]; void *user_data;
u_int16_t pc = current_insn;
if (!stab_nearest(pc, name, sizeof(name), &pc)) { u_int8_t memory[MEM_SIZE];
printf("%s", name); u_int16_t regs[DEVICE_NUM_REGS];
if (pc)
printf("+0x%x", pc);
} else {
printf("0x%04x", pc);
}
printf(": IO %s.%c: 0x%04x", prefix, is_byte ? 'B' : 'W', addr); int running;
if (!stab_nearest(addr, name, sizeof(name), &addr)) { u_int16_t current_insn;
printf(" (%s", name); int have_breakpoint;
if (addr) u_int16_t breakpoint_addr;
printf("+0x%x", addr); };
printf(")");
}
}
static int fetch_io(u_int16_t addr, int is_byte, u_int32_t *data_ret) #define MEM_GETB(dev, offset) ((dev)->memory[offset])
{ #define MEM_SETB(dev, offset, value) ((dev)->memory[offset] = (value))
io_prefix("READ", addr, is_byte); #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 (;;) { static int fetch_operand(struct sim_device *dev,
char text[128]; int amode, int reg, int is_byte,
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,
u_int16_t *addr_ret, u_int32_t *data_ret) u_int16_t *addr_ret, u_int32_t *data_ret)
{ {
u_int16_t addr = 0; u_int16_t addr = 0;
@ -135,7 +70,7 @@ static int fetch_operand(int amode, int reg, int is_byte,
return 0; return 0;
} }
if (data_ret) if (data_ret)
*data_ret = sim_regs[reg] & mask; *data_ret = dev->regs[reg] & mask;
return 0; return 0;
case MSP430_AMODE_INDEXED: case MSP430_AMODE_INDEXED:
@ -145,11 +80,11 @@ static int fetch_operand(int amode, int reg, int is_byte,
return 0; return 0;
} }
addr = MEM_GETW(sim_regs[MSP430_REG_PC]); addr = MEM_GETW(dev, dev->regs[MSP430_REG_PC]);
sim_regs[MSP430_REG_PC] += 2; dev->regs[MSP430_REG_PC] += 2;
if (reg != MSP430_REG_SR) if (reg != MSP430_REG_SR)
addr += sim_regs[reg]; addr += dev->regs[reg];
break; break;
case MSP430_AMODE_INDIRECT: case MSP430_AMODE_INDIRECT:
@ -164,7 +99,7 @@ static int fetch_operand(int amode, int reg, int is_byte,
*data_ret = 2; *data_ret = 2;
return 0; return 0;
} }
addr = sim_regs[reg]; addr = dev->regs[reg];
break; break;
case MSP430_AMODE_INDIRECT_INC: case MSP430_AMODE_INDIRECT_INC:
@ -178,8 +113,8 @@ static int fetch_operand(int amode, int reg, int is_byte,
*data_ret = mask; *data_ret = mask;
return 0; return 0;
} }
addr = sim_regs[reg]; addr = dev->regs[reg];
sim_regs[reg] += 2; dev->regs[reg] += 2;
break; break;
} }
@ -187,31 +122,42 @@ static int fetch_operand(int amode, int reg, int is_byte,
*addr_ret = addr; *addr_ret = addr;
if (data_ret) { if (data_ret) {
if (addr < MEM_IO_END) *data_ret = MEM_GETW(dev, addr) & mask;
return fetch_io(addr, is_byte, data_ret);
*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; 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) u_int16_t addr, u_int16_t data)
{ {
if (amode == MSP430_AMODE_REGISTER) if (is_byte)
sim_regs[reg] = data; MEM_SETB(dev, addr, data);
else if (addr < MEM_IO_END)
store_io(addr, is_byte, data);
else if (is_byte)
MEM_SETB(addr, data);
else 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) #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; u_int16_t opcode = ins & 0xf000;
int sreg = (ins >> 8) & 0xf; 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 msb = is_byte ? 0x80 : 0x8000;
u_int32_t mask = is_byte ? 0xff : 0xffff; 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; 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) opcode == MSP430_OP_MOV ? NULL : &dst_data) < 0)
return -1; return -1;
@ -244,7 +190,7 @@ static int step_double(u_int16_t ins)
case MSP430_OP_ADD: case MSP430_OP_ADD:
case MSP430_OP_ADDC: case MSP430_OP_ADDC:
if (opcode == MSP430_OP_ADDC || opcode == MSP430_OP_SUBC) 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; MSP430_SR_C) ? 1 : 0;
else if (opcode == MSP430_OP_SUB || opcode == MSP430_OP_CMP) else if (opcode == MSP430_OP_SUB || opcode == MSP430_OP_CMP)
res_data = 1; res_data = 1;
@ -254,42 +200,42 @@ static int step_double(u_int16_t ins)
res_data += src_data; res_data += src_data;
res_data += dst_data; res_data += dst_data;
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
if (!(res_data & mask)) if (!(res_data & mask))
sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
if (res_data & msb) 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)) 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) && if (!((src_data ^ dst_data) & msb) &&
(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; break;
case MSP430_OP_DADD: case MSP430_OP_DADD:
res_data = src_data + dst_data; 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++; res_data++;
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
if (!(res_data & mask)) if (!(res_data & mask))
sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
if (res_data == 1) 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) || if ((is_byte && res_data > 99) ||
(!is_byte && res_data > 9999)) (!is_byte && res_data > 9999))
sim_regs[MSP430_REG_SR] |= MSP430_SR_C; dev->regs[MSP430_REG_SR] |= MSP430_SR_C;
break; break;
case MSP430_OP_BIT: case MSP430_OP_BIT:
case MSP430_OP_AND: case MSP430_OP_AND:
res_data = src_data & dst_data; res_data = src_data & dst_data;
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
sim_regs[MSP430_REG_SR] |= dev->regs[MSP430_REG_SR] |=
(res_data & mask) ? MSP430_SR_C : MSP430_SR_Z; (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
if (res_data & msb) if (res_data & msb)
sim_regs[MSP430_REG_SR] |= MSP430_SR_N; dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
break; break;
case MSP430_OP_BIC: case MSP430_OP_BIC:
@ -302,29 +248,30 @@ static int step_double(u_int16_t ins)
case MSP430_OP_XOR: case MSP430_OP_XOR:
res_data = dst_data ^ src_data; res_data = dst_data ^ src_data;
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
sim_regs[MSP430_REG_SR] |= dev->regs[MSP430_REG_SR] |=
(res_data & mask) ? MSP430_SR_C : MSP430_SR_Z; (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
if (res_data & msb) 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) if (src_data & dst_data & msb)
sim_regs[MSP430_REG_SR] |= MSP430_SR_V; dev->regs[MSP430_REG_SR] |= MSP430_SR_V;
break; break;
default: default:
fprintf(stderr, "sim: invalid double-operand opcode: " fprintf(stderr, "sim: invalid double-operand opcode: "
"0x%04x (PC = 0x%04x)\n", "0x%04x (PC = 0x%04x)\n",
opcode, current_insn); opcode, dev->current_insn);
return -1; return -1;
} }
if (opcode != MSP430_OP_CMP && opcode != MSP430_OP_BIT) 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; 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; u_int16_t opcode = ins & 0xff80;
int is_byte = ins & 0x0040; 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 src_data;
u_int32_t res_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; return -1;
switch (opcode) { switch (opcode) {
@ -344,19 +291,19 @@ static int step_single(u_int16_t ins)
case MSP430_OP_RRA: case MSP430_OP_RRA:
res_data = (src_data >> 1) & ~msb; res_data = (src_data >> 1) & ~msb;
if (opcode == MSP430_OP_RRC) { 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; res_data |= msb;
} else { } else {
res_data |= src_data & msb; res_data |= src_data & msb;
} }
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
if (!(res_data & mask)) if (!(res_data & mask))
sim_regs[MSP430_REG_SR] |= MSP430_SR_Z; dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
if (res_data & msb) if (res_data & msb)
sim_regs[MSP430_REG_SR] |= MSP430_SR_N; dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
if (src_data & 1) if (src_data & 1)
sim_regs[MSP430_REG_SR] |= MSP430_SR_C; dev->regs[MSP430_REG_SR] |= MSP430_SR_C;
break; break;
case MSP430_OP_SWPB: case MSP430_OP_SWPB:
@ -365,53 +312,56 @@ static int step_single(u_int16_t ins)
case MSP430_OP_SXT: case MSP430_OP_SXT:
res_data = src_data & 0xff; res_data = src_data & 0xff;
sim_regs[MSP430_REG_SR] &= ~ARITH_BITS; dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
if (src_data & 0x80) { if (src_data & 0x80) {
res_data |= 0xff00; 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; (res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
break; break;
case MSP430_OP_PUSH: case MSP430_OP_PUSH:
sim_regs[MSP430_REG_SP] -= 2; dev->regs[MSP430_REG_SP] -= 2;
MEM_SETW(sim_regs[MSP430_REG_SP], src_data); MEM_SETW(dev, dev->regs[MSP430_REG_SP], src_data);
break; break;
case MSP430_OP_CALL: case MSP430_OP_CALL:
sim_regs[MSP430_REG_SP] -= 2; dev->regs[MSP430_REG_SP] -= 2;
MEM_SETW(sim_regs[MSP430_REG_SP], sim_regs[MSP430_REG_PC]); MEM_SETW(dev, dev->regs[MSP430_REG_SP],
sim_regs[MSP430_REG_PC] = src_data; dev->regs[MSP430_REG_PC]);
dev->regs[MSP430_REG_PC] = src_data;
break; break;
case MSP430_OP_RETI: case MSP430_OP_RETI:
sim_regs[MSP430_REG_SR] = MEM_GETW(sim_regs[MSP430_REG_SP]); dev->regs[MSP430_REG_SR] =
sim_regs[MSP430_REG_SP] += 2; MEM_GETW(dev, dev->regs[MSP430_REG_SP]);
sim_regs[MSP430_REG_PC] = MEM_GETW(sim_regs[MSP430_REG_SP]); dev->regs[MSP430_REG_SP] += 2;
sim_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; break;
default: default:
fprintf(stderr, "sim: unknown single-operand opcode: 0x%04x " 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; return -1;
} }
if (opcode != MSP430_OP_PUSH && opcode != MSP430_OP_CALL && if (opcode != MSP430_OP_PUSH && opcode != MSP430_OP_CALL &&
opcode != MSP430_OP_RETI) 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; 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 opcode = ins & 0xfc00;
u_int16_t pc_offset = (ins & 0x03ff) << 1; 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) if (pc_offset & 0x0400)
pc_offset |= 0xff800; pc_offset |= 0xff800;
@ -453,32 +403,32 @@ static int step_jump(u_int16_t ins)
} }
if (sr) if (sr)
sim_regs[MSP430_REG_PC] += pc_offset; dev->regs[MSP430_REG_PC] += pc_offset;
return 0; return 0;
} }
static int step_cpu(void) static int step_cpu(struct sim_device *dev)
{ {
u_int16_t ins; u_int16_t ins;
int ret; int ret;
/* Fetch the instruction */ /* Fetch the instruction */
current_insn = sim_regs[MSP430_REG_PC]; dev->current_insn = dev->regs[MSP430_REG_PC];
ins = MEM_GETW(current_insn); ins = MEM_GETW(dev, dev->current_insn);
sim_regs[MSP430_REG_PC] += 2; dev->regs[MSP430_REG_PC] += 2;
/* Handle different instruction types */ /* Handle different instruction types */
if ((ins & 0xf000) >= 0x4000) if ((ins & 0xf000) >= 0x4000)
ret = step_double(ins); ret = step_double(dev, ins);
else if ((ins & 0xf000) >= 0x2000) else if ((ins & 0xf000) >= 0x2000)
ret = step_jump(ins); ret = step_jump(dev, ins);
else else
ret = step_single(ins); ret = step_single(dev, ins);
/* If things went wrong, restart at the current instruction */ /* If things went wrong, restart at the current instruction */
if (ret < 0) if (ret < 0)
sim_regs[MSP430_REG_PC] = current_insn; dev->regs[MSP430_REG_PC] = dev->current_insn;
return ret; return ret;
} }
@ -487,161 +437,155 @@ static int step_cpu(void)
* Device interface * Device interface
*/ */
static enum { static void sim_destroy(device_t dev_base)
RUN_HALTED = 0,
RUN_FREE,
RUN_TO_BREAKPOINT
} run_mode;
static u_int16_t run_breakpoint;
static void sim_close(void)
{ {
if (memory) { free(dev_base);
free(memory);
memory = NULL;
}
} }
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: case DEVICE_CTL_RESET:
memset(sim_regs, 0, sizeof(sim_regs)); memset(dev->regs, 0, sizeof(dev->regs));
sim_regs[MSP430_REG_PC] = MEM_GETW(0xfffe); dev->regs[MSP430_REG_PC] = MEM_GETW(dev, 0xfffe);
return 0; return 0;
case DEVICE_CTL_ERASE: case DEVICE_CTL_ERASE:
memset(memory, 0xff, MEM_SIZE); memset(dev->memory, 0xff, MEM_SIZE);
return 0; return 0;
case DEVICE_CTL_HALT: case DEVICE_CTL_HALT:
run_mode = RUN_HALTED; dev->running = 0;
return 0; return 0;
case DEVICE_CTL_STEP: case DEVICE_CTL_STEP:
return step_cpu(); return step_cpu(dev);
case DEVICE_CTL_RUN_BP:
run_mode = RUN_TO_BREAKPOINT;
ctrlc_reset();
return 0;
case DEVICE_CTL_RUN: case DEVICE_CTL_RUN:
run_mode = RUN_FREE; dev->running = 1;
ctrlc_reset();
return 0; 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--) { ctrlc_reset();
if (run_mode == RUN_TO_BREAKPOINT && while (dev->running && count > 0) {
sim_regs[MSP430_REG_PC] == run_breakpoint) { if (dev->have_breakpoint &&
dev->regs[MSP430_REG_PC] == dev->breakpoint_addr) {
printf("Breakpoint reached\n"); printf("Breakpoint reached\n");
run_mode = RUN_HALTED; dev->running = 0;
return 0; break;
} }
if (sim_regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) { if (dev->regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) {
run_mode = RUN_HALTED;
printf("CPU disabled\n"); printf("CPU disabled\n");
return 0; dev->running = 0;
break;
} }
if (step_cpu() < 0) { if (step_cpu(dev) < 0) {
run_mode = RUN_HALTED; dev->running = 0;
return -1; 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) { struct sim_device *dev = malloc(sizeof(*dev));
do {
int ret = run_burst();
if (ret < 0) if (!dev) {
return DEVICE_STATUS_ERROR; perror("can't allocate memory for simulation");
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");
return NULL; 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); printf("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE);
return &sim_device; return (device_t)dev;
} }

40
sim.h Normal file
View File

@ -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