fet3: driver for eZ-FET debuggers.

This driver is experimental. It supports flash/memory access and basic
CPU control. It doesn't support breakpoints.
This commit is contained in:
Daniel Beer 2013-09-08 13:41:55 +12:00
parent 8ec807fe20
commit 0e58358bb1
9 changed files with 1856 additions and 1 deletions

View File

@ -146,6 +146,9 @@ OBJ=\
drivers/pif.o \ drivers/pif.o \
drivers/loadbsl.o \ drivers/loadbsl.o \
drivers/loadbsl_fw.o \ drivers/loadbsl_fw.o \
drivers/hal_proto.o \
drivers/v3hil.o \
drivers/fet3.o \
formats/binfile.o \ formats/binfile.o \
formats/coff.o \ formats/coff.o \
formats/elf32.o \ formats/elf32.o \

308
drivers/fet3.c Normal file
View File

@ -0,0 +1,308 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 Daniel Beer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include "util/ctrlc.h"
#include "dis.h"
#include "output.h"
#include "comport.h"
#include "cdc_acm.h"
#include "fet3.h"
#include "chipinfo.h"
#include "v3hil.h"
struct fet3 {
struct device base;
struct v3hil hil;
};
static int fet3_readmem(device_t dev_base, address_t addr,
uint8_t *mem, address_t len)
{
struct fet3 *fet = (struct fet3 *)dev_base;
if (addr & 1) {
uint8_t word[2];
if (v3hil_read(&fet->hil, addr - 1, word, 2) < 0)
return -1;
mem[0] = word[1];
addr++;
len--;
}
while (len >= 2) {
int r = 128;
if (r > len)
r = len;
r = v3hil_read(&fet->hil, addr, mem, r & ~1);
if (r < 0)
return -1;
addr += r;
mem += r;
len -= r;
}
if (len) {
uint8_t word[2];
if (v3hil_read(&fet->hil, addr, word, 2) < 0)
return -1;
mem[0] = word[0];
addr++;
len--;
}
return 0;
}
static int fet3_writemem(device_t dev_base, address_t addr,
const uint8_t *mem, address_t len)
{
struct fet3 *fet = (struct fet3 *)dev_base;
if (addr & 1) {
uint8_t word[2];
if (v3hil_read(&fet->hil, addr - 1, word, 2) < 0)
return -1;
word[1] = mem[0];
if (v3hil_write(&fet->hil, addr - 1, word, 2) < 0)
return -1;
addr++;
len--;
}
while (len >= 2) {
int r = 128;
if (r > len)
r = len;
r = v3hil_write(&fet->hil, addr, mem, r & ~1);
if (r < 0)
return -1;
addr += r;
mem += r;
len -= r;
}
if (len) {
uint8_t word[2];
if (v3hil_read(&fet->hil, addr, word, 2) < 0)
return -1;
word[0] = mem[0];
if (v3hil_write(&fet->hil, addr, word, 2) < 0)
return -1;
addr++;
len--;
}
return 0;
}
static int fet3_setregs(device_t dev_base, const address_t *regs)
{
struct fet3 *fet = (struct fet3 *)dev_base;
memcpy(fet->hil.regs, regs, sizeof(fet->hil.regs));
return -1;
}
static int fet3_getregs(device_t dev_base, address_t *regs)
{
struct fet3 *fet = (struct fet3 *)dev_base;
memcpy(regs, fet->hil.regs, sizeof(fet->hil.regs));
return 0;
}
static int fet3_ctl(device_t dev_base, device_ctl_t type)
{
struct fet3 *fet = (struct fet3 *)dev_base;
switch (type) {
case DEVICE_CTL_RESET:
if (v3hil_sync(&fet->hil) < 0)
return -1;
return v3hil_update_regs(&fet->hil);
case DEVICE_CTL_RUN:
if (v3hil_flush_regs(&fet->hil) < 0)
return -1;
return v3hil_context_restore(&fet->hil, 0);
case DEVICE_CTL_HALT:
if (v3hil_context_save(&fet->hil) < 0)
return -1;
return v3hil_update_regs(&fet->hil);
case DEVICE_CTL_STEP:
if (v3hil_flush_regs(&fet->hil) < 0)
return -1;
if (v3hil_single_step(&fet->hil) < 0)
return -1;
return v3hil_update_regs(&fet->hil);
}
return 0;
}
static device_status_t fet3_poll(device_t dev_base)
{
/* We don't support breakpoints yet, so there's nothing to poll
* for.
*/
delay_ms(500);
if (ctrlc_check())
return DEVICE_STATUS_INTR;
return DEVICE_STATUS_RUNNING;
}
static int fet3_erase(device_t dev_base, device_erase_type_t type,
address_t addr)
{
struct fet3 *fet = (struct fet3 *)dev_base;
if (type == DEVICE_ERASE_ALL) {
printc_err("fet3: mass erase is not supported\n");
return -1;
}
return v3hil_erase(&fet->hil,
(type == DEVICE_ERASE_MAIN) ? ADDRESS_NONE : addr);
}
static int debug_init(struct fet3 *fet, const struct device_args *args)
{
if (v3hil_comm_init(&fet->hil) < 0)
return -1;
printc_dbg("Set VCC: %d mV\n", args->vcc_mv);
if (v3hil_set_vcc(&fet->hil, args->vcc_mv) < 0)
return -1;
printc_dbg("Starting interface...\n");
if (v3hil_start_jtag(&fet->hil,
(args->flags & DEVICE_FLAG_JTAG) ?
V3HIL_JTAG_JTAG : V3HIL_JTAG_SPYBIWIRE) < 0)
return -1;
if (args->forced_chip_id) {
fet->hil.chip = chipinfo_find_by_name(args->forced_chip_id);
if (!fet->hil.chip) {
printc_err("fet3: unknown chip: %s\n",
args->forced_chip_id);
goto fail_stop_jtag;
}
} else {
if (v3hil_identify(&fet->hil) < 0)
goto fail_stop_jtag;
}
if (v3hil_configure(&fet->hil) < 0)
goto fail_stop_jtag;
if (v3hil_update_regs(&fet->hil) < 0)
goto fail_stop_jtag;
return 0;
fail_stop_jtag:
v3hil_stop_jtag(&fet->hil);
return -1;
}
static device_t fet3_open(const struct device_args *args)
{
struct fet3 *fet;
transport_t trans;
if (args->flags & DEVICE_FLAG_TTY)
trans = comport_open(args->path, 460800);
else
trans = cdc_acm_open(args->path, args->requested_serial,
460800, 0x2047, 0x0013);
if (!trans) {
printc_err("fet3: failed to open transport\n");
return NULL;
}
fet = malloc(sizeof(*fet));
if (!fet) {
printc_err("fet3: malloc: %s\n", last_error());
trans->ops->destroy(trans);
return NULL;
}
memset(fet, 0, sizeof(*fet));
fet->base.type = &device_ezfet;
/* Breakpoints aren't supported yet */
fet->base.max_breakpoints = 0;
v3hil_init(&fet->hil, trans, 0);
if (debug_init(fet, args) < 0) {
trans->ops->destroy(trans);
free(fet);
return NULL;
}
return &fet->base;
}
static void fet3_destroy(device_t dev_base)
{
struct fet3 *fet = (struct fet3 *)dev_base;
transport_t tr = fet->hil.hal.trans;
v3hil_flush_regs(&fet->hil);
v3hil_context_restore(&fet->hil, 1);
v3hil_stop_jtag(&fet->hil);
tr->ops->destroy(tr);
free(fet);
}
const struct device_class device_ezfet = {
.name = "ezfet",
.help = "Texas Instruments eZ-FET",
.open = fet3_open,
.destroy = fet3_destroy,
.readmem = fet3_readmem,
.writemem = fet3_writemem,
.getregs = fet3_getregs,
.setregs = fet3_setregs,
.ctl = fet3_ctl,
.poll = fet3_poll,
.erase = fet3_erase
};

27
drivers/fet3.h Normal file
View File

@ -0,0 +1,27 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 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 FET3_H_
#define FET3_H_
#include "device.h"
/* eZ-FET */
extern const struct device_class device_ezfet;
#endif

196
drivers/hal_proto.c Normal file
View File

@ -0,0 +1,196 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2013 Daniel Beer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "util.h"
#include "output.h"
#include "hal_proto.h"
void hal_proto_init(struct hal_proto *p, transport_t trans,
hal_proto_flags_t flags)
{
memset(p, 0, sizeof(*p));
p->trans = trans;
p->flags = flags;
p->ref_id = 0;
}
int hal_proto_send(struct hal_proto *p, hal_proto_type_t type,
const uint8_t *data, int length)
{
uint8_t buf[512];
size_t len = 0;
if (length > HAL_MAX_PAYLOAD) {
printc_err("hal_proto_send: payload too long: %d\n", length);
return -1;
}
buf[len++] = length + 3;
buf[len++] = type;
buf[len++] = p->ref_id;
buf[len++] = 0;
p->ref_id = (p->ref_id + 1) & 0x7f;
memcpy(buf + len, data, length);
len += length;
if (len & 1)
buf[len++] = 0;
if (p->flags & HAL_PROTO_CHECKSUM) {
size_t i;
uint8_t sum_l = 0xff;
uint8_t sum_h = 0xff;
for (i = 0; i < len; i += 2) {
sum_l ^= buf[i];
sum_h ^= buf[i + 1];
}
buf[len++] = sum_l;
buf[len++] = sum_h;
}
if (p->trans->ops->send(p->trans, buf, len) < 0) {
printc_err("hal_proto_send: type: 0x%02x\n", type);
return -1;
}
return 0;
}
int hal_proto_receive(struct hal_proto *p, uint8_t *buf, int max_len)
{
uint8_t rx_buf[512];
uint8_t sum_h = 0xff;
uint8_t sum_l = 0xff;
int rx_len = 0;
int len;
int i;
for (;;) {
int r = p->trans->ops->recv(p->trans, rx_buf + rx_len,
sizeof(rx_buf) - rx_len);
if (r <= 0) {
printc_err("hal_proto_recv: read error\n");
return -1;
}
rx_len += r;
if (rx_len) {
const size_t expect_len =
rx_buf[0] + 4 - (rx_buf[0] & 1);
if (rx_len == expect_len)
break;
if (rx_len > expect_len) {
printc_err("hal_proto_recv: length "
"mismatch\n");
return -1;
}
}
}
if (rx_len < 6) {
printc_err("hal_proto_recv: short read: %d\n", rx_len);
return -1;
}
for (i = 0; i < rx_len; i += 2) {
sum_h ^= rx_buf[i];
sum_l ^= rx_buf[i + 1];
}
if (sum_h || sum_l) {
printc_err("hal_proto_recv: bad checksum\n");
return -1;
}
len = rx_buf[0] - 3;
p->type = rx_buf[1];
p->ref = rx_buf[2];
p->seq = rx_buf[3];
if (len > max_len) {
printc_err("hal_proto_recv: reply too long\n");
return -1;
}
memcpy(buf, rx_buf + 4, len);
return len;
}
int hal_proto_execute(struct hal_proto *p, uint8_t fid,
const uint8_t *data, int len)
{
uint8_t fdata[HAL_MAX_PAYLOAD];
if (len + 2 > HAL_MAX_PAYLOAD) {
printc_err("hal_proto_execute: payload too big: %d\n", len);
return -1;
}
fdata[0] = fid;
fdata[1] = 0;
memcpy(fdata + 2, data, len);
if (hal_proto_send(p, HAL_PROTO_TYPE_CMD_EXECUTE, fdata, len + 2) < 0)
goto fail;
p->length = 0;
do {
int r = hal_proto_receive(p, p->payload + p->length,
sizeof(p->payload) - p->length);
if (r < 0)
goto fail;
if ((p->type == HAL_PROTO_TYPE_EXCEPTION) && (r >= 2)) {
printc_err("hal_proto_execute: HAL exception: 0x%04x\n",
LE_WORD(p->payload, p->length));
goto fail;
}
if (p->type == HAL_PROTO_TYPE_ACKNOWLEDGE)
break;
if (p->type != HAL_PROTO_TYPE_DATA) {
printc_err("hal_proto_execute: no data "
"(got type 0x%02x)\n", p->type);
goto fail;
}
if (hal_proto_send(p, HAL_PROTO_TYPE_ACKNOWLEDGE, NULL, 0) < 0)
goto fail;
p->length += r;
} while (p->ref & 0x80);
return 0;
fail:
printc_err("hal_proto_execute: fid: 0x%02x\n", fid);
return -1;
}

100
drivers/hal_proto.h Normal file
View File

@ -0,0 +1,100 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2013 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 HAL_PROTO_H_
#define HAL_PROTO_H_
#include <stdint.h>
#include <stddef.h>
#include "transport.h"
/* Low-level HAL message types */
typedef enum {
HAL_PROTO_TYPE_UP_INIT = 0x51,
HAL_PROTO_TYPE_UP_ERASE = 0x52,
HAL_PROTO_TYPE_UP_WRITE = 0x53,
HAL_PROTO_TYPE_UP_READ = 0x54,
HAL_PROTO_TYPE_UP_CORE = 0x55,
HAL_PROTO_TYPE_DCDC_CALIBRATE = 0x56,
HAL_PROTO_TYPE_DCDC_INIT_INTERFACE = 0x57,
HAL_PROTO_TYPE_DCDC_SUB_MCU_VERSION = 0x58,
HAL_PROTO_TYPE_DCDC_LAYER_VERSION = 0x59,
HAL_PROTO_TYPE_DCDC_POWER_DOWN = 0x60,
HAL_PROTO_TYPE_DCDC_SET_VCC = 0x61,
HAL_PROTO_TYPE_DCDC_RESTART = 0x62,
HAL_PROTO_TYPE_CMD_LEGACY = 0x7e,
HAL_PROTO_TYPE_CMD_SYNC = 0x80,
HAL_PROTO_TYPE_CMD_EXECUTE = 0x81,
HAL_PROTO_TYPE_CMD_EXECUTE_LOOP = 0x82,
HAL_PROTO_TYPE_CMD_LOAD = 0x83,
HAL_PROTO_TYPE_CMD_LOAD_CONTINUED = 0x84,
HAL_PROTO_TYPE_CMD_DATA = 0x85,
HAL_PROTO_TYPE_CMD_KILL = 0x86,
HAL_PROTO_TYPE_CMD_MOVE = 0x87,
HAL_PROTO_TYPE_CMD_UNLOAD = 0x88,
HAL_PROTO_TYPE_CMD_BYPASS = 0x89,
HAL_PROTO_TYPE_CMD_EXECUTE_LOOP_CONT = 0x8a,
HAL_PROTO_TYPE_CMD_COM_RESET = 0x8b,
HAL_PROTO_TYPE_CMD_PAUSE_LOOP = 0x8c,
HAL_PROTO_TYPE_CMD_RESUME_LOOP = 0x8d,
HAL_PROTO_TYPE_ACKNOWLEDGE = 0x91,
HAL_PROTO_TYPE_EXCEPTION = 0x92,
HAL_PROTO_TYPE_DATA = 0x93,
HAL_PROTO_TYPE_DATA_REQUEST = 0x94,
HAL_PROTO_TYPE_STATUS = 0x95
} hal_proto_type_t;
typedef enum {
HAL_PROTO_CHECKSUM = 0x01
} hal_proto_flags_t;
#define HAL_MAX_PAYLOAD 253
struct hal_proto {
transport_t trans;
hal_proto_flags_t flags;
uint8_t ref_id;
/* Receive parameters */
hal_proto_type_t type;
uint8_t ref;
uint8_t seq;
/* Execute data */
int length;
uint8_t payload[4096];
};
/* Initialize a HAL protocol interpreter */
void hal_proto_init(struct hal_proto *p, transport_t trans,
hal_proto_flags_t flags);
/* Send a low-level HAL command */
int hal_proto_send(struct hal_proto *p, hal_proto_type_t type,
const uint8_t *data, int length);
/* Receive a low-level HAL response */
int hal_proto_receive(struct hal_proto *p, uint8_t *buf, int max_len);
/* Execute a high-level function. The reply data is kept in the payload
* buffer.
*/
int hal_proto_execute(struct hal_proto *p, uint8_t fid,
const uint8_t *data, int len);
#endif

1103
drivers/v3hil.c Normal file

File diff suppressed because it is too large Load Diff

113
drivers/v3hil.h Normal file
View File

@ -0,0 +1,113 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 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 V3HIL_H_
#define V3HIL_H_
#include "hal_proto.h"
#include "chipinfo.h"
#include "util.h"
#include "device.h"
#include "transport.h"
/* Clock calibration data */
struct v3hil_calibrate {
uint8_t is_cal;
/* Calibration parameters for write/erase funclets */
uint16_t cal0;
uint16_t cal1;
};
struct v3hil {
struct hal_proto hal;
const struct chipinfo *chip;
/* 0x89 is old-style CPU */
uint8_t jtag_id;
/* Lower 8 bits of saved WDTCTL */
uint8_t wdtctl;
/* Register cache: this must be flushed before restoring context
* and updated after saving context.
*/
address_t regs[DEVICE_NUM_REGS];
struct v3hil_calibrate cal;
};
/* Initialize data, associate transport */
void v3hil_init(struct v3hil *h, transport_t trans,
hal_proto_flags_t flags);
/* Reset communications and probe HAL. */
int v3hil_comm_init(struct v3hil *h);
/* Set voltage */
int v3hil_set_vcc(struct v3hil *h, int vcc_mv);
/* Start/stop JTAG controller */
typedef enum {
V3HIL_JTAG_JTAG = 0,
V3HIL_JTAG_SPYBIWIRE = 1
} v3hil_jtag_type_t;
int v3hil_start_jtag(struct v3hil *h, v3hil_jtag_type_t);
int v3hil_stop_jtag(struct v3hil *h);
/* Synchronize JTAG and reset the chip. This is the only operation which
* can be done pre-configuration.
*/
int v3hil_sync(struct v3hil *h);
/* Run the chip identification procedure. chip will be filled out if
* this is successful. This calls v3hil_sync().
*/
int v3hil_identify(struct v3hil *h);
/* Configure for the current chip */
int v3hil_configure(struct v3hil *h);
/* Read/write memory. LSB of address and size are ignored. Number of
* bytes read is returned, which may be less than requested if a memory
* map boundary is crossed.
*/
int v3hil_read(struct v3hil *h, address_t addr,
uint8_t *mem, address_t size);
int v3hil_write(struct v3hil *h, address_t addr,
const uint8_t *mem, address_t size);
/* Erase flash. If address is specified, a segment erase is performed.
* Otherwise, ADDRESS_NONE indicates that a main memory erase should be
* performed.
*/
int v3hil_erase(struct v3hil *h, address_t segment);
/* Read/write register cache. */
int v3hil_update_regs(struct v3hil *h);
int v3hil_flush_regs(struct v3hil *h);
/* Restore context (run) and save context (halt). */
int v3hil_context_restore(struct v3hil *h, int free);
int v3hil_context_save(struct v3hil *h);
/* Single-step the CPU. You must handle the register cache yourself. */
int v3hil_single_step(struct v3hil *h);
#endif

View File

@ -184,6 +184,9 @@ supported for Linux. A parallel port device must be specified via the
.IP "\fBload-bsl\fR" .IP "\fBload-bsl\fR"
Connect to a USB bootloader. The stub bootloader will be used to load a Connect to a USB bootloader. The stub bootloader will be used to load a
fuller-featured bootloader into RAM for execution. fuller-featured bootloader into RAM for execution.
.IP "\fBezfet\fR"
This driver is for Texas Instruments' eZ-FET devices. It supports USB
and TTY access. It does not support breakpoint control.
.SH COMMANDS .SH COMMANDS
MSPDebug can accept commands either through an interactive prompt, or MSPDebug can accept commands either through an interactive prompt, or
non-interactively when specified on the command line. The supported non-interactively when specified on the command line. The supported

View File

@ -55,6 +55,7 @@
#include "input_async.h" #include "input_async.h"
#include "pif.h" #include "pif.h"
#include "loadbsl.h" #include "loadbsl.h"
#include "fet3.h"
#ifdef __CYGWIN__ #ifdef __CYGWIN__
#include <sys/cygwin.h> #include <sys/cygwin.h>
@ -84,7 +85,8 @@ static const struct device_class *const driver_table[] = {
&device_tilib, &device_tilib,
&device_goodfet, &device_goodfet,
&device_pif, &device_pif,
&device_loadbsl &device_loadbsl,
&device_ezfet
}; };
static const char *version_text = static const char *version_text =