Abstracted interface to FET driver.
Tested with eZ430-RF2500.
This commit is contained in:
parent
7505ce654d
commit
ce308c5823
|
@ -0,0 +1,54 @@
|
||||||
|
/* MSPDebug - debugging tool for the eZ430
|
||||||
|
* Copyright (C) 2009 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 DEVICE_H_
|
||||||
|
#define DEVICE_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "transport.h"
|
||||||
|
|
||||||
|
#define DEVICE_NUM_REGS 16
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DEVICE_CTL_RESET,
|
||||||
|
DEVICE_CTL_RUN,
|
||||||
|
DEVICE_CTL_HALT,
|
||||||
|
DEVICE_CTL_RUN_BP,
|
||||||
|
DEVICE_CTL_STEP,
|
||||||
|
DEVICE_CTL_ERASE
|
||||||
|
} device_ctl_t;
|
||||||
|
|
||||||
|
struct device {
|
||||||
|
void (*close)(void);
|
||||||
|
int (*control)(device_ctl_t action);
|
||||||
|
int (*wait)(void);
|
||||||
|
int (*breakpoint)(u_int16_t addr);
|
||||||
|
int (*getregs)(u_int16_t *regs);
|
||||||
|
int (*setregs)(const u_int16_t *regs);
|
||||||
|
int (*readmem)(u_int16_t addr, u_int8_t *mem, int len);
|
||||||
|
int (*writemem)(u_int16_t addr, const u_int8_t *mem, int len);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
#endif
|
392
fet.c
392
fet.c
|
@ -26,7 +26,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "fet.h"
|
#include "device.h"
|
||||||
|
|
||||||
#define ARRAY_LEN(a) ((sizeof(a)) / sizeof((a)[0]))
|
#define ARRAY_LEN(a) ((sizeof(a)) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
@ -77,6 +77,23 @@ static int fet_is_rf2500;
|
||||||
#define C_WRITEI2C 35
|
#define C_WRITEI2C 35
|
||||||
#define C_ENTERBOOTLOADER 36
|
#define C_ENTERBOOTLOADER 36
|
||||||
|
|
||||||
|
/* Constants for parameters of various FET commands */
|
||||||
|
#define FET_RUN_FREE 1
|
||||||
|
#define FET_RUN_STEP 2
|
||||||
|
#define FET_RUN_BREAKPOINT 3
|
||||||
|
|
||||||
|
#define FET_RESET_PUC 0x01
|
||||||
|
#define FET_RESET_RST 0x02
|
||||||
|
#define FET_RESET_VCC 0x04
|
||||||
|
#define FET_RESET_ALL 0x07
|
||||||
|
|
||||||
|
#define FET_ERASE_SEGMENT 0
|
||||||
|
#define FET_ERASE_MAIN 1
|
||||||
|
#define FET_ERASE_ALL 2
|
||||||
|
|
||||||
|
#define FET_POLL_RUNNING 0x01
|
||||||
|
#define FET_POLL_BREAKPOINT 0x02
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* Checksum calculation
|
* Checksum calculation
|
||||||
*/
|
*/
|
||||||
|
@ -578,138 +595,158 @@ static int do_identify(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_open(const struct fet_transport *tr, int proto_flags, int vcc_mv)
|
static void fet_close(void)
|
||||||
{
|
{
|
||||||
fet_transport = tr;
|
if (xfer(C_RUN, NULL, 0, 2, FET_RUN_FREE, 1) < 0)
|
||||||
fet_is_rf2500 = proto_flags & FET_PROTO_RF2500;
|
fprintf(stderr, "fet: failed to restart CPU\n");
|
||||||
init_codes();
|
|
||||||
|
|
||||||
if (xfer(C_INITIALIZE, NULL, 0, 0) < 0) {
|
if (xfer(C_CLOSE, NULL, 0, 1, 0) < 0)
|
||||||
fprintf(stderr, "fet_open: open failed\n");
|
fprintf(stderr, "fet: close command failed\n");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fet_version = fet_reply.argv[0];
|
|
||||||
printf("FET protocol version is %d\n", fet_version);
|
|
||||||
|
|
||||||
if (xfer(39, NULL, 0, 1, 4) < 0) {
|
|
||||||
fprintf(stderr, "fet_open: init failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* configure: Spy-Bi-Wire or JTAG */
|
|
||||||
if (xfer(C_CONFIGURE, NULL, 0,
|
|
||||||
2, 8, (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0) < 0) {
|
|
||||||
fprintf(stderr, "fet_open: configure failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Configured for %s\n",
|
|
||||||
(proto_flags & FET_PROTO_SPYBIWIRE) ? "Spy-Bi-Wire" : "JTAG");
|
|
||||||
|
|
||||||
/* Identify the chip */
|
|
||||||
if (do_identify() < 0) {
|
|
||||||
fprintf(stderr, "fet_open: identify failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set VCC */
|
|
||||||
if (xfer(C_VCC, NULL, 0, 2, vcc_mv, 0) < 0) {
|
|
||||||
fprintf(stderr, "fet_open: set VCC failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Set Vcc: %d mV\n", vcc_mv);
|
|
||||||
|
|
||||||
/* I don't know what this is, but it appears to halt the MSP. Without
|
|
||||||
* it, memory reads return garbage. This is RF2500-specific.
|
|
||||||
*/
|
|
||||||
if (fet_is_rf2500 && xfer(0x28, NULL, 0, 2, 0, 0) < 0) {
|
|
||||||
fprintf(stderr, "fet_open: command 0x28 failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Who knows what this is. Without it, register reads don't work.
|
|
||||||
* This is RF2500-specific.
|
|
||||||
*/
|
|
||||||
if (fet_is_rf2500) {
|
|
||||||
static const u_int8_t data[] = {
|
|
||||||
0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x10,
|
|
||||||
0xff, 0x10, 0x40, 0x00, 0x00, 0x02, 0xff, 0x05,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
|
|
||||||
0x01, 0x00, 0xd7, 0x60, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x08, 0x07, 0x10, 0x0e, 0xc4, 0x09, 0x70, 0x17,
|
|
||||||
0x58, 0x1b, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x33, 0x0f, 0x1f, 0x0f,
|
|
||||||
0xff, 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
if (xfer(0x29, data, sizeof(data), 4, 0, 0x39, 0x31,
|
|
||||||
sizeof(data)) < 0) {
|
|
||||||
fprintf(stderr, "fet_open: command 0x29 failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fet_reset(int flags)
|
|
||||||
{
|
|
||||||
int wh = flags & FET_RESET_HALT ? 0 : 1;
|
|
||||||
int wr = flags & FET_RESET_RELEASE ? 1 : 0;
|
|
||||||
|
|
||||||
if (xfer(C_RESET, NULL, 0, 3, flags & FET_RESET_ALL, wh, wr) < 0) {
|
|
||||||
fprintf(stderr, "fet_reset: reset failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fet_close(void)
|
|
||||||
{
|
|
||||||
if (xfer(C_CLOSE, NULL, 0, 1, 0) < 0) {
|
|
||||||
fprintf(stderr, "fet_shutdown: close command failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fet_transport->close();
|
fet_transport->close();
|
||||||
fet_transport = NULL;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_get_context(u_int16_t *regs)
|
static int do_run(int type)
|
||||||
|
{
|
||||||
|
if (xfer(C_RUN, NULL, 0, 2, type, 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: failed to restart CPU\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_halt(void)
|
||||||
|
{
|
||||||
|
if (xfer(C_STATE, NULL, 0, 1, 1) < 0) {
|
||||||
|
fprintf(stderr, "fet: failed to halt CPU\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_erase(void)
|
||||||
|
{
|
||||||
|
if (xfer(C_RESET, NULL, 0, 3, FET_RESET_ALL, 0, 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: reset before erase failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xfer(C_CONFIGURE, NULL, 0, 2, 2, 0x26) < 0) {
|
||||||
|
fprintf(stderr, "fet: config (1) failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xfer(C_CONFIGURE, NULL, 0, 2, 5, 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: config (2) failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xfer(C_ERASE, NULL, 0, 3, FET_ERASE_ALL, 0x1000, 0x100) < 0) {
|
||||||
|
fprintf(stderr, "fet: erase command failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fet_wait(void)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
/* Without this delay, breakpoints can get lost. */
|
||||||
|
if (usleep(500000) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (xfer(C_STATE, NULL, 0, 1, 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: polling failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fet_reply.argv[0] & FET_POLL_RUNNING))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fet_control(device_ctl_t action)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case DEVICE_CTL_RESET:
|
||||||
|
return do_reset();
|
||||||
|
|
||||||
|
case DEVICE_CTL_RUN:
|
||||||
|
return do_run(FET_RUN_FREE);
|
||||||
|
|
||||||
|
case DEVICE_CTL_RUN_BP:
|
||||||
|
return do_run(FET_RUN_BREAKPOINT);
|
||||||
|
|
||||||
|
case DEVICE_CTL_HALT:
|
||||||
|
return do_halt();
|
||||||
|
|
||||||
|
case DEVICE_CTL_STEP:
|
||||||
|
if (do_run(FET_RUN_STEP) < 0)
|
||||||
|
return -1;
|
||||||
|
if (fet_wait() < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DEVICE_CTL_ERASE:
|
||||||
|
return do_erase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fet_breakpoint(u_int16_t addr)
|
||||||
|
{
|
||||||
|
if (xfer(C_BREAKPOINT, NULL, 0, 2, 0, addr) < 0) {
|
||||||
|
fprintf(stderr, "fet: set breakpoint failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fet_getregs(u_int16_t *regs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (xfer(C_READREGISTERS, NULL, 0, 0) < 0)
|
if (xfer(C_READREGISTERS, NULL, 0, 0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (fet_reply.datalen < FET_NUM_REGS * 4) {
|
if (fet_reply.datalen < DEVICE_NUM_REGS * 4) {
|
||||||
fprintf(stderr, "fet_get_context: short reply (%d bytes)\n",
|
fprintf(stderr, "fet: short reply (%d bytes)\n",
|
||||||
fet_reply.datalen);
|
fet_reply.datalen);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < FET_NUM_REGS; i++)
|
for (i = 0; i < DEVICE_NUM_REGS; i++)
|
||||||
regs[i] = BUFFER_WORD(fet_reply.data, i * 4);
|
regs[i] = BUFFER_WORD(fet_reply.data, i * 4);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_set_context(u_int16_t *regs)
|
static int fet_setregs(const u_int16_t *regs)
|
||||||
{
|
{
|
||||||
u_int8_t buf[FET_NUM_REGS * 4];;
|
u_int8_t buf[DEVICE_NUM_REGS * 4];;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
for (i = 0; i < FET_NUM_REGS; i++) {
|
for (i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||||
buf[i * 4] = regs[i] & 0xff;
|
buf[i * 4] = regs[i] & 0xff;
|
||||||
buf[i * 4 + 1] = regs[i] >> 8;
|
buf[i * 4 + 1] = regs[i] >> 8;
|
||||||
}
|
}
|
||||||
|
@ -722,14 +759,14 @@ int fet_set_context(u_int16_t *regs)
|
||||||
1, 0xffff);
|
1, 0xffff);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "fet_set_context: context set failed\n");
|
fprintf(stderr, "fet: context set failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_read_mem(u_int16_t addr, u_int8_t *buffer, int count)
|
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;
|
||||||
|
@ -755,7 +792,7 @@ int fet_read_mem(u_int16_t addr, u_int8_t *buffer, int count)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_write_mem(u_int16_t addr, const u_int8_t *buffer, int count)
|
int fet_writemem(u_int16_t addr, const u_int8_t *buffer, int count)
|
||||||
{
|
{
|
||||||
while (count) {
|
while (count) {
|
||||||
int plen = count > 128 ? 128 : count;
|
int plen = count > 128 ? 128 : count;
|
||||||
|
@ -769,8 +806,8 @@ int fet_write_mem(u_int16_t addr, const u_int8_t *buffer, int count)
|
||||||
1, addr);
|
1, addr);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "fet_write_mem: failed to write "
|
fprintf(stderr, "fet: failed to write to 0x%04x\n",
|
||||||
"to 0x%04x\n", addr);
|
addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,69 +819,92 @@ int fet_write_mem(u_int16_t addr, const u_int8_t *buffer, int count)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fet_erase(int type, u_int16_t addr, int len)
|
const static struct device fet_device = {
|
||||||
|
.close = fet_close,
|
||||||
|
.control = fet_control,
|
||||||
|
.wait = fet_wait,
|
||||||
|
.breakpoint = fet_breakpoint,
|
||||||
|
.getregs = fet_getregs,
|
||||||
|
.setregs = fet_setregs,
|
||||||
|
.readmem = fet_readmem,
|
||||||
|
.writemem = fet_writemem
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct device *fet_open(const struct fet_transport *tr,
|
||||||
|
int proto_flags, int vcc_mv)
|
||||||
{
|
{
|
||||||
if (xfer(C_CONFIGURE, NULL, 0, 2, 2, 0x26) < 0) {
|
fet_transport = tr;
|
||||||
fprintf(stderr, "fet_erase: config (1) failed\n");
|
fet_is_rf2500 = proto_flags & FET_PROTO_RF2500;
|
||||||
return -1;
|
init_codes();
|
||||||
|
|
||||||
|
if (xfer(C_INITIALIZE, NULL, 0, 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: open failed\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfer(C_CONFIGURE, NULL, 0, 2, 5, 0) < 0) {
|
fet_version = fet_reply.argv[0];
|
||||||
fprintf(stderr, "fet_erase: config (2) failed\n");
|
printf("FET protocol version is %d\n", fet_version);
|
||||||
return -1;
|
|
||||||
|
if (xfer(39, NULL, 0, 1, 4) < 0) {
|
||||||
|
fprintf(stderr, "fet: init failed\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfer(C_ERASE, NULL, 0, 3, type, addr, len) < 0) {
|
/* configure: Spy-Bi-Wire or JTAG */
|
||||||
fprintf(stderr, "fet_erase: erase command failed\n");
|
if (xfer(C_CONFIGURE, NULL, 0,
|
||||||
return -1;
|
2, 8, (proto_flags & FET_PROTO_SPYBIWIRE) ? 1 : 0) < 0) {
|
||||||
|
fprintf(stderr, "fet: configure failed\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
printf("Configured for %s\n",
|
||||||
}
|
(proto_flags & FET_PROTO_SPYBIWIRE) ? "Spy-Bi-Wire" : "JTAG");
|
||||||
|
|
||||||
int fet_poll(void)
|
/* Identify the chip */
|
||||||
{
|
if (do_identify() < 0) {
|
||||||
/* Without this delay, breakpoints can get lost. */
|
fprintf(stderr, "fet: identify failed\n");
|
||||||
if (usleep(500000) < 0)
|
return NULL;
|
||||||
return -1;
|
}
|
||||||
|
|
||||||
if (xfer(C_STATE, NULL, 0, 1, 0) < 0) {
|
/* set VCC */
|
||||||
fprintf(stderr, "fet_poll: polling failed\n");
|
if (xfer(C_VCC, NULL, 0, 2, vcc_mv, 0) < 0) {
|
||||||
return -1;
|
fprintf(stderr, "fet: set VCC failed\n");
|
||||||
}
|
return NULL;
|
||||||
|
}
|
||||||
return fet_reply.argv[0];
|
|
||||||
}
|
printf("Set Vcc: %d mV\n", vcc_mv);
|
||||||
|
|
||||||
int fet_run(int type)
|
/* I don't know what this is, but it appears to halt the MSP. Without
|
||||||
{
|
* it, memory reads return garbage. This is RF2500-specific.
|
||||||
int wr = type & FET_RUN_RELEASE ? 1 : 0;
|
*/
|
||||||
|
if (fet_is_rf2500 && xfer(0x28, NULL, 0, 2, 0, 0) < 0) {
|
||||||
type &= ~FET_RUN_RELEASE;
|
fprintf(stderr, "fet: command 0x28 failed\n");
|
||||||
if (xfer(C_RUN, NULL, 0, 2, type, wr) < 0) {
|
return NULL;
|
||||||
fprintf(stderr, "fet_run: run failed\n");
|
}
|
||||||
return -1;
|
|
||||||
}
|
/* Who knows what this is. Without it, register reads don't work.
|
||||||
|
* This is RF2500-specific.
|
||||||
return 0;
|
*/
|
||||||
}
|
if (fet_is_rf2500) {
|
||||||
|
static const u_int8_t data[] = {
|
||||||
int fet_stop(void)
|
0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x10,
|
||||||
{
|
0xff, 0x10, 0x40, 0x00, 0x00, 0x02, 0xff, 0x05,
|
||||||
if (xfer(C_STATE, NULL, 0, 1, 1) < 0) {
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
|
||||||
fprintf(stderr, "fet_stop: stop failed\n");
|
0x01, 0x00, 0xd7, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||||
return -1;
|
0x08, 0x07, 0x10, 0x0e, 0xc4, 0x09, 0x70, 0x17,
|
||||||
}
|
0x58, 0x1b, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
return 0;
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
}
|
0x00, 0x00, 0x00, 0x00, 0x33, 0x0f, 0x1f, 0x0f,
|
||||||
|
0xff, 0xff
|
||||||
int fet_break(int which, u_int16_t addr)
|
};
|
||||||
{
|
|
||||||
if (xfer(C_BREAKPOINT, NULL, 0, 2, which, addr) < 0) {
|
if (xfer(0x29, data, sizeof(data), 4, 0, 0x39, 0x31,
|
||||||
fprintf(stderr, "fet_break: set breakpoint failed\n");
|
sizeof(data)) < 0) {
|
||||||
return -1;
|
fprintf(stderr, "fet: command 0x29 failed\n");
|
||||||
}
|
return NULL;
|
||||||
|
}
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
return &fet_device;
|
||||||
}
|
}
|
||||||
|
|
98
fet.h
98
fet.h
|
@ -1,98 +0,0 @@
|
||||||
/* MSPDebug - debugging tool for the eZ430
|
|
||||||
* Copyright (C) 2009 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 "transport.h"
|
|
||||||
|
|
||||||
/* Start up the FET controller by specifying a transport, a voltage in
|
|
||||||
* millivolts and a set of protocol mode flags.
|
|
||||||
*/
|
|
||||||
#define FET_PROTO_SPYBIWIRE 0x01
|
|
||||||
#define FET_PROTO_RF2500 0x02
|
|
||||||
|
|
||||||
int fet_open(const struct fet_transport *transport,
|
|
||||||
int proto_flags, int vcc_mv);
|
|
||||||
|
|
||||||
/* Shut down the connection to the FET. This also closes the underlying
|
|
||||||
* transport.
|
|
||||||
*/
|
|
||||||
int fet_close(void);
|
|
||||||
|
|
||||||
/* Issue a reset to the CPU. The CPU can be reset via any combination
|
|
||||||
* of three methods, and you can choose whether or not to leave the CPU
|
|
||||||
* halted after reset.
|
|
||||||
*/
|
|
||||||
#define FET_RESET_PUC 0x01
|
|
||||||
#define FET_RESET_RST 0x02
|
|
||||||
#define FET_RESET_VCC 0x04
|
|
||||||
#define FET_RESET_ALL 0x07
|
|
||||||
#define FET_RESET_HALT 0x10
|
|
||||||
#define FET_RESET_RELEASE 0x20
|
|
||||||
|
|
||||||
int fet_reset(int flags);
|
|
||||||
|
|
||||||
/* Retrieve and store register values. There are 16 16-bit registers in
|
|
||||||
* the MSP430 CPU. regs must always be a pointer to an array of 16
|
|
||||||
* u_int16_t.
|
|
||||||
*/
|
|
||||||
#define FET_NUM_REGS 16
|
|
||||||
|
|
||||||
int fet_get_context(u_int16_t *regs);
|
|
||||||
int fet_set_context(u_int16_t *regs);
|
|
||||||
|
|
||||||
/* Erase the CPU's internal flash. */
|
|
||||||
#define FET_ERASE_SEGMENT 0
|
|
||||||
#define FET_ERASE_MAIN 1
|
|
||||||
#define FET_ERASE_ALL 2
|
|
||||||
|
|
||||||
int fet_erase(int type, u_int16_t addr, int len);
|
|
||||||
|
|
||||||
/* Read and write memory. fet_write_mem can be used to reflash the
|
|
||||||
* device, but only after an erase.
|
|
||||||
*/
|
|
||||||
int fet_read_mem(u_int16_t addr, u_int8_t *buffer, int count);
|
|
||||||
int fet_write_mem(u_int16_t addr, const u_int8_t *buffer, int count);
|
|
||||||
|
|
||||||
/* Fetch the device status. If the device is currently running, then
|
|
||||||
* the FET_POLL_RUNNING flag will be set. FET_POLL_BREAKPOINT is set
|
|
||||||
* when the device hits the preset breakpoint, and then resets on the
|
|
||||||
* next call to fet_poll().
|
|
||||||
*/
|
|
||||||
#define FET_POLL_RUNNING 0x01
|
|
||||||
#define FET_POLL_BREAKPOINT 0x02
|
|
||||||
|
|
||||||
int fet_poll(void);
|
|
||||||
|
|
||||||
/* CPU run/step/stop control. While the CPU is running, memory and
|
|
||||||
* registers are inaccessible (only fet_poll() or fet_stop()) will
|
|
||||||
* work.
|
|
||||||
*/
|
|
||||||
#define FET_RUN_FREE 1
|
|
||||||
#define FET_RUN_STEP 2
|
|
||||||
#define FET_RUN_BREAKPOINT 3
|
|
||||||
#define FET_RUN_RELEASE 0x10
|
|
||||||
|
|
||||||
int fet_run(int type);
|
|
||||||
int fet_stop(void);
|
|
||||||
|
|
||||||
/* Set a breakpoint address */
|
|
||||||
int fet_break(int which, u_int16_t addr);
|
|
||||||
|
|
||||||
#endif
|
|
64
main.c
64
main.c
|
@ -25,10 +25,12 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
#include "fet.h"
|
#include "device.h"
|
||||||
#include "binfile.h"
|
#include "binfile.h"
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
|
|
||||||
|
static const struct device *msp430_dev;
|
||||||
|
|
||||||
void hexdump(int addr, const u_int8_t *data, int len)
|
void hexdump(int addr, const u_int8_t *data, int len)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
@ -93,7 +95,7 @@ char *get_arg(char **text)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REG_COLUMNS 4
|
#define REG_COLUMNS 4
|
||||||
#define REG_ROWS ((FET_NUM_REGS + REG_COLUMNS - 1) / REG_COLUMNS)
|
#define REG_ROWS ((DEVICE_NUM_REGS + REG_COLUMNS - 1) / REG_COLUMNS)
|
||||||
|
|
||||||
static void show_regs(u_int16_t *regs)
|
static void show_regs(u_int16_t *regs)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +108,7 @@ static void show_regs(u_int16_t *regs)
|
||||||
for (j = 0; j < REG_COLUMNS; j++) {
|
for (j = 0; j < REG_COLUMNS; j++) {
|
||||||
int k = j * REG_ROWS + i;
|
int k = j * REG_ROWS + i;
|
||||||
|
|
||||||
if (k < FET_NUM_REGS)
|
if (k < DEVICE_NUM_REGS)
|
||||||
printf("(r%02d: %04x) ", k, regs[k]);
|
printf("(r%02d: %04x) ", k, regs[k]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -154,7 +156,7 @@ static int cmd_md(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 (fet_read_mem(offset, buf, blen) < 0)
|
if (msp430_dev->readmem(offset, buf, blen) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
hexdump(offset, buf, blen);
|
hexdump(offset, buf, blen);
|
||||||
|
|
||||||
|
@ -243,7 +245,7 @@ static int cmd_dis(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fet_read_mem(offset, buf, length) < 0)
|
if (msp430_dev->readmem(offset, buf, length) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
disassemble(offset, (u_int8_t *)buf, length);
|
disassemble(offset, (u_int8_t *)buf, length);
|
||||||
|
@ -252,20 +254,20 @@ static int cmd_dis(char **arg)
|
||||||
|
|
||||||
static int cmd_reset(char **arg)
|
static int cmd_reset(char **arg)
|
||||||
{
|
{
|
||||||
return fet_reset(FET_RESET_ALL | FET_RESET_HALT);
|
return msp430_dev->control(DEVICE_CTL_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_regs(char **arg)
|
static int cmd_regs(char **arg)
|
||||||
{
|
{
|
||||||
u_int16_t regs[FET_NUM_REGS];
|
u_int16_t regs[DEVICE_NUM_REGS];
|
||||||
u_int8_t code[16];
|
u_int8_t code[16];
|
||||||
|
|
||||||
if (fet_get_context(regs) < 0)
|
if (msp430_dev->getregs(regs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
show_regs(regs);
|
show_regs(regs);
|
||||||
|
|
||||||
/* Try to disassemble the instruction at PC */
|
/* Try to disassemble the instruction at PC */
|
||||||
if (fet_read_mem(regs[0], code, sizeof(code)) < 0)
|
if (msp430_dev->readmem(regs[0], code, sizeof(code)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
disassemble(regs[0], (u_int8_t *)code, sizeof(code));
|
disassemble(regs[0], (u_int8_t *)code, sizeof(code));
|
||||||
|
@ -285,26 +287,19 @@ static int cmd_run(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fet_break(0, addr);
|
msp430_dev->breakpoint(addr);
|
||||||
} else {
|
|
||||||
fet_break(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fet_run(bp_text ? FET_RUN_BREAKPOINT : FET_RUN_FREE) < 0)
|
if (msp430_dev->control(bp_text ?
|
||||||
|
DEVICE_CTL_RUN_BP : DEVICE_CTL_RUN) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
printf("Running. Press Ctrl+C to interrupt...");
|
printf("Running. Press Ctrl+C to interrupt...");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
msp430_dev->wait();
|
||||||
for (;;) {
|
|
||||||
int r = fet_poll();
|
|
||||||
|
|
||||||
if (r < 0 || !(r & FET_POLL_RUNNING))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (fet_stop() < 0)
|
|
||||||
|
if (msp430_dev->control(DEVICE_CTL_HALT) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return cmd_regs(NULL);
|
return cmd_regs(NULL);
|
||||||
|
@ -316,7 +311,7 @@ static int cmd_set(char **arg)
|
||||||
char *val_text = get_arg(arg);
|
char *val_text = get_arg(arg);
|
||||||
int reg;
|
int reg;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
u_int16_t regs[FET_NUM_REGS];
|
u_int16_t regs[DEVICE_NUM_REGS];
|
||||||
|
|
||||||
if (!(reg_text && val_text)) {
|
if (!(reg_text && val_text)) {
|
||||||
fprintf(stderr, "set: must specify a register and a value\n");
|
fprintf(stderr, "set: must specify a register and a value\n");
|
||||||
|
@ -332,15 +327,15 @@ static int cmd_set(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg < 0 || reg >= FET_NUM_REGS) {
|
if (reg < 0 || reg >= DEVICE_NUM_REGS) {
|
||||||
fprintf(stderr, "set: register out of range: %d\n", reg);
|
fprintf(stderr, "set: register out of range: %d\n", reg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fet_get_context(regs) < 0)
|
if (msp430_dev->getregs(regs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
regs[reg] = value;
|
regs[reg] = value;
|
||||||
if (fet_set_context(regs) < 0)
|
if (msp430_dev->setregs(regs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
show_regs(regs);
|
show_regs(regs);
|
||||||
|
@ -349,9 +344,7 @@ static int cmd_set(char **arg)
|
||||||
|
|
||||||
static int cmd_step(char **arg)
|
static int cmd_step(char **arg)
|
||||||
{
|
{
|
||||||
if (fet_run(FET_RUN_STEP) < 0)
|
if (msp430_dev->control(DEVICE_CTL_STEP) < 0)
|
||||||
return -1;
|
|
||||||
if (fet_poll() < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return cmd_regs(NULL);
|
return cmd_regs(NULL);
|
||||||
|
@ -383,13 +376,13 @@ static int prog_flush(void)
|
||||||
|
|
||||||
if (!prog_have_erased) {
|
if (!prog_have_erased) {
|
||||||
printf("Erasing...\n");
|
printf("Erasing...\n");
|
||||||
if (fet_erase(FET_ERASE_ALL, 0x1000, 0x100) < 0)
|
if (msp430_dev->control(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 (fet_write_mem(prog_addr, prog_buf, wlen) < 0)
|
if (msp430_dev->writemem(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);
|
||||||
|
@ -442,7 +435,7 @@ static int cmd_prog(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fet_reset(FET_RESET_ALL | FET_RESET_HALT) < 0) {
|
if (msp430_dev->control(DEVICE_CTL_HALT) < 0) {
|
||||||
fclose(in);
|
fclose(in);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -711,7 +704,8 @@ int main(int argc, char **argv)
|
||||||
/* Then initialize the device */
|
/* Then initialize the device */
|
||||||
if (!want_jtag)
|
if (!want_jtag)
|
||||||
flags |= FET_PROTO_SPYBIWIRE;
|
flags |= FET_PROTO_SPYBIWIRE;
|
||||||
if (fet_open(trans, flags, 3000) < 0)
|
msp430_dev = fet_open(trans, flags, 3000);
|
||||||
|
if (!msp430_dev)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
|
@ -721,8 +715,6 @@ int main(int argc, char **argv)
|
||||||
reader_loop();
|
reader_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fet_run(FET_RUN_FREE | FET_RUN_RELEASE);
|
msp430_dev->close();
|
||||||
fet_close();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue