Device drivers are now objects.
This commit is contained in:
parent
1f98eb4339
commit
204aa31291
|
@ -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
182
bsl.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
12
cproc.c
|
@ -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
11
cproc.h
|
@ -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
133
devcmd.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
18
device.c
18
device.c
|
@ -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;
|
||||||
|
|
57
device.h
57
device.h
|
@ -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
10
elf32.c
|
@ -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
501
fet.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
289
gdb.c
|
@ -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
10
ihex.c
|
@ -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
123
main.c
|
@ -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;
|
||||||
|
|
4
rtools.c
4
rtools.c
|
@ -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
504
sim.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue