Merge pull request #669 from blacksphere/v1.6.2-rc0
V1.6.2 rc0: Unify PC-Hosted BMP Add CMSIS-DAP and Jlink Add high level BMP remote commands Clean up command line interface and debug messages
This commit is contained in:
commit
f5e305e237
|
@ -16,4 +16,5 @@ tags
|
|||
*.b#*
|
||||
blackmagic_upgrade
|
||||
*.exe
|
||||
*.elf
|
||||
.vscode
|
||||
|
|
|
@ -10,7 +10,7 @@ before_install:
|
|||
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2.sig
|
||||
- gpg --trust-model always --verify libftdi1-1.2.tar.bz2.sig
|
||||
- tar -xjf libftdi1-1.2.tar.bz2
|
||||
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev
|
||||
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev
|
||||
|
||||
install:
|
||||
- cd libftdi1-1.2
|
||||
|
|
23
README.md
23
README.md
|
@ -23,3 +23,26 @@ makes [SWO viewing as simple as connecting to a serial port](https://github.com/
|
|||
See online documentation at https://github.com/blacksphere/blackmagic/wiki
|
||||
|
||||
Binaries from the latest automated build are at http://builds.blacksphere.co.nz/blackmagic
|
||||
|
||||
BLACKMAGIC
|
||||
==========
|
||||
|
||||
You can also build blackmagic as a PC hosted application
|
||||
"make PROBE_HOST=hosted"
|
||||
|
||||
This builds the same GDB server, that is running on the Black Magic Probe.
|
||||
While connection to the Black Magic Probe GDB server is via serial line,
|
||||
connection to the PC-Hosted GDB server is via TCP port 2000 for the first
|
||||
GDB server and higher for more invokations. Use "tar(get) ext(ented) :2000"
|
||||
to connect.
|
||||
PC-hosted BMP GDB server can talk to the Black Magic Probe itself,
|
||||
ST-LinkV2 and V3, CMSIS-DAP, JLINK and FTDI MPSSE based debuggers.
|
||||
|
||||
When connected to a single BMP supported probe, starting "blackmagic" w/o any
|
||||
arguments starts the server. When several BMP supported probes are connected,
|
||||
their types, position and serial number is displayed and the program exits.
|
||||
Add "-P (position)" to the next invokation to select one.
|
||||
|
||||
PC hosted BMP also allows to flash, read and verify a binary file, by default
|
||||
starting at 0x08000000. The "-t" argument displays information about the
|
||||
connected target. Use "-h " to get a list of supported options.
|
||||
|
|
34
src/Makefile
34
src/Makefile
|
@ -1,6 +1,6 @@
|
|||
PROBE_HOST ?= native
|
||||
PLATFORM_DIR = platforms/$(PROBE_HOST)
|
||||
VPATH += $(PLATFORM_DIR) platforms/common target
|
||||
VPATH += $(PLATFORM_DIR) target
|
||||
ENABLE_DEBUG ?=
|
||||
|
||||
ifneq ($(V), 1)
|
||||
|
@ -9,8 +9,8 @@ Q := @
|
|||
endif
|
||||
|
||||
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
||||
-std=gnu99 -g3 -MD \
|
||||
-I. -Iinclude -Iplatforms/common -I$(PLATFORM_DIR)
|
||||
-std=gnu99 -g3 -MD -I./target \
|
||||
-I. -Iinclude -I$(PLATFORM_DIR)
|
||||
|
||||
ifeq ($(ENABLE_DEBUG), 1)
|
||||
CFLAGS += -DENABLE_DEBUG
|
||||
|
@ -32,6 +32,7 @@ SRC = \
|
|||
gdb_packet.c \
|
||||
hex_utils.c \
|
||||
jtag_devs.c \
|
||||
jtag_scan.c \
|
||||
lmi.c \
|
||||
lpc_common.c \
|
||||
lpc11xx.c \
|
||||
|
@ -45,6 +46,7 @@ SRC = \
|
|||
nrf51.c \
|
||||
nxpke04.c \
|
||||
platform.c \
|
||||
remote.c \
|
||||
sam3x.c \
|
||||
sam4l.c \
|
||||
samd.c \
|
||||
|
@ -58,23 +60,29 @@ SRC = \
|
|||
|
||||
include $(PLATFORM_DIR)/Makefile.inc
|
||||
|
||||
OPT_FLAGS ?= -O2
|
||||
OPT_FLAGS ?= -Og
|
||||
CFLAGS += $(OPT_FLAGS)
|
||||
LDFLAGS += $(OPT_FLAGS)
|
||||
|
||||
ifndef TARGET
|
||||
TARGET=blackmagic
|
||||
ifdef PC_HOSTED
|
||||
TARGET = blackmagic
|
||||
else
|
||||
TARGET = blackmagic.elf
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NO_OWN_LL
|
||||
SRC += jtagtap_generic.c swdptap_generic.c
|
||||
endif
|
||||
|
||||
ifndef OWN_HL
|
||||
SRC += jtag_scan.c jtagtap.c swdptap.c
|
||||
SRC += remote.c
|
||||
ifdef PC_HOSTED
|
||||
CFLAGS += -DPC_HOSTED=1
|
||||
else
|
||||
CFLAGS += -DOWN_HL
|
||||
SRC += swdptap.c jtagtap.c
|
||||
CFLAGS += -DPC_HOSTED=0
|
||||
VPATH += platforms/common
|
||||
CFLAGS += -Iplatforms/common
|
||||
endif
|
||||
|
||||
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
|
||||
|
@ -91,19 +99,21 @@ $(TARGET): include/version.h $(OBJ)
|
|||
@echo " AS $<"
|
||||
$(Q)$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.bin: %
|
||||
ifndef PC_HOSTED
|
||||
%.bin: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
$(Q)$(OBJCOPY) -O binary $^ $@
|
||||
|
||||
%.hex: %
|
||||
%.hex: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
$(Q)$(OBJCOPY) -O ihex $^ $@
|
||||
endif
|
||||
|
||||
.PHONY: clean host_clean all_platforms FORCE
|
||||
|
||||
clean: host_clean
|
||||
$(Q)echo " CLEAN"
|
||||
-$(Q)$(RM) *.o *.d *~ blackmagic $(HOSTFILES)
|
||||
-$(Q)$(RM) *.o *.d *.elf *~ $(TARGET) $(HOSTFILES)
|
||||
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
||||
|
||||
all_platforms:
|
||||
|
|
|
@ -60,7 +60,7 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
|
|||
static bool cmd_traceswo(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
static bool cmd_heapinfo(target *t, int argc, const char **argv);
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
|
||||
|
@ -85,14 +85,14 @@ const struct command_s cmd_list[] = {
|
|||
#endif
|
||||
#endif
|
||||
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
|
||||
#endif
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
bool connect_assert_srst;
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
bool debug_bmp;
|
||||
#endif
|
||||
long cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */
|
||||
|
@ -135,8 +135,8 @@ bool cmd_version(target *t, int argc, char **argv)
|
|||
(void)t;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#if defined PC_HOSTED
|
||||
gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT
|
||||
#if PC_HOSTED == 1
|
||||
gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT()
|
||||
", Version " FIRMWARE_VERSION "\n");
|
||||
#else
|
||||
gdb_outf("Black Magic Probe (Firmware " FIRMWARE_VERSION ") (Hardware Version %d)\n", platform_hwversion());
|
||||
|
@ -171,7 +171,8 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
|
|||
(void)t;
|
||||
uint8_t irlens[argc];
|
||||
|
||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||
if (platform_target_voltage())
|
||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||
|
||||
if (argc > 1) {
|
||||
/* Accept a list of IR lengths on command line */
|
||||
|
@ -186,7 +187,11 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
|
|||
int devs = -1;
|
||||
volatile struct exception e;
|
||||
TRY_CATCH (e, EXCEPTION_ALL) {
|
||||
#if PC_HOSTED == 1
|
||||
devs = platform_jtag_scan(argc > 1 ? irlens : NULL);
|
||||
#else
|
||||
devs = jtag_scan(argc > 1 ? irlens : NULL);
|
||||
#endif
|
||||
}
|
||||
switch (e.type) {
|
||||
case EXCEPTION_TIMEOUT:
|
||||
|
@ -212,7 +217,8 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
|
|||
(void)t;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||
if (platform_target_voltage())
|
||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||
|
||||
if(connect_assert_srst)
|
||||
platform_srst_set_val(true); /* will be deasserted after attach */
|
||||
|
@ -220,8 +226,12 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
|
|||
int devs = -1;
|
||||
volatile struct exception e;
|
||||
TRY_CATCH (e, EXCEPTION_ALL) {
|
||||
#if PC_HOSTED == 1
|
||||
devs = platform_adiv5_swdp_scan();
|
||||
#else
|
||||
devs = adiv5_swdp_scan();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
switch (e.type) {
|
||||
case EXCEPTION_TIMEOUT:
|
||||
gdb_outf("Timeout during scan. Is target stuck in WFI?\n");
|
||||
|
@ -357,11 +367,7 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
|
|||
#ifdef PLATFORM_HAS_TRACESWO
|
||||
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
||||
{
|
||||
#if defined(STM32L0) || defined(STM32F3) || defined(STM32F4)
|
||||
extern char serial_no[13];
|
||||
#else
|
||||
extern char serial_no[9];
|
||||
#endif
|
||||
extern char *serial_no;
|
||||
(void)t;
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
uint32_t baudrate = SWO_DEFAULT_BAUD;
|
||||
|
@ -389,7 +395,7 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
|
|||
}
|
||||
}
|
||||
}
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED) && defined(ENABLE_DEBUG)
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) && defined(ENABLE_DEBUG)
|
||||
if (debug_bmp) {
|
||||
#if TRACESWO_PROTOCOL == 2
|
||||
gdb_outf("baudrate: %lu ", baudrate);
|
||||
|
@ -412,7 +418,7 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
static bool cmd_debug_bmp(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)t;
|
||||
|
|
|
@ -26,7 +26,7 @@ struct exception *innermost_exception;
|
|||
void raise_exception(uint32_t type, const char *msg)
|
||||
{
|
||||
struct exception *e;
|
||||
DEBUG("Exception: %s\n", msg);
|
||||
DEBUG_WARN("Exception: %s\n", msg);
|
||||
for (e = innermost_exception; e; e = e->outer) {
|
||||
if (e->mask & type) {
|
||||
e->type = type;
|
||||
|
|
|
@ -120,7 +120,8 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||
gdb_putpacketz("E02");
|
||||
break;
|
||||
}
|
||||
DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
|
||||
DEBUG_GDB("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
|
||||
addr, len);
|
||||
uint8_t mem[len];
|
||||
if (target_mem_read(cur_target, mem, addr, len))
|
||||
gdb_putpacketz("E01");
|
||||
|
@ -145,7 +146,8 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||
gdb_putpacketz("E02");
|
||||
break;
|
||||
}
|
||||
DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
|
||||
DEBUG_GDB("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
|
||||
addr, len);
|
||||
uint8_t mem[len];
|
||||
unhexify(mem, pbuf + hex, len);
|
||||
if (target_mem_write(cur_target, addr, mem, len))
|
||||
|
@ -242,7 +244,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||
if (in_syscall) {
|
||||
return hostio_reply(tc, pbuf, size);
|
||||
} else {
|
||||
DEBUG("*** F packet when not in syscall! '%s'\n", pbuf);
|
||||
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf);
|
||||
gdb_putpacketz("");
|
||||
}
|
||||
break;
|
||||
|
@ -295,7 +297,8 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||
gdb_putpacketz("E02");
|
||||
break;
|
||||
}
|
||||
DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
|
||||
DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
|
||||
addr, len);
|
||||
if (target_mem_write(cur_target, addr, pbuf+bin, len))
|
||||
gdb_putpacketz("E01");
|
||||
else
|
||||
|
@ -319,7 +322,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||
break;
|
||||
|
||||
default: /* Packet not implemented */
|
||||
DEBUG("*** Unsupported packet: %s\n", pbuf);
|
||||
DEBUG_GDB("*** Unsupported packet: %s\n", pbuf);
|
||||
gdb_putpacketz("");
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +413,7 @@ handle_q_packet(char *packet, int len)
|
|||
gdb_putpacket_f("C%lx", generic_crc32(cur_target, addr, alen));
|
||||
|
||||
} else {
|
||||
DEBUG("*** Unsupported packet: %s\n", packet);
|
||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||
gdb_putpacket("", 0);
|
||||
}
|
||||
}
|
||||
|
@ -478,7 +481,7 @@ handle_v_packet(char *packet, int plen)
|
|||
|
||||
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
|
||||
/* Erase Flash Memory */
|
||||
DEBUG("Flash Erase %08lX %08lX\n", addr, len);
|
||||
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
|
||||
if(!cur_target) { gdb_putpacketz("EFF"); return; }
|
||||
|
||||
if(!flash_mode) {
|
||||
|
@ -495,7 +498,7 @@ handle_v_packet(char *packet, int plen)
|
|||
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
|
||||
/* Write Flash Memory */
|
||||
len = plen - bin;
|
||||
DEBUG("Flash Write %08lX %08lX\n", addr, len);
|
||||
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
|
||||
if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
|
||||
gdb_putpacketz("OK");
|
||||
else
|
||||
|
@ -507,7 +510,7 @@ handle_v_packet(char *packet, int plen)
|
|||
flash_mode = 0;
|
||||
|
||||
} else {
|
||||
DEBUG("*** Unsupported packet: %s\n", packet);
|
||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||
gdb_putpacket("", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ int gdb_getpacket(char *packet, int size)
|
|||
packet[0] = gdb_if_getchar();
|
||||
if (packet[0]==0x04) return 1;
|
||||
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
|
||||
#ifndef OWN_HL
|
||||
#if PC_HOSTED == 0
|
||||
if (packet[0]==REMOTE_SOM) {
|
||||
/* This is probably a remote control packet
|
||||
* - get and handle it */
|
||||
|
@ -118,16 +118,16 @@ int gdb_getpacket(char *packet, int size)
|
|||
gdb_if_putchar('+', 1); /* send ack */
|
||||
packet[i] = 0;
|
||||
|
||||
#ifdef DEBUG_GDBPACKET
|
||||
DEBUG("%s : ", __func__);
|
||||
#if PC_HOSTED == 1
|
||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
||||
for(int j = 0; j < i; j++) {
|
||||
c = packet[j];
|
||||
if ((c >= 32) && (c < 127))
|
||||
DEBUG("%c", c);
|
||||
DEBUG_GDB_WIRE("%c", c);
|
||||
else
|
||||
DEBUG("\\x%02X", c);
|
||||
DEBUG_GDB_WIRE("\\x%02X", c);
|
||||
}
|
||||
DEBUG("\n");
|
||||
DEBUG_GDB_WIRE("\n");
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
@ -141,18 +141,16 @@ void gdb_putpacket(const char *packet, int size)
|
|||
int tries = 0;
|
||||
|
||||
do {
|
||||
#ifdef DEBUG_GDBPACKET
|
||||
DEBUG("%s : ", __func__);
|
||||
#endif
|
||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
||||
csum = 0;
|
||||
gdb_if_putchar('$', 0);
|
||||
for(i = 0; i < size; i++) {
|
||||
c = packet[i];
|
||||
#ifdef DEBUG_GDBPACKET
|
||||
#if PC_HOSTED == 1
|
||||
if ((c >= 32) && (c < 127))
|
||||
DEBUG("%c", c);
|
||||
DEBUG_GDB_WIRE("%c", c);
|
||||
else
|
||||
DEBUG("\\x%02X", c);
|
||||
DEBUG_GDB_WIRE("\\x%02X", c);
|
||||
#endif
|
||||
if((c == '$') || (c == '#') || (c == '}')) {
|
||||
gdb_if_putchar('}', 0);
|
||||
|
@ -167,9 +165,7 @@ void gdb_putpacket(const char *packet, int size)
|
|||
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
||||
gdb_if_putchar(xmit_csum[0], 0);
|
||||
gdb_if_putchar(xmit_csum[1], 1);
|
||||
#ifdef DEBUG_GDBPACKET
|
||||
DEBUG("\n");
|
||||
#endif
|
||||
DEBUG_GDB_WIRE("\n");
|
||||
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#ifndef __GDB_IF_H
|
||||
#define __GDB_IF_H
|
||||
|
||||
#if !defined(NO_LIBOPENCM3)
|
||||
#if PC_HOSTED == 0
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
|
||||
#endif
|
||||
|
|
|
@ -37,8 +37,116 @@
|
|||
#include "platform.h"
|
||||
#include "platform_support.h"
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG printf
|
||||
enum BMP_DEBUG {
|
||||
BMP_DEBUG_NONE = 0,
|
||||
BMP_DEBUG_INFO = 1,
|
||||
BMP_DEBUG_GDB = 2,
|
||||
BMP_DEBUG_TARGET = 4,
|
||||
BMP_DEBUG_PROBE = 8,
|
||||
BMP_DEBUG_WIRE = 0x10,
|
||||
BMP_DEBUG_MAX = 0x20,
|
||||
BMP_DEBUG_STDOUT = 0x8000,
|
||||
};
|
||||
|
||||
#if PC_HOSTED == 0
|
||||
/* For BMP debug output on a firmware BMP platform, using
|
||||
* BMP PC-Hosted is the preferred way. Printing DEBUG_WARN
|
||||
* and DEBUG_INFO is kept for comptibiluty.
|
||||
*/
|
||||
# if defined(ENABLE_DEBUG)
|
||||
# define DEBUG_WARN printf
|
||||
# define DEBUG_INFO printf
|
||||
# else
|
||||
# define DEBUG_WARN(...)
|
||||
# define DEBUG_INFO(...)
|
||||
# endif
|
||||
# define DEBUG_GDB(...)
|
||||
# define DEBUG_TARGET(...)
|
||||
# define DEBUG_PROBE(...)
|
||||
# define DEBUG_WIRE(...)
|
||||
# define DEBUG_GDB_WIRE(...)
|
||||
#else
|
||||
# include <stdarg.h>
|
||||
extern int cl_debuglevel;
|
||||
|
||||
static inline void DEBUG_WARN(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_INFO(const char *format, ...)
|
||||
{
|
||||
if (~cl_debuglevel & BMP_DEBUG_INFO)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
if (cl_debuglevel & BMP_DEBUG_STDOUT)
|
||||
vfprintf(stdout, format, ap);
|
||||
else
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_GDB(const char *format, ...)
|
||||
{
|
||||
if (~cl_debuglevel & BMP_DEBUG_GDB)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_GDB_WIRE(const char *format, ...)
|
||||
{
|
||||
if ((cl_debuglevel & (BMP_DEBUG_GDB | BMP_DEBUG_WIRE)) !=
|
||||
(BMP_DEBUG_GDB | BMP_DEBUG_WIRE))
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_TARGET(const char *format, ...)
|
||||
{
|
||||
if (~cl_debuglevel & BMP_DEBUG_TARGET)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_PROBE(const char *format, ...)
|
||||
{
|
||||
if (~cl_debuglevel & BMP_DEBUG_PROBE)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void DEBUG_WIRE(const char *format, ...)
|
||||
{
|
||||
if (~cl_debuglevel & BMP_DEBUG_WIRE)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ALIGN(x, n) (((x) + (n) - 1) & ~((n) - 1))
|
||||
|
|
|
@ -21,13 +21,12 @@
|
|||
#ifndef __JTAGTAP_H
|
||||
#define __JTAGTAP_H
|
||||
|
||||
typedef struct jtag_proc_s {
|
||||
/* Note: Signal names are as for the device under test. */
|
||||
|
||||
int jtagtap_init(void);
|
||||
void (*jtagtap_reset)(void);
|
||||
|
||||
void jtagtap_reset(void);
|
||||
|
||||
uint8_t jtagtap_next(const uint8_t TMS, const uint8_t TDI);
|
||||
uint8_t (*jtagtap_next)(const uint8_t TMS, const uint8_t TDI);
|
||||
/* tap_next executes one state transision in the JTAG TAP state machine:
|
||||
* - Ensure TCK is low
|
||||
* - Assert the values of TMS and TDI
|
||||
|
@ -36,30 +35,39 @@ uint8_t jtagtap_next(const uint8_t TMS, const uint8_t TDI);
|
|||
* - Release TCK.
|
||||
*/
|
||||
|
||||
void jtagtap_tms_seq(uint32_t MS, int ticks);
|
||||
void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
void (*jtagtap_tms_seq)(uint32_t MS, int ticks);
|
||||
void (*jtagtap_tdi_tdo_seq)
|
||||
(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
/* Shift out a sequence on MS and DI, capture data to DO.
|
||||
* - This is not endian safe: First byte will always be first shifted out.
|
||||
* - DO may be NULL to ignore captured data.
|
||||
* - DO may be point to the same address as DI.
|
||||
*/
|
||||
void (*jtagtap_tdi_seq)
|
||||
(const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
} jtag_proc_t;
|
||||
extern jtag_proc_t jtag_proc;
|
||||
|
||||
/* generic soft reset: 1, 1, 1, 1, 1, 0 */
|
||||
#define jtagtap_soft_reset() \
|
||||
jtagtap_tms_seq(0x1F, 6)
|
||||
jtag_proc.jtagtap_tms_seq(0x1F, 6)
|
||||
|
||||
/* Goto Shift-IR: 1, 1, 0, 0 */
|
||||
#define jtagtap_shift_ir() \
|
||||
jtagtap_tms_seq(0x03, 4)
|
||||
jtag_proc.jtagtap_tms_seq(0x03, 4)
|
||||
|
||||
/* Goto Shift-DR: 1, 0, 0 */
|
||||
#define jtagtap_shift_dr() \
|
||||
jtagtap_tms_seq(0x01, 3)
|
||||
jtag_proc.jtagtap_tms_seq(0x01, 3)
|
||||
|
||||
/* Goto Run-test/Idle: 1, 1, 0 */
|
||||
#define jtagtap_return_idle() \
|
||||
jtagtap_tms_seq(0x01, 2)
|
||||
jtag_proc.jtagtap_tms_seq(0x01, 2)
|
||||
|
||||
# if PC_HOSTED == 1
|
||||
int platform_jtagtap_init(void);
|
||||
# else
|
||||
int jtagtap_init(void);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
# error "Include 'general.h' instead"
|
||||
#endif
|
||||
|
||||
#if defined(PC_HOSTED)
|
||||
#include "target.h"
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
void platform_init(int argc, char **argv);
|
||||
#else
|
||||
void platform_init(void);
|
||||
|
|
|
@ -20,20 +20,17 @@
|
|||
|
||||
#ifndef __SWDPTAP_H
|
||||
#define __SWDPTAP_H
|
||||
typedef struct swd_proc_s {
|
||||
uint32_t (*swdptap_seq_in)(int ticks);
|
||||
bool (*swdptap_seq_in_parity)(uint32_t *data, int ticks);
|
||||
void (*swdptap_seq_out)(uint32_t MS, int ticks);
|
||||
void (*swdptap_seq_out_parity)(uint32_t MS, int ticks);
|
||||
} swd_proc_t;
|
||||
extern swd_proc_t swd_proc;
|
||||
|
||||
# if PC_HOSTED == 1
|
||||
int platform_swdptap_init(void);
|
||||
# else
|
||||
int swdptap_init(void);
|
||||
|
||||
/* Primitive functions */
|
||||
bool swdptap_bit_in(void);
|
||||
void swdptap_bit_out(bool val);
|
||||
|
||||
/* Low level functions, provided in swdptap_generic.c from the primitives
|
||||
(indicate NO_OWN_LL in the Makefile.inc or libopencm specific in
|
||||
platforms/common*/
|
||||
uint32_t swdptap_seq_in(int ticks);
|
||||
bool swdptap_seq_in_parity(uint32_t *data, int ticks);
|
||||
void swdptap_seq_out(uint32_t MS, int ticks);
|
||||
void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ typedef struct target_s target;
|
|||
typedef uint32_t target_addr;
|
||||
struct target_controller;
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
int platform_adiv5_swdp_scan(void);
|
||||
int platform_jtag_scan(const uint8_t *lrlens);
|
||||
#endif
|
||||
int adiv5_swdp_scan(void);
|
||||
int jtag_scan(const uint8_t *lrlens);
|
||||
|
||||
|
|
|
@ -27,4 +27,3 @@ struct platform_timeout {
|
|||
uint32_t platform_time_ms(void);
|
||||
|
||||
#endif /* __TIMING_H */
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
#if defined(PC_HOSTED)
|
||||
#if PC_HOSTED == 1
|
||||
platform_init(argc, argv);
|
||||
#else
|
||||
(void) argc;
|
||||
|
|
|
@ -59,9 +59,9 @@ static char morse_repeat;
|
|||
|
||||
void morse(const char *msg, char repeat)
|
||||
{
|
||||
#if defined(PC_HOSTED)
|
||||
#if PC_HOSTED == 1
|
||||
if (msg)
|
||||
DEBUG("%s\n", msg);
|
||||
DEBUG_WARN("%s\n", msg);
|
||||
(void) repeat;
|
||||
#else
|
||||
morse_msg = morse_ptr = msg;
|
||||
|
|
|
@ -26,10 +26,26 @@
|
|||
#include "jtagtap.h"
|
||||
#include "gdb_packet.h"
|
||||
|
||||
int jtagtap_init(void)
|
||||
jtag_proc_t jtag_proc;
|
||||
|
||||
static void jtagtap_reset(void);
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks);
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
|
||||
|
||||
int jtagtap_init()
|
||||
{
|
||||
TMS_SET_MODE();
|
||||
|
||||
jtag_proc.jtagtap_reset = jtagtap_reset;
|
||||
jtag_proc.jtagtap_next =jtagtap_next;
|
||||
jtag_proc.jtagtap_tms_seq = jtagtap_tms_seq;
|
||||
jtag_proc.jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
|
||||
jtag_proc.jtagtap_tdi_seq = jtagtap_tdi_seq;
|
||||
|
||||
/* Go to JTAG mode for SWJ-DP */
|
||||
for(int i = 0; i <= 50; i++) jtagtap_next(1, 0); /* Reset SW-DP */
|
||||
jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */
|
||||
|
@ -38,7 +54,7 @@ int jtagtap_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void jtagtap_reset(void)
|
||||
static void jtagtap_reset(void)
|
||||
{
|
||||
#ifdef TRST_PORT
|
||||
if (platform_hwversion() == 0) {
|
||||
|
@ -51,7 +67,7 @@ void jtagtap_reset(void)
|
|||
jtagtap_soft_reset();
|
||||
}
|
||||
|
||||
inline uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
|
@ -66,7 +82,7 @@ inline uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
|||
return ret != 0;
|
||||
}
|
||||
|
||||
void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
gpio_set_val(TDI_PORT, TDI_PIN, 1);
|
||||
int data = MS & 1;
|
||||
|
@ -80,8 +96,8 @@ void jtagtap_tms_seq(uint32_t MS, int ticks)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t index = 1;
|
||||
gpio_set_val(TMS_PORT, TMS_PIN, 0);
|
||||
|
@ -111,8 +127,7 @@ jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int
|
|||
gpio_clear(TCK_PORT, TCK_PIN);
|
||||
}
|
||||
|
||||
void
|
||||
jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t index = 1;
|
||||
while(ticks--) {
|
||||
|
|
|
@ -27,11 +27,14 @@ enum {
|
|||
SWDIO_STATUS_FLOAT = 0,
|
||||
SWDIO_STATUS_DRIVE
|
||||
};
|
||||
|
||||
int swdptap_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static void swdptap_turnaround(int dir) __attribute__ ((optimize(3)));
|
||||
static uint32_t swdptap_seq_in(int ticks) __attribute__ ((optimize(3)));
|
||||
static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||
__attribute__ ((optimize(3)));
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
__attribute__ ((optimize(3)));
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
__attribute__ ((optimize(3)));
|
||||
|
||||
static void swdptap_turnaround(int dir)
|
||||
{
|
||||
|
@ -54,26 +57,7 @@ static void swdptap_turnaround(int dir)
|
|||
SWDIO_MODE_DRIVE();
|
||||
}
|
||||
|
||||
bool swdptap_bit_in(void)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
|
||||
ret = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
DEBUG("%d", ret?1:0);
|
||||
#endif
|
||||
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
swdptap_seq_in(int ticks)
|
||||
static uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
uint32_t index = 1;
|
||||
uint32_t ret = 0;
|
||||
|
@ -97,55 +81,39 @@ swdptap_seq_in(int ticks)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||
static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
|
||||
{
|
||||
uint32_t index = 1;
|
||||
uint8_t parity = 0;
|
||||
uint32_t res = 0;
|
||||
bool bit;
|
||||
int len = ticks;
|
||||
|
||||
swdptap_turnaround(SWDIO_STATUS_FLOAT);
|
||||
while (len--) {
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (bit) {
|
||||
res |= index;
|
||||
parity ^= 1;
|
||||
}
|
||||
index <<= 1;
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
int parity = __builtin_popcount(res);
|
||||
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
if (bit)
|
||||
parity ^= 1;
|
||||
parity++;
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
for (int i = 0; i < len; i++)
|
||||
DEBUG("%d", (res & (1 << i)) ? 1 : 0);
|
||||
#endif
|
||||
*ret = res;
|
||||
return parity;
|
||||
return (parity & 1);
|
||||
}
|
||||
|
||||
void swdptap_bit_out(bool val)
|
||||
{
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
DEBUG("%d", val);
|
||||
#endif
|
||||
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, val);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
void
|
||||
swdptap_seq_out(uint32_t MS, int ticks)
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
int data = MS & 1;
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
|
@ -155,31 +123,30 @@ swdptap_seq_out(uint32_t MS, int ticks)
|
|||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
while (ticks--) {
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
MS >>= 1;
|
||||
data = MS & 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
MS >>= 1;
|
||||
data = MS & 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
|
||||
void
|
||||
swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t parity = 0;
|
||||
int parity = __builtin_popcount(MS);
|
||||
int data = MS & 1;
|
||||
#ifdef DEBUG_SWD_BITS
|
||||
for (int i = 0; i < ticks; i++)
|
||||
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
|
||||
#endif
|
||||
swdptap_turnaround(SWDIO_STATUS_DRIVE);
|
||||
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
MS >>= 1;
|
||||
while (ticks--) {
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
parity ^= MS;
|
||||
MS >>= 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
data = MS & 1;
|
||||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
|
||||
MS >>= 1;
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
|
||||
|
@ -188,3 +155,15 @@ swdptap_seq_out_parity(uint32_t MS, int ticks)
|
|||
gpio_set(SWCLK_PORT, SWCLK_PIN);
|
||||
gpio_clear(SWCLK_PORT, SWCLK_PIN);
|
||||
}
|
||||
|
||||
swd_proc_t swd_proc;
|
||||
|
||||
int swdptap_init(void)
|
||||
{
|
||||
swd_proc.swdptap_seq_in = swdptap_seq_in;
|
||||
swd_proc.swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||
swd_proc.swdptap_seq_out = swdptap_seq_out;
|
||||
swd_proc.swdptap_seq_out_parity = swdptap_seq_out_parity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ bool platform_srst_get_val(void) { return false; }
|
|||
|
||||
const char *platform_target_voltage(void)
|
||||
{
|
||||
return "ABSENT!";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void platform_request_boot(void)
|
||||
|
|
|
@ -135,8 +135,6 @@
|
|||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||
#define TRACE_ISR tim3_isr
|
||||
|
||||
#define DEBUG(...)
|
||||
|
||||
#define gpio_set_val(port, pin, val) do { \
|
||||
if(val) \
|
||||
gpio_set((port), (pin)); \
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
|
||||
ifneq (, $(findstring linux, $(SYS)))
|
||||
SRC += serial_unix.c
|
||||
CFLAGS += -fsanitize=address
|
||||
LDFLAGS += -lasan
|
||||
else ifneq (, $(findstring mingw, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
LDFLAGS += -lsetupapi
|
||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
LDFLAGS += -lsetupapi
|
||||
#https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator
|
||||
else ifneq (filter, macosx darwin, $(SYS)))
|
||||
LDFLAGS += -lsetupapi
|
||||
LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit
|
||||
LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a
|
||||
CFLAGS += -Ihidapi/hidapi
|
||||
endif
|
||||
|
||||
LDFLAGS += -lusb-1.0
|
||||
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
||||
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
||||
|
||||
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
|
||||
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
|
||||
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
|
||||
CFLAGS += -DCMSIS_DAP
|
||||
SRC += cmsis_dap.c dap.c
|
||||
endif
|
||||
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c cl_utils.c utils.c libusb_utils.c
|
||||
SRC += stlinkv2.c
|
||||
SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c
|
||||
SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c
|
||||
SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c
|
||||
PC_HOSTED = 1
|
|
@ -0,0 +1,54 @@
|
|||
# PC-Hosted BMP
|
||||
Compile in src with "make PROBE_HOST=hosted"
|
||||
|
||||
## Description
|
||||
PC-hosted BMP run on the PC and compiles as "blackmagic". When started,
|
||||
it either presents a list of available probes or starts the BMP process
|
||||
if either only one probe is attached to the PC or enough information is
|
||||
given on the command line to select one of several probes.
|
||||
|
||||
When started without any other argument beside the probe selection, a
|
||||
GDB server is started as port 2000 and up. Connect to the server as you would
|
||||
connect to the BMP with the CDCACM GDB serial server. GDB functionality
|
||||
is the same, monitor option may vary.
|
||||
|
||||
More arguments allow to
|
||||
### print information on the connected target "blackmagiv -t"
|
||||
### directly flash a binary file at 0x0800000 "blackmagic <file.bin>"
|
||||
or with the -S argument at some other address
|
||||
### read flash to binary file "blackmagic -r <file>.bin
|
||||
### verify flash against binary file "blackmagic -V <file>.bin
|
||||
|
||||
Use "blackmagic -h" to see all options.
|
||||
|
||||
## Used libraries:
|
||||
### libusb
|
||||
### libftdi, for FTDI support
|
||||
### hidapi-libusb, for CMSIS-DAP support
|
||||
|
||||
## Supported debuggers
|
||||
REMOTE_BMP is a "normal" BMP usb connected
|
||||
|
||||
| Debugger | Speed | Remarks
|
||||
| ------------ | ----- | ------
|
||||
| REMOTE_BMP | +++ | Requires recent firmware for decent speed
|
||||
| ST-Link V3 | ++++ | Requires recent firmware, Only STM32 devices supported!
|
||||
| ST-Link V2 | +++ | Requires recent firmware, No CDCACM uart! Cortex only!
|
||||
| ST-Link V2/1 | +++ | Requires recent firmware, Cortex only!
|
||||
| CMSIS-DAP | +++ | Speed varies with MCU implementing CMSIS-DAP
|
||||
| FTDI MPSSE | ++ | Requires a device descrition
|
||||
| JLINK | - | Usefull to add BMP support for MCUs with built-in JLINK
|
||||
|
||||
## Feedback
|
||||
### Issues and Pull request on https://github.com/blacksphere/blackmagic/
|
||||
### Discussions on Discord.
|
||||
You can find the Discord link here: https://1bitsquared.com/pages/chat
|
||||
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419
|
||||
|
||||
## Known deficiencies
|
||||
### For REMOTE_BMP
|
||||
#### On windows, the device node must be given on the command line
|
||||
Finding the device from USB VID/PID/Serial in not yet implemented
|
||||
### FTDI MPSSE
|
||||
#### No auto detection
|
||||
Cable description must be given on the command line
|
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Additions by Dave Marples <dave@marples.net>
|
||||
* Modifications (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "platform.h"
|
||||
#include "remote.h"
|
||||
#include "target.h"
|
||||
#include "bmp_remote.h"
|
||||
#include "cl_utils.h"
|
||||
#include "hex_utils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "adiv5.h"
|
||||
|
||||
int remote_init(bool verbose)
|
||||
{
|
||||
char construct[REMOTE_MAX_MSG_SIZE];
|
||||
int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR);
|
||||
platform_buffer_write((uint8_t *)construct, c);
|
||||
c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!c) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("Remote Start failed, error %s\n",
|
||||
c ? (char *)&(construct[1]) : "unknown");
|
||||
return -1;
|
||||
}
|
||||
if (verbose)
|
||||
DEBUG_WARN("Remote is %s\n", &construct[1]);
|
||||
char *p = strstr(&construct[1], "(Firmware v");
|
||||
if (!p)
|
||||
return -1;
|
||||
int major = 0, minor = 0, step = 0;
|
||||
int res = sscanf(p, "(Firmware v%d.%d.%d", &major, &minor, &step);
|
||||
if (res !=3)
|
||||
return -1;
|
||||
uint32_t version = major * 10000 + minor * 100 + step;
|
||||
/* check that firmare is > 1.6.1 */
|
||||
if (version < 10602)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool remote_target_get_power(void)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
|
||||
REMOTE_PWR_GET_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN(" platform_target_get_power failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
return (construct[1] == '1');
|
||||
}
|
||||
|
||||
void remote_target_set_power(bool power)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_PWR_SET_STR,
|
||||
power ? '1' : '0');
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("platform_target_set_power failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void remote_srst_set_val(bool assert)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_SRST_SET_STR,
|
||||
assert ? '1' : '0');
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
bool remote_srst_get_val(void)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,"%s",
|
||||
REMOTE_SRST_GET_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("platform_srst_set_val failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
return (construct[1] == '1');
|
||||
}
|
||||
|
||||
const char *remote_target_voltage(void)
|
||||
{
|
||||
static uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE," %s",
|
||||
REMOTE_VOLTAGE_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("platform_target_voltage failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(- 1);
|
||||
}
|
||||
return (char *)&construct[1];
|
||||
}
|
||||
|
||||
static uint32_t remote_adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
(void)dp;
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_DP_READ_STR,
|
||||
addr);
|
||||
platform_buffer_write(construct, s);
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||
}
|
||||
uint32_t dest[1];
|
||||
unhexify(dest, (const char*)&construct[1], 4);
|
||||
DEBUG_PROBE("dp_read addr %04x: %08" PRIx32 "\n", dest[0]);
|
||||
return dest[0];
|
||||
}
|
||||
|
||||
static uint32_t remote_adiv5_low_access(
|
||||
ADIv5_DP_t *dp, uint8_t RnW, uint16_t addr, uint32_t value)
|
||||
{
|
||||
(void)dp;
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_LOW_ACCESS_STR, RnW, addr, value);
|
||||
platform_buffer_write(construct, s);
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||
}
|
||||
uint32_t dest[1];
|
||||
unhexify(dest, (const char*)&construct[1], 4);
|
||||
return dest[0];
|
||||
}
|
||||
|
||||
static uint32_t remote_adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_READ_STR,
|
||||
ap->apsel, addr);
|
||||
platform_buffer_write(construct, s);
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||
}
|
||||
uint32_t dest[1];
|
||||
unhexify(dest, (const char*)&construct[1], 4);
|
||||
return dest[0];
|
||||
}
|
||||
|
||||
static void remote_adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_WRITE_STR,
|
||||
ap->apsel, addr, value);
|
||||
platform_buffer_write(construct, s);
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void remote_mem_read(
|
||||
ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
(void)ap;
|
||||
if (len == 0)
|
||||
return;
|
||||
DEBUG_WIRE("memread @ %" PRIx32 " len %ld, start: \n",
|
||||
src, len);
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
int batchsize = (REMOTE_MAX_MSG_SIZE - 32) / 2;
|
||||
while(len) {
|
||||
int count = len;
|
||||
if (count > batchsize)
|
||||
count = batchsize;
|
||||
s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_MEM_READ_STR, src, count);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) {
|
||||
unhexify(dest, (const char*)&construct[1], count);
|
||||
src += count;
|
||||
dest += count;
|
||||
len -= count;
|
||||
|
||||
continue;
|
||||
} else {
|
||||
if(construct[0] == REMOTE_RESP_ERR) {
|
||||
ap->dp->fault = 1;
|
||||
DEBUG_WARN("%s returned REMOTE_RESP_ERR at addr: 0x%08x\n",
|
||||
__func__, src);
|
||||
break;
|
||||
} else {
|
||||
DEBUG_WARN("%s error %d\n", __func__, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void remote_ap_mem_read(
|
||||
ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
(void)ap;
|
||||
if (len == 0)
|
||||
return;
|
||||
char construct[REMOTE_MAX_MSG_SIZE];
|
||||
int batchsize = (REMOTE_MAX_MSG_SIZE - 0x20) / 2;
|
||||
while(len) {
|
||||
int s;
|
||||
int count = len;
|
||||
if (count > batchsize)
|
||||
count = batchsize;
|
||||
s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_AP_MEM_READ_STR, ap->apsel, ap->csw, src, count);
|
||||
platform_buffer_write((uint8_t*)construct, s);
|
||||
s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) {
|
||||
unhexify(dest, (const char*)&construct[1], count);
|
||||
src += count;
|
||||
dest += count;
|
||||
len -= count;
|
||||
continue;
|
||||
} else {
|
||||
if(construct[0] == REMOTE_RESP_ERR) {
|
||||
ap->dp->fault = 1;
|
||||
DEBUG_WARN("%s returned REMOTE_RESP_ERR at apsel %d, "
|
||||
"addr: 0x%08" PRIx32 "\n", __func__, ap->apsel, src);
|
||||
break;
|
||||
} else {
|
||||
DEBUG_WARN("%s error %d around 0x%08" PRIx32 "\n",
|
||||
__func__, s, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void remote_ap_mem_write_sized(
|
||||
ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len,
|
||||
enum align align)
|
||||
{
|
||||
(void)ap;
|
||||
if (len == 0)
|
||||
return;
|
||||
char construct[REMOTE_MAX_MSG_SIZE];
|
||||
/* (5 * 1 (char)) + (2 * 2 (bytes)) + (3 * 8 (words)) */
|
||||
int batchsize = (REMOTE_MAX_MSG_SIZE - 0x30) / 2;
|
||||
while (len) {
|
||||
int count = len;
|
||||
if (count > batchsize)
|
||||
count = batchsize;
|
||||
int s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_AP_MEM_WRITE_SIZED_STR,
|
||||
ap->apsel, ap->csw, align, dest, count);
|
||||
char *p = construct + s;
|
||||
hexify(p, src, count);
|
||||
p += 2 * count;
|
||||
src += count;
|
||||
dest += count;
|
||||
len -= count;
|
||||
*p++ = REMOTE_EOM;
|
||||
*p = 0;
|
||||
platform_buffer_write((uint8_t*)construct, p - construct);
|
||||
|
||||
s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s > 0) && (construct[0] == REMOTE_RESP_OK))
|
||||
continue;
|
||||
if ((s > 0) && (construct[0] == REMOTE_RESP_ERR)) {
|
||||
ap->dp->fault = 1;
|
||||
DEBUG_WARN("%s returned REMOTE_RESP_ERR at apsel %d, "
|
||||
"addr: 0x%08x\n", __func__, ap->apsel, dest);
|
||||
} else {
|
||||
DEBUG_WARN("%s error %d around address 0x%08" PRIx32 "\n",
|
||||
__func__, s, dest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||
{
|
||||
if (remote_init(false)) {
|
||||
DEBUG_WARN(
|
||||
"Please update BMP firmware for substantial speed increase!\n");
|
||||
return;
|
||||
}
|
||||
dp->low_access = remote_adiv5_low_access;
|
||||
dp->dp_read = remote_adiv5_dp_read;
|
||||
dp->ap_write = remote_adiv5_ap_write;
|
||||
dp->ap_read = remote_adiv5_ap_read;
|
||||
dp->mem_read = remote_ap_mem_read;
|
||||
dp->mem_write_sized = remote_ap_mem_write_sized;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__BMP_REMOTE_H_)
|
||||
#define __BMP_REMOTE_H_
|
||||
#include "swdptap.h"
|
||||
#include "jtagtap.h"
|
||||
#include "adiv5.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
|
||||
#define REMOTE_MAX_MSG_SIZE (1024)
|
||||
|
||||
int platform_buffer_write(const uint8_t *data, int size);
|
||||
int platform_buffer_read(uint8_t *data, int size);
|
||||
|
||||
int remote_init(bool verbose);
|
||||
int remote_swdptap_init(swd_proc_t *swd_proc);
|
||||
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||
bool remote_target_get_power(void);
|
||||
const char *remote_target_voltage(void);
|
||||
void remote_target_set_power(bool power);
|
||||
void remote_srst_set_val(bool assert);
|
||||
bool remote_srst_get_val(void);
|
||||
const char *platform_target_voltage(void);
|
||||
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||
#define __BMP_REMOTE_H_
|
||||
#endif
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019-20 Uwe Bonnes <bon@elektron,ikp.physik.tu-darmstadt.de>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* Modified from edbg.c
|
||||
* Links between bmp and edbg
|
||||
*
|
||||
* https://arm-software.github.io/CMSIS_5/DAP/html/index.html
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "adiv5.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <hidapi.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "dap.h"
|
||||
#include "cmsis_dap.h"
|
||||
|
||||
#include "cl_utils.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
|
||||
uint8_t dap_caps;
|
||||
uint8_t mode;
|
||||
|
||||
/*- Variables ---------------------------------------------------------------*/
|
||||
static hid_device *handle = NULL;
|
||||
static uint8_t hid_buffer[1024 + 1];
|
||||
static int report_size = 512 + 1; // TODO: read actual report size
|
||||
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
||||
int dap_init(bmp_info_t *info)
|
||||
{
|
||||
if (hid_init())
|
||||
return -1;
|
||||
int size = strlen(info->serial);
|
||||
wchar_t serial[size + 1], *wc = serial;
|
||||
for (int i = 0; i < size; i++)
|
||||
*wc++ = info->serial[i];
|
||||
*wc = 0;
|
||||
/* Blacklist devices that do not wirk with 513 byte report length
|
||||
* FIXME: Find a solution to decipher from the device.
|
||||
*/
|
||||
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
|
||||
DEBUG_WARN("Blacklist\n");
|
||||
report_size = 64 + 1;
|
||||
}
|
||||
handle = hid_open(info->vid, info->pid, serial);
|
||||
if (!handle)
|
||||
return -1;
|
||||
dap_disconnect();
|
||||
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
||||
dap_caps = hid_buffer[0];
|
||||
DEBUG_INFO(" Cap (0x%2x): %s%s%s", hid_buffer[0],
|
||||
(hid_buffer[0] & 1)? "SWD" : "",
|
||||
((hid_buffer[0] & 3) == 3) ? "/" : "",
|
||||
(hid_buffer[0] & 2)? "JTAG" : "");
|
||||
if (hid_buffer[0] & 4)
|
||||
DEBUG_INFO(", SWO_UART");
|
||||
if (hid_buffer[0] & 8)
|
||||
DEBUG_INFO(", SWO_MANCHESTER");
|
||||
if (hid_buffer[0] & 0x10)
|
||||
DEBUG_INFO(", Atomic Cmds");
|
||||
DEBUG_INFO("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
{
|
||||
/* DP Write to Reg 0.*/
|
||||
dap_write_reg(dp, ADIV5_DP_ABORT, abort);
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT);
|
||||
uint32_t err = ctrlstat &
|
||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
||||
uint32_t clr = 0;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYORUN)
|
||||
clr |= ADIV5_DP_ABORT_ORUNERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYCMP)
|
||||
clr |= ADIV5_DP_ABORT_STKCMPCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYERR)
|
||||
clr |= ADIV5_DP_ABORT_STKERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_WDATAERR)
|
||||
clr |= ADIV5_DP_ABORT_WDERRCLR;
|
||||
dap_write_reg(dp, ADIV5_DP_ABORT, clr);
|
||||
dp->fault = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
uint32_t res = 0;
|
||||
uint8_t reg = (addr & 0xc) | ((APnDP)? 1 : 0);
|
||||
if (RnW) {
|
||||
res = dap_read_reg(dp, reg);
|
||||
}
|
||||
else {
|
||||
dap_write_reg(dp, reg, value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
return dap_read_reg(dp, addr);
|
||||
}
|
||||
|
||||
void dap_exit_function(void)
|
||||
{
|
||||
if (handle) {
|
||||
dap_disconnect();
|
||||
hid_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
int dbg_get_report_size(void)
|
||||
{
|
||||
return report_size;
|
||||
}
|
||||
|
||||
int dbg_dap_cmd(uint8_t *data, int size, int rsize)
|
||||
|
||||
{
|
||||
char cmd = data[0];
|
||||
int res;
|
||||
|
||||
memset(hid_buffer, 0xff, report_size + 1);
|
||||
|
||||
hid_buffer[0] = 0x00; // Report ID??
|
||||
memcpy(&hid_buffer[1], data, rsize);
|
||||
|
||||
DEBUG_WIRE("cmd : ");
|
||||
for(int i = 0; (i < 16) && (i < rsize + 1); i++)
|
||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
||||
DEBUG_WIRE("\n");
|
||||
res = hid_write(handle, hid_buffer, rsize + 1);
|
||||
if (res < 0) {
|
||||
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
|
||||
exit(-1);
|
||||
}
|
||||
if (size) {
|
||||
res = hid_read(handle, hid_buffer, report_size + 1);
|
||||
if (res < 0) {
|
||||
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
|
||||
exit(-1);
|
||||
}
|
||||
if (size && hid_buffer[0] != cmd) {
|
||||
DEBUG_WARN("cmd %02x invalid response received %02x\n",
|
||||
cmd, hid_buffer[0]);
|
||||
}
|
||||
res--;
|
||||
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
|
||||
DEBUG_WIRE("cmd res:");
|
||||
for(int i = 0; (i < 16) && (i < size + 4); i++)
|
||||
DEBUG_WIRE("%02x.", hid_buffer[i]);
|
||||
DEBUG_WIRE("\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
||||
(((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE))
|
||||
|
||||
static void dap_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
enum align align = MIN(ALIGNOF(src), ALIGNOF(len));
|
||||
DEBUG_WIRE("memread @ %" PRIx32 " len %ld, align %d , start: \n",
|
||||
src, len, align);
|
||||
if (((unsigned)(1 << align)) == len)
|
||||
return dap_read_single(ap, dest, src, align);
|
||||
/* One word transfer for every byte/halfword/word
|
||||
* Total number of bytes in transfer*/
|
||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
||||
while (len) {
|
||||
dap_ap_mem_access_setup(ap, src, align);
|
||||
/* Calculate length until next access setup is needed */
|
||||
unsigned int blocksize = (src | 0x3ff) - src + 1;
|
||||
if (blocksize > len)
|
||||
blocksize = len;
|
||||
while (blocksize) {
|
||||
unsigned int transfersize = blocksize;
|
||||
if (transfersize > max_size)
|
||||
transfersize = max_size;
|
||||
unsigned int res = dap_read_block(ap, dest, src, transfersize,
|
||||
align);
|
||||
if (res) {
|
||||
DEBUG_WIRE("mem_read failed %02x\n", res);
|
||||
ap->dp->fault = 1;
|
||||
return;
|
||||
}
|
||||
blocksize -= transfersize;
|
||||
len -= transfersize;
|
||||
dest += transfersize;
|
||||
src += transfersize;
|
||||
}
|
||||
}
|
||||
DEBUG_WIRE("memread res last data %08" PRIx32 "\n", ((uint32_t*)dest)[-1]);
|
||||
}
|
||||
|
||||
static void dap_mem_write_sized(
|
||||
ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
DEBUG_WIRE("memwrite @ %" PRIx32 " len %ld, align %d , %08x start: \n",
|
||||
dest, len, align, *(uint32_t *)src);
|
||||
if (((unsigned)(1 << align)) == len)
|
||||
return dap_write_single(ap, dest, src, align);
|
||||
unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
|
||||
while (len) {
|
||||
dap_ap_mem_access_setup(ap, dest, align);
|
||||
unsigned int blocksize = (dest | 0x3ff) - dest + 1;
|
||||
if (blocksize > len)
|
||||
blocksize = len;
|
||||
while (blocksize) {
|
||||
unsigned int transfersize = blocksize;
|
||||
if (transfersize > max_size)
|
||||
transfersize = max_size;
|
||||
unsigned int res = dap_write_block(ap, dest, src, transfersize,
|
||||
align);
|
||||
if (res) {
|
||||
DEBUG_WARN("mem_write failed %02x\n", res);
|
||||
ap->dp->fault = 1;
|
||||
return;
|
||||
}
|
||||
blocksize -= transfersize;
|
||||
len -= transfersize;
|
||||
dest += transfersize;
|
||||
src += transfersize;
|
||||
}
|
||||
}
|
||||
DEBUG_WIRE("memwrite done\n");
|
||||
}
|
||||
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp)
|
||||
{
|
||||
target_list_free();
|
||||
if (!(dap_caps & DAP_CAP_SWD))
|
||||
return -1;
|
||||
mode = DAP_CAP_SWD;
|
||||
dap_swj_clock(2000000);
|
||||
dap_transfer_configure(2, 128, 128);
|
||||
dap_swd_configure(0);
|
||||
dap_connect(false);
|
||||
dap_led(0, 1);
|
||||
dap_reset_link(false);
|
||||
|
||||
dp->idcode = dap_read_idcode(dp);
|
||||
dp->dp_read = dap_dp_read_reg;
|
||||
dp->error = dap_dp_error;
|
||||
dp->low_access = dap_dp_low_access;
|
||||
dp->abort = dap_dp_abort; /* DP Write to Reg 0.*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||
{
|
||||
if ((mode == DAP_CAP_JTAG) && dap_jtag_configure())
|
||||
return;
|
||||
dp->ap_read = dap_ap_read;
|
||||
dp->ap_write = dap_ap_write;
|
||||
dp->mem_read = dap_mem_read;
|
||||
dp->mem_write_sized = dap_mem_write_sized;
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_reset(void)
|
||||
{
|
||||
jtagtap_soft_reset();
|
||||
/* Is there a way to know if TRST is available?*/
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t TMS[4] = {MS & 0xff, (MS >> 8) & 0xff, (MS >> 16) & 0xff,
|
||||
(MS >> 24) & 0xff};
|
||||
dap_jtagtap_tdi_tdo_seq(NULL, false, TMS, NULL, ticks);
|
||||
DEBUG_PROBE("tms_seq DI %08x %d\n", MS, ticks);
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks);
|
||||
DEBUG_PROBE("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], DO[0]);
|
||||
}
|
||||
|
||||
static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
dap_jtagtap_tdi_tdo_seq(NULL, (final_tms), NULL, DI, ticks);
|
||||
DEBUG_PROBE("jtagtap_tdi_seq %d, %02x\n", ticks, DI[0]);
|
||||
}
|
||||
|
||||
static uint8_t cmsis_dap_jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint8_t tdo[1];
|
||||
dap_jtagtap_tdi_tdo_seq(tdo, false, &dTMS, &dTDI, 1);
|
||||
DEBUG_PROBE("next tms %02x tdi %02x tdo %02x\n", dTMS, dTDI, tdo[0]);
|
||||
return (tdo[0] & 1);
|
||||
}
|
||||
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
DEBUG_PROBE("jtap_init\n");
|
||||
if (!(dap_caps & DAP_CAP_JTAG))
|
||||
return -1;
|
||||
mode = DAP_CAP_JTAG;
|
||||
dap_disconnect();
|
||||
dap_connect(true);
|
||||
dap_swj_clock(2000000);
|
||||
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
|
||||
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
|
||||
dap_reset_link(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
||||
{
|
||||
dp->dp_read = dap_dp_read_reg;
|
||||
dp->error = dap_dp_error;
|
||||
dp->low_access = dap_dp_low_access;
|
||||
dp->abort = dap_dp_abort;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__CMSIS_DAP_H_)
|
||||
#define __CMSIS_DAP_H_
|
||||
|
||||
#include "adiv5.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
#if defined(CMSIS_DAP)
|
||||
int dap_init(bmp_info_t *info);
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp);
|
||||
void dap_exit_function(void);
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp);
|
||||
#else
|
||||
int dap_init(bmp_info_t *info) {(void)info; return -1;}
|
||||
int dap_enter_debug_swd(ADIv5_DP_t *dp) {(void)dp; return -1;}
|
||||
void dap_exit_function(void) {return;};
|
||||
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {(void)dp; return; }
|
||||
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
(void)jtag_proc;
|
||||
return -1;
|
||||
}
|
||||
int dap_jtag_dp_init(ADIv5_DP_t *dp)
|
||||
{
|
||||
(void)dp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015, Alex Taradov <alex@taradov.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Modified for Blackmagic Probe
|
||||
* Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
||||
*/
|
||||
|
||||
/*- Includes ----------------------------------------------------------------*/
|
||||
#include <general.h>
|
||||
#include <stdlib.h>
|
||||
#include "dap.h"
|
||||
#include "jtag_scan.h"
|
||||
|
||||
/*- Definitions -------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
ID_DAP_INFO = 0x00,
|
||||
ID_DAP_LED = 0x01,
|
||||
ID_DAP_CONNECT = 0x02,
|
||||
ID_DAP_DISCONNECT = 0x03,
|
||||
ID_DAP_TRANSFER_CONFIGURE = 0x04,
|
||||
ID_DAP_TRANSFER = 0x05,
|
||||
ID_DAP_TRANSFER_BLOCK = 0x06,
|
||||
ID_DAP_TRANSFER_ABORT = 0x07,
|
||||
ID_DAP_WRITE_ABORT = 0x08,
|
||||
ID_DAP_DELAY = 0x09,
|
||||
ID_DAP_RESET_TARGET = 0x0a,
|
||||
ID_DAP_SWJ_PINS = 0x10,
|
||||
ID_DAP_SWJ_CLOCK = 0x11,
|
||||
ID_DAP_SWJ_SEQUENCE = 0x12,
|
||||
ID_DAP_SWD_CONFIGURE = 0x13,
|
||||
ID_DAP_JTAG_SEQUENCE = 0x14,
|
||||
ID_DAP_JTAG_CONFIGURE = 0x15,
|
||||
ID_DAP_JTAG_IDCODE = 0x16,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_TRANSFER_APnDP = 1 << 0,
|
||||
DAP_TRANSFER_RnW = 1 << 1,
|
||||
DAP_TRANSFER_A2 = 1 << 2,
|
||||
DAP_TRANSFER_A3 = 1 << 3,
|
||||
DAP_TRANSFER_MATCH_VALUE = 1 << 4,
|
||||
DAP_TRANSFER_MATCH_MASK = 1 << 5,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_TRANSFER_INVALID = 0,
|
||||
DAP_TRANSFER_OK = 1 << 0,
|
||||
DAP_TRANSFER_WAIT = 1 << 1,
|
||||
DAP_TRANSFER_FAULT = 1 << 2,
|
||||
DAP_TRANSFER_ERROR = 1 << 3,
|
||||
DAP_TRANSFER_MISMATCH = 1 << 4,
|
||||
DAP_TRANSFER_NO_TARGET = 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_SWJ_SWCLK_TCK = 1 << 0,
|
||||
DAP_SWJ_SWDIO_TMS = 1 << 1,
|
||||
DAP_SWJ_TDI = 1 << 2,
|
||||
DAP_SWJ_TDO = 1 << 3,
|
||||
DAP_SWJ_nTRST = 1 << 5,
|
||||
DAP_SWJ_nRESET = 1 << 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_OK = 0x00,
|
||||
DAP_ERROR = 0xff,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_JTAG_TMS = 1 << 6,
|
||||
DAP_JTAG_TDO_CAPTURE = 1 << 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SWD_DP_R_IDCODE = 0x00,
|
||||
SWD_DP_W_ABORT = 0x00,
|
||||
SWD_DP_R_CTRL_STAT = 0x04,
|
||||
SWD_DP_W_CTRL_STAT = 0x04, // When CTRLSEL == 0
|
||||
SWD_DP_W_WCR = 0x04, // When CTRLSEL == 1
|
||||
SWD_DP_R_RESEND = 0x08,
|
||||
SWD_DP_W_SELECT = 0x08,
|
||||
SWD_DP_R_RDBUFF = 0x0c,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SWD_AP_CSW = 0x00 | DAP_TRANSFER_APnDP,
|
||||
SWD_AP_TAR = 0x04 | DAP_TRANSFER_APnDP,
|
||||
SWD_AP_DRW = 0x0c | DAP_TRANSFER_APnDP,
|
||||
|
||||
SWD_AP_DB0 = 0x00 | DAP_TRANSFER_APnDP, // 0x10
|
||||
SWD_AP_DB1 = 0x04 | DAP_TRANSFER_APnDP, // 0x14
|
||||
SWD_AP_DB2 = 0x08 | DAP_TRANSFER_APnDP, // 0x18
|
||||
SWD_AP_DB3 = 0x0c | DAP_TRANSFER_APnDP, // 0x1c
|
||||
|
||||
SWD_AP_CFG = 0x04 | DAP_TRANSFER_APnDP, // 0xf4
|
||||
SWD_AP_BASE = 0x08 | DAP_TRANSFER_APnDP, // 0xf8
|
||||
SWD_AP_IDR = 0x0c | DAP_TRANSFER_APnDP, // 0xfc
|
||||
};
|
||||
|
||||
#define DP_ABORT_DAPABORT (1 << 0)
|
||||
#define DP_ABORT_STKCMPCLR (1 << 1)
|
||||
#define DP_ABORT_STKERRCLR (1 << 2)
|
||||
#define DP_ABORT_WDERRCLR (1 << 3)
|
||||
#define DP_ABORT_ORUNERRCLR (1 << 4)
|
||||
|
||||
#define DP_CST_ORUNDETECT (1 << 0)
|
||||
#define DP_CST_STICKYORUN (1 << 1)
|
||||
#define DP_CST_TRNMODE_NORMAL (0 << 2)
|
||||
#define DP_CST_TRNMODE_VERIFY (1 << 2)
|
||||
#define DP_CST_TRNMODE_COMPARE (2 << 2)
|
||||
#define DP_CST_STICKYCMP (1 << 4)
|
||||
#define DP_CST_STICKYERR (1 << 5)
|
||||
#define DP_CST_READOK (1 << 6)
|
||||
#define DP_CST_WDATAERR (1 << 7)
|
||||
#define DP_CST_MASKLANE(x) ((x) << 8)
|
||||
#define DP_CST_TRNCNT(x) ((x) << 12)
|
||||
#define DP_CST_CDBGRSTREQ (1 << 26)
|
||||
#define DP_CST_CDBGRSTACK (1 << 27)
|
||||
#define DP_CST_CDBGPWRUPREQ (1 << 28)
|
||||
#define DP_CST_CDBGPWRUPACK (1 << 29)
|
||||
#define DP_CST_CSYSPWRUPREQ (1 << 30)
|
||||
#define DP_CST_CSYSPWRUPACK (1 << 31)
|
||||
|
||||
#define DP_SELECT_CTRLSEL (1 << 0)
|
||||
#define DP_SELECT_APBANKSEL(x) ((x) << 4)
|
||||
#define DP_SELECT_APSEL(x) ((x) << 24)
|
||||
|
||||
#define AP_CSW_SIZE_BYTE (0 << 0)
|
||||
#define AP_CSW_SIZE_HALF (1 << 0)
|
||||
#define AP_CSW_SIZE_WORD (2 << 0)
|
||||
#define AP_CSW_ADDRINC_OFF (0 << 4)
|
||||
#define AP_CSW_ADDRINC_SINGLE (1 << 4)
|
||||
#define AP_CSW_ADDRINC_PACKED (2 << 4)
|
||||
#define AP_CSW_DEVICEEN (1 << 6)
|
||||
#define AP_CSW_TRINPROG (1 << 7)
|
||||
#define AP_CSW_SPIDEN (1 << 23)
|
||||
#define AP_CSW_PROT(x) ((x) << 24)
|
||||
#define AP_CSW_DBGSWENABLE (1 << 31)
|
||||
|
||||
/*- Implementations ---------------------------------------------------------*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_led(int index, int state)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
|
||||
buf[0] = ID_DAP_LED;
|
||||
buf[1] = index;
|
||||
buf[2] = state;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 3);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_connect(bool jtag)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = ID_DAP_CONNECT;
|
||||
buf[1] = (jtag) ? DAP_CAP_JTAG : DAP_CAP_SWD;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_disconnect(void)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
|
||||
buf[0] = ID_DAP_DISCONNECT;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_swj_clock(uint32_t clock)
|
||||
{
|
||||
uint8_t buf[5];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_CLOCK;
|
||||
buf[1] = clock & 0xff;
|
||||
buf[2] = (clock >> 8) & 0xff;
|
||||
buf[3] = (clock >> 16) & 0xff;
|
||||
buf[4] = (clock >> 24) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 5);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry)
|
||||
{
|
||||
uint8_t buf[6];
|
||||
|
||||
buf[0] = ID_DAP_TRANSFER_CONFIGURE;
|
||||
buf[1] = idle;
|
||||
buf[2] = count & 0xff;
|
||||
buf[3] = (count >> 8) & 0xff;
|
||||
buf[4] = retry & 0xff;
|
||||
buf[5] = (retry >> 8) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 6);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_swd_configure(uint8_t cfg)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
buf[0] = ID_DAP_SWD_CONFIGURE;
|
||||
buf[1] = cfg;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int dap_info(int info, uint8_t *data, int size)
|
||||
{
|
||||
uint8_t buf[256];
|
||||
int rsize;
|
||||
|
||||
buf[0] = ID_DAP_INFO;
|
||||
buf[1] = info;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 2);
|
||||
|
||||
rsize = (size < buf[0]) ? size : buf[0];
|
||||
memcpy(data, &buf[1], rsize);
|
||||
|
||||
if (rsize < size)
|
||||
data[rsize] = 0;
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
void dap_reset_pin(int state)
|
||||
{
|
||||
uint8_t buf[7];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = state ? DAP_SWJ_nRESET : 0; // Value
|
||||
buf[2] = DAP_SWJ_nRESET; // Select
|
||||
buf[3] = 0; // Wait
|
||||
buf[4] = 0;
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
}
|
||||
|
||||
void dap_trst_reset(void)
|
||||
{
|
||||
uint8_t buf[7];
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = DAP_SWJ_nTRST;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = 4; /* ~ 1 ms*/
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
|
||||
buf[0] = ID_DAP_SWJ_PINS;
|
||||
buf[1] = DAP_SWJ_nTRST;
|
||||
buf[2] = DAP_SWJ_nTRST;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 7);
|
||||
}
|
||||
|
||||
static void dap_line_reset(void)
|
||||
{
|
||||
uint8_t buf[] = {
|
||||
ID_DAP_SWJ_SEQUENCE,
|
||||
64,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0
|
||||
};
|
||||
dbg_dap_cmd(buf, sizeof(buf), 10);
|
||||
if (buf[0])
|
||||
DEBUG_WARN("line reset failed\n");
|
||||
}
|
||||
|
||||
static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault)
|
||||
{
|
||||
do {
|
||||
dbg_dap_cmd(buf, size, len);
|
||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||
break;
|
||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||
|
||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
||||
// DEBUG_WARN("dap_read_reg fault\n");
|
||||
*dp_fault = 1;
|
||||
}
|
||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
||||
DEBUG_WARN("dap_read_reg, protocoll error\n");
|
||||
dap_line_reset();
|
||||
}
|
||||
uint32_t res =
|
||||
((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) |
|
||||
((uint32_t)buf[3] << 8) | (uint32_t)buf[2];
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
uint8_t dap_index = 0;
|
||||
if (dp->dev)
|
||||
dap_index = dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = 0x01; // Request size
|
||||
buf[3] = reg | DAP_TRANSFER_RnW;
|
||||
uint32_t res = wait_word(buf, 8, 4, &dp->fault);
|
||||
DEBUG_WIRE("\tdap_read_reg %02x %08x\n", reg, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
DEBUG_PROBE("\tdap_write_reg %02x %08x\n", reg, data);
|
||||
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
uint8_t dap_index = 0;
|
||||
if (dp->dev)
|
||||
dap_index = dp->dev->dev;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = 0x01; // Request size
|
||||
buf[3] = reg & ~DAP_TRANSFER_RnW;;
|
||||
buf[4] = data & 0xff;
|
||||
buf[5] = (data >> 8) & 0xff;
|
||||
buf[6] = (data >> 16) & 0xff;
|
||||
buf[7] = (data >> 24) & 0xff;
|
||||
do {
|
||||
dbg_dap_cmd(buf, sizeof(buf), 8);
|
||||
if (buf[1] < DAP_TRANSFER_WAIT)
|
||||
break;
|
||||
} while (buf[1] == DAP_TRANSFER_WAIT);
|
||||
|
||||
if (buf[1] > DAP_TRANSFER_WAIT) {
|
||||
DEBUG_PROBE("dap_write_reg %02x data %08x:fault\n", reg, data);
|
||||
dp->fault = 1;
|
||||
}
|
||||
if (buf[1] == DAP_TRANSFER_ERROR) {
|
||||
DEBUG_PROBE("dap_write_reg %02x data %08x: protocoll error\n",
|
||||
reg, data);
|
||||
dap_line_reset();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
unsigned int sz = len >> align;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = sz & 0xff;
|
||||
buf[3] = (sz >> 8) & 0xff;
|
||||
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||
dbg_dap_cmd(buf, 1023, 5 + 1);
|
||||
unsigned int transferred = buf[0] + (buf[1] << 8);
|
||||
if (buf[2] > DAP_TRANSFER_FAULT) {
|
||||
DEBUG_PROBE("line_reset\n");
|
||||
dap_line_reset();
|
||||
}
|
||||
if (sz != transferred) {
|
||||
return 1;
|
||||
} else if (align > ALIGN_HALFWORD) {
|
||||
memcpy(dest, &buf[3], len);
|
||||
} else {
|
||||
uint32_t *p = (uint32_t *)&buf[3];
|
||||
while(sz) {
|
||||
dest = extract(dest, src, *p, align);
|
||||
p++;
|
||||
src += (1 << align);
|
||||
dest += (1 << align);
|
||||
sz--;
|
||||
}
|
||||
}
|
||||
return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
unsigned int sz = len >> align;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
buf[0] = ID_DAP_TRANSFER_BLOCK;
|
||||
buf[1] = dap_index;
|
||||
buf[2] = sz & 0xff;
|
||||
buf[3] = (sz >> 8) & 0xff;
|
||||
buf[4] = SWD_AP_DRW;
|
||||
if (align > ALIGN_HALFWORD) {
|
||||
memcpy(&buf[5], src, len);
|
||||
} else {
|
||||
unsigned int size = len;
|
||||
uint32_t *p = (uint32_t *)&buf[5];
|
||||
while (size) {
|
||||
uint32_t tmp = 0;
|
||||
/* Pack data into correct data lane */
|
||||
if (align == ALIGN_BYTE) {
|
||||
tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3);
|
||||
} else {
|
||||
tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3);
|
||||
}
|
||||
src = src + (1 << align);
|
||||
dest += (1 << align);
|
||||
size--;
|
||||
*p++ = tmp;
|
||||
}
|
||||
}
|
||||
dbg_dap_cmd(buf, 1023, 5 + (sz << 2));
|
||||
if (buf[2] > DAP_TRANSFER_FAULT) {
|
||||
dap_line_reset();
|
||||
}
|
||||
return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void dap_reset_link(bool jtag)
|
||||
{
|
||||
uint8_t buf[128], *p = buf;
|
||||
|
||||
//-------------
|
||||
*p++ = ID_DAP_SWJ_SEQUENCE;
|
||||
p++;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
if (jtag) {
|
||||
*p++ = 0x3c;
|
||||
*p++ = 0xe7;
|
||||
*p++ = 0x1f;
|
||||
buf[1] = ((p - &buf[2]) * 8) - 2;
|
||||
} else {
|
||||
*p++ = 0x9e;
|
||||
*p++ = 0xe7;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0xff;
|
||||
*p++ = 0x00;
|
||||
buf[1] = (p - &buf[2]) * 8;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
|
||||
if (!jtag) {
|
||||
//-------------
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
buf[1] = 0; // DAP index
|
||||
buf[2] = 1; // Request size
|
||||
buf[3] = SWD_DP_R_IDCODE | DAP_TRANSFER_RnW;
|
||||
dbg_dap_cmd(buf, sizeof(buf), 4);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t dap_read_idcode(ADIv5_DP_t *dp)
|
||||
{
|
||||
return dap_read_reg(dp, SWD_DP_R_IDCODE);
|
||||
}
|
||||
|
||||
static uint8_t *mem_access_setup(ADIv5_AP_t *ap, uint8_t *p,
|
||||
uint32_t addr, enum align align)
|
||||
{
|
||||
uint32_t csw = ap->csw | ADIV5_AP_CSW_ADDRINC_SINGLE;
|
||||
switch (align) {
|
||||
case ALIGN_BYTE:
|
||||
csw |= ADIV5_AP_CSW_SIZE_BYTE;
|
||||
break;
|
||||
case ALIGN_HALFWORD:
|
||||
csw |= ADIV5_AP_CSW_SIZE_HALFWORD;
|
||||
break;
|
||||
case ALIGN_DWORD:
|
||||
case ALIGN_WORD:
|
||||
csw |= ADIV5_AP_CSW_SIZE_WORD;
|
||||
break;
|
||||
}
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 3; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = ADIV5_AP_CSW & 0xF0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = SWD_AP_CSW;
|
||||
*p++ = (csw >> 0) & 0xff;
|
||||
*p++ = (csw >> 8) & 0xff;
|
||||
*p++ = (csw >> 16) & 0xff;
|
||||
*p++ = (csw >> 24) & 0xff;
|
||||
*p++ = SWD_AP_TAR ;
|
||||
*p++ = (addr >> 0) & 0xff;
|
||||
*p++ = (addr >> 8) & 0xff;
|
||||
*p++ = (addr >> 16) & 0xff;
|
||||
*p++ = (addr >> 24) & 0xff;
|
||||
return p;
|
||||
}
|
||||
|
||||
void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, addr, align);
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
}
|
||||
|
||||
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
DEBUG_PROBE("dap_ap_read_start\n");
|
||||
uint8_t buf[63], *p = buf;
|
||||
buf[0] = ID_DAP_TRANSFER;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 2; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = (addr & 0xF0);
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = (addr & 0x0c) | DAP_TRANSFER_RnW |
|
||||
((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
||||
uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||
return res;
|
||||
}
|
||||
|
||||
void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value);
|
||||
uint8_t buf[63], *p = buf;
|
||||
uint8_t dap_index = 0;
|
||||
if (ap->dp->dev)
|
||||
dap_index = ap->dp->dev->dev;
|
||||
*p++ = ID_DAP_TRANSFER;
|
||||
*p++ = dap_index;
|
||||
*p++ = 2; /* Nr transfers */
|
||||
*p++ = SWD_DP_W_SELECT;
|
||||
*p++ = (addr & 0xF0);
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = ap->apsel & 0xff;
|
||||
*p++ = (addr & 0x0c) | ((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
|
||||
*p++ = (value >> 0) & 0xff;
|
||||
*p++ = (value >> 8) & 0xff;
|
||||
*p++ = (value >> 16) & 0xff;
|
||||
*p++ = (value >> 24) & 0xff;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
}
|
||||
|
||||
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, src, align);
|
||||
*p++ = SWD_AP_DRW | DAP_TRANSFER_RnW;
|
||||
buf[2] = 4;
|
||||
uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault);
|
||||
dest = extract(dest, src, tmp, align);
|
||||
}
|
||||
|
||||
void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
enum align align)
|
||||
{
|
||||
uint8_t buf[63];
|
||||
uint8_t *p = mem_access_setup(ap, buf, dest, align);
|
||||
*p++ = SWD_AP_DRW;
|
||||
uint32_t tmp = 0;
|
||||
/* Pack data into correct data lane */
|
||||
switch (align) {
|
||||
case ALIGN_BYTE:
|
||||
tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3);
|
||||
break;
|
||||
case ALIGN_HALFWORD:
|
||||
tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3);
|
||||
break;
|
||||
case ALIGN_DWORD:
|
||||
case ALIGN_WORD:
|
||||
tmp = *(uint32_t *)src;
|
||||
break;
|
||||
}
|
||||
*p++ = (tmp >> 0) & 0xff;
|
||||
*p++ = (tmp >> 8) & 0xff;
|
||||
*p++ = (tmp >> 16) & 0xff;
|
||||
*p++ = (tmp >> 24) & 0xff;
|
||||
buf[2] = 4;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
}
|
||||
|
||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
if (!TMS) {
|
||||
int last_byte = 0;
|
||||
int last_bit = 0;
|
||||
if (final_tms) {
|
||||
last_byte = ticks >> 3;
|
||||
last_bit = ticks & 7;
|
||||
ticks --;
|
||||
}
|
||||
while (ticks) {
|
||||
int transfers = ticks;
|
||||
if (transfers > 64)
|
||||
transfers = 64;
|
||||
uint8_t *p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = 1;
|
||||
*p++ = transfers | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
|
||||
int n_di_bytes = (transfers + 7) >> 3;
|
||||
if (DI) {
|
||||
p = memcpy(p, DI, n_di_bytes);
|
||||
DI += n_di_bytes;
|
||||
} else {
|
||||
p = memset(p, 0xff, n_di_bytes);
|
||||
}
|
||||
p += n_di_bytes;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] != DAP_OK)
|
||||
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
memcpy(DO, &buf[1], (transfers + 7) >> 3);
|
||||
DO += (transfers + 7) >> 3;
|
||||
}
|
||||
ticks -= transfers;
|
||||
}
|
||||
if (final_tms) {
|
||||
uint8_t *p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = 1;
|
||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
|
||||
if (DI) {
|
||||
*p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0);
|
||||
} else {
|
||||
*p++ = 0;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] == DAP_ERROR)
|
||||
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
if (buf[1] & 1)
|
||||
DO[last_byte] |= (1 << last_bit);
|
||||
else
|
||||
DO[last_byte] &= ~(1 << last_bit);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while(ticks) {
|
||||
uint8_t *p = buf;
|
||||
int transfers = ticks;
|
||||
if (transfers > 64)
|
||||
transfers = 64;
|
||||
p = buf;
|
||||
*p++ = ID_DAP_JTAG_SEQUENCE;
|
||||
*p++ = transfers;
|
||||
for (int i = 0; i < transfers; i++) {
|
||||
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) |
|
||||
((TMS[i >> 8] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
|
||||
if (DI)
|
||||
*p++ = (DI[i >> 8] & (1 << (i & 7))) ? 1 : 0;
|
||||
else
|
||||
*p++ = 0x55;
|
||||
}
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] == DAP_ERROR)
|
||||
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
|
||||
if (DO) {
|
||||
for (int i = 0; i < transfers; i++) {
|
||||
if (buf[i + 1])
|
||||
DO[i >> 8] |= (1 << (i & 7));
|
||||
else
|
||||
DO[i >> 8] &= ~(1 << (i & 7));
|
||||
}
|
||||
}
|
||||
ticks -= transfers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dap_jtag_configure(void)
|
||||
{
|
||||
uint8_t buf[64], *p = &buf[2];
|
||||
int i = 0;
|
||||
for (; i < jtag_dev_count; i++) {
|
||||
struct jtag_dev_s *jtag_dev = &jtag_devs[i];
|
||||
*p++ = jtag_dev->ir_len;
|
||||
DEBUG_PROBE("irlen %d\n", jtag_dev->ir_len);
|
||||
}
|
||||
if ((!i || i >= JTAG_MAX_DEVS))
|
||||
return -1;
|
||||
buf[0] = 0x15;
|
||||
buf[1] = i;
|
||||
dbg_dap_cmd(buf, sizeof(buf), p - buf);
|
||||
if (buf[0] != DAP_OK)
|
||||
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015, Alex Taradov <alex@taradov.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DAP_H_
|
||||
#define _DAP_H_
|
||||
|
||||
/*- Includes ----------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "adiv5.h"
|
||||
|
||||
/*- Definitions -------------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
DAP_INFO_VENDOR = 0x01,
|
||||
DAP_INFO_PRODUCT = 0x02,
|
||||
DAP_INFO_SER_NUM = 0x03,
|
||||
DAP_INFO_FW_VER = 0x04,
|
||||
DAP_INFO_DEVICE_VENDOR = 0x05,
|
||||
DAP_INFO_DEVICE_NAME = 0x06,
|
||||
DAP_INFO_CAPABILITIES = 0xf0,
|
||||
DAP_INFO_TDT = 0xf1,
|
||||
DAP_INFO_SWO_BUF_SIZE = 0xfd,
|
||||
DAP_INFO_PACKET_COUNT = 0xfe,
|
||||
DAP_INFO_PACKET_SIZE = 0xff,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DAP_CAP_SWD = (1 << 0),
|
||||
DAP_CAP_JTAG = (1 << 1),
|
||||
DAP_CAP_SWO_UART = (1 << 2),
|
||||
DAP_CAP_SWO_MANCHESTER = (1 << 3),
|
||||
DAP_CAP_ATOMIC_CMD = (1 << 4),
|
||||
DAP_CAP_TDT = (1 << 5),
|
||||
DAP_CAP_SWO_STREAMING = (1 << 6),
|
||||
};
|
||||
|
||||
/*- Prototypes --------------------------------------------------------------*/
|
||||
void dap_led(int index, int state);
|
||||
void dap_connect(bool jtag);
|
||||
void dap_disconnect(void);
|
||||
void dap_swj_clock(uint32_t clock);
|
||||
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry);
|
||||
void dap_swd_configure(uint8_t cfg);
|
||||
int dap_info(int info, uint8_t *data, int size);
|
||||
void dap_reset_target(void);
|
||||
void dap_trst_reset(void);
|
||||
void dap_reset_target_hw(int state);
|
||||
void dap_reset_pin(int state);
|
||||
uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg);
|
||||
void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data);
|
||||
void dap_reset_link(bool jtag);
|
||||
uint32_t dap_read_idcode(ADIv5_DP_t *dp);
|
||||
unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len, enum align align);
|
||||
unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align);
|
||||
void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align);
|
||||
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr);
|
||||
void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align);
|
||||
void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
enum align align);
|
||||
int dbg_dap_cmd(uint8_t *data, int size, int rsize);
|
||||
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
|
||||
const uint8_t *DI, int ticks);
|
||||
int dap_jtag_configure(void);
|
||||
#endif // _DAP_H_
|
|
@ -21,14 +21,15 @@
|
|||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "platform.h"
|
||||
#include "target.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct ftdi_context *ftdic;
|
||||
#include "ftdi_bmp.h"
|
||||
|
||||
#include "cl_utils.h"
|
||||
struct ftdi_context *ftdic;
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
static uint8_t outbuf[BUF_SIZE];
|
||||
|
@ -180,117 +181,103 @@ cable_desc_t cable_desc[] = {
|
|||
},
|
||||
};
|
||||
|
||||
void platform_init(int argc, char **argv)
|
||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
||||
{
|
||||
BMP_CL_OPTIONS_t cl_opts = {0};
|
||||
cl_opts.opt_idstring = "Blackmagic Debug Probe for FTDI/MPSSE";
|
||||
cl_opts.opt_cable = "ftdi";
|
||||
cl_init(&cl_opts, argc, argv);
|
||||
|
||||
int err;
|
||||
unsigned index = 0;
|
||||
int ret = -1;
|
||||
for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
|
||||
index++)
|
||||
if (strcmp(cable_desc[index].name, cl_opts.opt_cable) == 0)
|
||||
if (strcmp(cable_desc[index].name, cl_opts->opt_cable) == 0)
|
||||
break;
|
||||
|
||||
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])){
|
||||
fprintf(stderr, "No cable matching %s found\n", cl_opts.opt_cable);
|
||||
exit(-1);
|
||||
if (index == sizeof(cable_desc)/sizeof(cable_desc[0])) {
|
||||
DEBUG_WARN( "No cable matching %s found\n", cl_opts->opt_cable);
|
||||
return -1;
|
||||
}
|
||||
|
||||
active_cable = &cable_desc[index];
|
||||
|
||||
printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n");
|
||||
printf("Copyright (C) 2015 Black Sphere Technologies Ltd.\n");
|
||||
printf("License GPLv3+: GNU GPL version 3 or later "
|
||||
"<http://gnu.org/licenses/gpl.html>\n\n");
|
||||
|
||||
DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n");
|
||||
if(ftdic) {
|
||||
ftdi_usb_close(ftdic);
|
||||
ftdi_free(ftdic);
|
||||
ftdic = NULL;
|
||||
}
|
||||
if((ftdic = ftdi_new()) == NULL) {
|
||||
fprintf(stderr, "ftdi_new: %s\n",
|
||||
DEBUG_WARN( "ftdi_new: %s\n",
|
||||
ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
info->ftdic = ftdic;
|
||||
if((err = ftdi_set_interface(ftdic, active_cable->interface)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_interface: %d: %s\n",
|
||||
DEBUG_WARN( "ftdi_set_interface: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_1;
|
||||
}
|
||||
if((err = ftdi_usb_open_desc(
|
||||
ftdic, active_cable->vendor, active_cable->product,
|
||||
active_cable->description, cl_opts.opt_serial)) != 0) {
|
||||
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
|
||||
active_cable->description, cl_opts->opt_serial)) != 0) {
|
||||
DEBUG_WARN( "unable to open ftdi device: %d (%s)\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_1;
|
||||
}
|
||||
|
||||
if((err = ftdi_set_latency_timer(ftdic, 1)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_latency_timer: %d: %s\n",
|
||||
DEBUG_WARN( "ftdi_set_latency_timer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
if((err = ftdi_set_baudrate(ftdic, 1000000)) != 0) {
|
||||
fprintf(stderr, "ftdi_set_baudrate: %d: %s\n",
|
||||
DEBUG_WARN( "ftdi_set_baudrate: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
if((err = ftdi_write_data_set_chunksize(ftdic, BUF_SIZE)) != 0) {
|
||||
fprintf(stderr, "ftdi_write_data_set_chunksize: %d: %s\n",
|
||||
DEBUG_WARN( "ftdi_write_data_set_chunksize: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
goto error_2;
|
||||
}
|
||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||
ret = cl_execute(&cl_opts);
|
||||
} else {
|
||||
assert(gdb_if_init() == 0);
|
||||
return;
|
||||
}
|
||||
return 0;
|
||||
error_2:
|
||||
ftdi_usb_close(ftdic);
|
||||
error_1:
|
||||
ftdi_free(ftdic);
|
||||
exit(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void platform_srst_set_val(bool assert)
|
||||
void libftdi_srst_set_val(bool assert)
|
||||
{
|
||||
(void)assert;
|
||||
platform_buffer_flush();
|
||||
libftdi_buffer_flush();
|
||||
}
|
||||
|
||||
bool platform_srst_get_val(void) { return false; }
|
||||
bool libftdi_srst_get_val(void) { return false; }
|
||||
|
||||
void platform_buffer_flush(void)
|
||||
void libftdi_buffer_flush(void)
|
||||
{
|
||||
assert(ftdi_write_data(ftdic, outbuf, bufptr) == bufptr);
|
||||
// printf("FT2232 platform_buffer flush: %d bytes\n", bufptr);
|
||||
DEBUG_WIRE("FT2232 libftdi_buffer flush: %d bytes\n", bufptr);
|
||||
bufptr = 0;
|
||||
}
|
||||
|
||||
int platform_buffer_write(const uint8_t *data, int size)
|
||||
int libftdi_buffer_write(const uint8_t *data, int size)
|
||||
{
|
||||
if((bufptr + size) / BUF_SIZE > 0) platform_buffer_flush();
|
||||
if((bufptr + size) / BUF_SIZE > 0) libftdi_buffer_flush();
|
||||
memcpy(outbuf + bufptr, data, size);
|
||||
bufptr += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int platform_buffer_read(uint8_t *data, int size)
|
||||
int libftdi_buffer_read(uint8_t *data, int size)
|
||||
{
|
||||
int index = 0;
|
||||
outbuf[bufptr++] = SEND_IMMEDIATE;
|
||||
platform_buffer_flush();
|
||||
libftdi_buffer_flush();
|
||||
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
|
||||
return size;
|
||||
}
|
||||
|
||||
const char *platform_target_voltage(void)
|
||||
const char *libftdi_target_voltage(void)
|
||||
{
|
||||
return "not supported";
|
||||
}
|
|
@ -18,36 +18,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PLATFORM_H
|
||||
#define __PLATFORM_H
|
||||
#ifndef __FTDI_BMP_H
|
||||
#define __FTDI_BMP_H
|
||||
|
||||
#include <libftdi1/ftdi.h>
|
||||
|
||||
#include "timing.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <alloca.h>
|
||||
#else
|
||||
# ifndef alloca
|
||||
# define alloca __builtin_alloca
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define FT2232_VID 0x0403
|
||||
#define FT2232_PID 0x6010
|
||||
|
||||
#define PLATFORM_HAS_DEBUG
|
||||
|
||||
#define PLATFORM_IDENT "FTDI/MPSSE"
|
||||
#define SET_RUN_STATE(state)
|
||||
#define SET_IDLE_STATE(state)
|
||||
#define SET_ERROR_STATE(state)
|
||||
|
||||
extern struct ftdi_context *ftdic;
|
||||
|
||||
void platform_buffer_flush(void);
|
||||
int platform_buffer_write(const uint8_t *data, int size);
|
||||
int platform_buffer_read(uint8_t *data, int size);
|
||||
#include "cl_utils.h"
|
||||
#include "swdptap.h"
|
||||
#include "jtagtap.h"
|
||||
|
||||
typedef struct cable_desc_s {
|
||||
int vendor;
|
||||
|
@ -67,15 +43,19 @@ typedef struct cable_desc_s {
|
|||
}cable_desc_t;
|
||||
|
||||
extern cable_desc_t *active_cable;
|
||||
extern struct ftdi_context *ftdic;
|
||||
|
||||
static inline int platform_hwversion(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
|
||||
|
||||
int libftdi_swdptap_init(swd_proc_t *swd_proc);
|
||||
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||
void libftdi_buffer_flush(void);
|
||||
int libftdi_buffer_write(const uint8_t *data, int size);
|
||||
int libftdi_buffer_read(uint8_t *data, int size);
|
||||
const char *libftdi_target_voltage(void);
|
||||
|
||||
#define MPSSE_TDI 2
|
||||
#define MPSSE_TDO 4
|
||||
#define MPSSE_TMS 8
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* Base on code from git://repo.or.cz/libjaylink.git
|
||||
* and https://github.com/afaerber/jlink.git*/
|
||||
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "adiv5.h"
|
||||
#include "exception.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "cl_utils.h"
|
||||
#include "jlink.h"
|
||||
|
||||
#define USB_PID_SEGGER 0x1366
|
||||
|
||||
/* Only two devices PIDS tested so long */
|
||||
#define USB_VID_SEGGER_0101 0x0101
|
||||
#define USB_VID_SEGGER_0105 0x0105
|
||||
|
||||
static void jlink_print_caps(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[1] = {CMD_GET_CAPS};
|
||||
uint8_t res[4];
|
||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||
uint32_t caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
|
||||
DEBUG_INFO("Caps %" PRIx32 "\n", caps);
|
||||
if (caps & JLINK_CAP_GET_HW_VERSION) {
|
||||
uint8_t cmd[1] = {CMD_GET_HW_VERSION};
|
||||
send_recv(info->usb_link, cmd, 1, NULL, 0);
|
||||
send_recv(info->usb_link, NULL, 0, res, sizeof(res));
|
||||
DEBUG_INFO("HW: Type %d, Major %d, Minor %d, Rev %d\n",
|
||||
res[3], res[2], res[1], res[0]);
|
||||
}
|
||||
}
|
||||
static void jlink_print_speed(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[1] = {CMD_GET_SPEED};
|
||||
uint8_t res[6];
|
||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||
uint32_t speed = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
|
||||
double freq_mhz = speed / 1000000.0;
|
||||
uint16_t divisor = res[4] | (res[5] << 8);
|
||||
DEBUG_INFO("Emulator speed %3.1f MHz, Mindiv %d\n", freq_mhz, divisor);
|
||||
}
|
||||
|
||||
static void jlink_print_version(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[1] = {CMD_GET_VERSION};
|
||||
uint8_t len_str[2];
|
||||
send_recv(info->usb_link, cmd, 1, len_str, sizeof(len_str));
|
||||
uint8_t version[0x70];
|
||||
send_recv(info->usb_link, NULL, 0, version, sizeof(version));
|
||||
DEBUG_INFO("%s\n", version );
|
||||
}
|
||||
|
||||
static void jlink_print_interfaces(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_ACTIVE};
|
||||
uint8_t res[4];
|
||||
send_recv(info->usb_link, cmd, 2, res, sizeof(res));
|
||||
cmd[1] = JLINK_IF_GET_AVAILABLE;
|
||||
uint8_t res1[4];
|
||||
send_recv(info->usb_link, cmd, 2, res1, sizeof(res1));
|
||||
DEBUG_INFO("%s active", (res[0] == SELECT_IF_SWD) ? "SWD":
|
||||
(res[0] == SELECT_IF_JTAG) ? "JTAG" : "NONE");
|
||||
uint8_t other_interface = res1[0] - (res[0] + 1);
|
||||
if (other_interface)
|
||||
DEBUG_INFO(", %s available\n",
|
||||
(other_interface == JLINK_IF_SWD) ? "SWD": "JTAG");
|
||||
else
|
||||
DEBUG_WARN(", %s not available\n",
|
||||
((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD");
|
||||
}
|
||||
|
||||
static void jlink_info(bmp_info_t *info)
|
||||
{
|
||||
jlink_print_version(info);
|
||||
jlink_print_speed(info);
|
||||
jlink_print_caps(info);
|
||||
jlink_print_interfaces(info);
|
||||
}
|
||||
|
||||
/* On success endpoints are set and return 0, !0 else */
|
||||
static int initialize_handle(bmp_info_t *info, libusb_device *dev)
|
||||
{
|
||||
struct libusb_config_descriptor *config;
|
||||
int ret = libusb_get_active_config_descriptor(dev, &config);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
DEBUG_WARN( "Failed to get configuration descriptor: %s.",
|
||||
libusb_error_name(ret));
|
||||
return -1;
|
||||
}
|
||||
const struct libusb_interface *interface;
|
||||
bool found_interface = false;
|
||||
const struct libusb_interface_descriptor *desc;
|
||||
for (int i = 0; i < config->bNumInterfaces; i++) {
|
||||
interface = &config->interface[i];
|
||||
desc = &interface->altsetting[0];
|
||||
if (desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC)
|
||||
continue;
|
||||
if (desc->bInterfaceSubClass != LIBUSB_CLASS_VENDOR_SPEC)
|
||||
continue;
|
||||
if (desc->bNumEndpoints < 2)
|
||||
continue;
|
||||
found_interface = true;
|
||||
if (libusb_claim_interface (
|
||||
info->usb_link->ul_libusb_device_handle, i)) {
|
||||
DEBUG_WARN( " Can not claim handle\n");
|
||||
found_interface = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!found_interface) {
|
||||
DEBUG_WARN( "No suitable interface found.");
|
||||
libusb_free_config_descriptor(config);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < desc->bNumEndpoints; i++) {
|
||||
const struct libusb_endpoint_descriptor *epdesc = &desc->endpoint[i];
|
||||
if (epdesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
|
||||
info->usb_link->ep_rx = epdesc->bEndpointAddress;
|
||||
} else {
|
||||
info->usb_link->ep_tx = epdesc->bEndpointAddress;
|
||||
}
|
||||
}
|
||||
libusb_free_config_descriptor(config);
|
||||
return 0;
|
||||
}
|
||||
/* Return 0 if single J-Link device connected or
|
||||
* serial given matches one of several J-Link devices.
|
||||
*/
|
||||
int jlink_init(bmp_info_t *info)
|
||||
{
|
||||
usb_link_t *jl = calloc(1, sizeof(usb_link_t));
|
||||
if (!jl)
|
||||
return -1;
|
||||
info->usb_link = jl;
|
||||
jl->ul_libusb_ctx = info->libusb_ctx;
|
||||
int ret = -1;
|
||||
libusb_device **devs;
|
||||
if (libusb_get_device_list(info->libusb_ctx, &devs) < 0) {
|
||||
DEBUG_WARN( "libusb_get_device_list() failed");
|
||||
return ret;
|
||||
}
|
||||
int i = 0;
|
||||
for (; devs[i]; i++) {
|
||||
libusb_device *dev = devs[i];
|
||||
struct libusb_device_descriptor desc;
|
||||
if (libusb_get_device_descriptor(dev, &desc) < 0) {
|
||||
DEBUG_WARN( "libusb_get_device_descriptor() failed");
|
||||
goto error;;
|
||||
}
|
||||
if (desc.idVendor != USB_PID_SEGGER)
|
||||
continue;
|
||||
if ((desc.idProduct != USB_VID_SEGGER_0101) &&
|
||||
(desc.idProduct != USB_VID_SEGGER_0105))
|
||||
continue;
|
||||
int res = libusb_open(dev, &jl->ul_libusb_device_handle);
|
||||
if (res != LIBUSB_SUCCESS)
|
||||
continue;
|
||||
char buf[32];
|
||||
res = libusb_get_string_descriptor_ascii(jl->ul_libusb_device_handle,
|
||||
desc.iSerialNumber, (uint8_t*) buf, sizeof(buf));
|
||||
if ((res <= 0) || (!strstr(buf, info->serial))) {
|
||||
libusb_close(jl->ul_libusb_device_handle);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!devs[i])
|
||||
goto error;
|
||||
if (initialize_handle(info, devs[i]))
|
||||
goto error;
|
||||
jl->req_trans = libusb_alloc_transfer(0);
|
||||
jl->rep_trans = libusb_alloc_transfer(0);
|
||||
if (!jl->req_trans || !jl->rep_trans ||
|
||||
!jl->ep_tx || !jl->ep_rx) {
|
||||
DEBUG_WARN("Device setup failed\n");
|
||||
goto error;
|
||||
}
|
||||
libusb_free_device_list(devs, 1);
|
||||
jlink_info(info);
|
||||
return 0;
|
||||
error:
|
||||
libusb_free_device_list(devs, 1);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
const char *jlink_target_voltage(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[1] = {CMD_GET_HW_STATUS};
|
||||
uint8_t res[8];
|
||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||
uint16_t mVolt = res[0] | (res[1] << 8);
|
||||
static char ret[7];
|
||||
sprintf(ret, "%2d.%03d", mVolt / 1000, mVolt % 1000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool srst_status = false;
|
||||
void jlink_srst_set_val(bmp_info_t *info, bool assert)
|
||||
{
|
||||
uint8_t cmd[1];
|
||||
cmd[0]= (assert)? CMD_HW_RESET0: CMD_HW_RESET1;
|
||||
send_recv(info->usb_link, cmd, 1, NULL, 0);
|
||||
platform_delay(2);
|
||||
srst_status = assert;
|
||||
}
|
||||
|
||||
bool jlink_srst_get_val(bmp_info_t *info) {
|
||||
uint8_t cmd[1] = {CMD_GET_HW_STATUS};
|
||||
uint8_t res[8];
|
||||
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
|
||||
return !(res[6]);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__JLINK_H_)
|
||||
#define __JLINK_H_
|
||||
|
||||
#include "jtagtap.h"
|
||||
|
||||
/** @cond PRIVATE */
|
||||
#define CMD_GET_VERSION 0x01
|
||||
#define CMD_GET_HW_STATUS 0x07
|
||||
#define CMD_GET_SPEED 0xc0
|
||||
#define CMD_GET_SELECT_IF 0xc7
|
||||
#define CMD_HW_JTAG3 0xcf
|
||||
#define CMD_HW_RESET0 0xdc
|
||||
#define CMD_HW_RESET1 0xdd
|
||||
#define CMD_GET_CAPS 0xe8
|
||||
#define CMD_GET_EXT_CAPS 0xed
|
||||
#define CMD_GET_HW_VERSION 0xf0
|
||||
|
||||
#define JLINK_IF_GET_ACTIVE 0xfe
|
||||
#define JLINK_IF_GET_AVAILABLE 0xff
|
||||
|
||||
#define JLINK_CAP_GET_HW_VERSION 2
|
||||
#define JLINK_IF_JTAG 1
|
||||
#define JLINK_IF_SWD 2
|
||||
|
||||
#define SELECT_IF_JTAG 0
|
||||
#define SELECT_IF_SWD 1
|
||||
|
||||
|
||||
int jlink_init(bmp_info_t *info);
|
||||
int jlink_swdp_scan(bmp_info_t *info);
|
||||
int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc);
|
||||
const char *jlink_target_voltage(bmp_info_t *info);
|
||||
void jlink_srst_set_val(bmp_info_t *info, bool assert);
|
||||
bool jlink_srst_get_val(bmp_info_t *info);
|
||||
#endif
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file implements the SW-DP specific functions of the
|
||||
* ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A.
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "exception.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "adiv5.h"
|
||||
#include "jlink.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
#define SWDP_ACK_OK 0x01
|
||||
#define SWDP_ACK_WAIT 0x02
|
||||
#define SWDP_ACK_FAULT 0x04
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_error(ADIv5_DP_t *dp);
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
|
||||
static void jlink_adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort);
|
||||
|
||||
enum {
|
||||
SWDIO_WRITE = 0,
|
||||
SWDIO_READ
|
||||
};
|
||||
|
||||
/* Write at least 50 bits high, two bits low and read DP_IDR and put
|
||||
* idle cyccles at the end*/
|
||||
static int line_reset(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[44];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
/* write 19 Bytes.*/
|
||||
cmd[2] = 19 * 8;
|
||||
cmd[3] = 0;
|
||||
uint8_t *direction = cmd + 4;
|
||||
direction[0] = 0;
|
||||
direction[1] = 0;
|
||||
direction[2] = 0;
|
||||
direction[3] = 0;
|
||||
direction[4] = 0;
|
||||
direction[5] = 0xff;
|
||||
direction[6] = 0xff;
|
||||
direction[7] = 0xff;
|
||||
direction[8] = 0xff;
|
||||
direction[9] = 0xff;
|
||||
direction[10] = 0xff;
|
||||
direction[11] = 0xff;
|
||||
direction[12] = 0xff;
|
||||
direction[13] = 0xff;
|
||||
direction[14] = 0x0;
|
||||
direction[15] = 0x0;
|
||||
direction[16] = 0x0;
|
||||
direction[17] = 0x0;
|
||||
direction[18] = 0xe0;
|
||||
uint8_t *data = direction + 19;
|
||||
data[5] = 0xff;
|
||||
data[6] = 0xff;
|
||||
data[7] = 0xff;
|
||||
data[8] = 0xff;
|
||||
data[9] = 0xff;
|
||||
data[10] = 0xff;
|
||||
data[11] = 0xff;
|
||||
data[12] = 0;
|
||||
data[13] = 0xa5;
|
||||
data[18] = 0;
|
||||
|
||||
uint8_t res[18];
|
||||
send_recv(info->usb_link, cmd, 42, res, 19);
|
||||
send_recv(info->usb_link, NULL, 0, res, 1);
|
||||
|
||||
if (res[0] != 0) {
|
||||
DEBUG_WARN( "Line reset failed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swdptap_init(bmp_info_t *info)
|
||||
{
|
||||
uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE};
|
||||
uint8_t res[4];
|
||||
send_recv(info->usb_link, cmd, 2, res, sizeof(res));
|
||||
if (!(res[0] & JLINK_IF_SWD))
|
||||
return -1;
|
||||
cmd[1] = SELECT_IF_SWD;
|
||||
send_recv(info->usb_link, cmd, 2, res, sizeof(res));
|
||||
platform_delay(10);
|
||||
/* Set speed 256 kHz*/
|
||||
unsigned int speed = 2000;
|
||||
uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8};
|
||||
send_recv(info->usb_link, jtag_speed, 3, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jlink_swdp_scan(bmp_info_t *info)
|
||||
{
|
||||
swdptap_init(info);
|
||||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!dp) /* calloc failed: heap exhaustion */
|
||||
return 0;
|
||||
uint8_t cmd[44];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
/* write 18 Bytes.*/
|
||||
cmd[2] = 17 * 8;
|
||||
cmd[3] = 0;
|
||||
uint8_t *direction = cmd + 4;
|
||||
direction[0] = 0xff;
|
||||
direction[1] = 0xff;
|
||||
direction[2] = 0xff;
|
||||
direction[3] = 0xff;
|
||||
direction[4] = 0xff;
|
||||
direction[5] = 0xff;
|
||||
direction[6] = 0xff;
|
||||
direction[7] = 0xff;
|
||||
direction[8] = 0xff;
|
||||
direction[9] = 0xff;
|
||||
direction[10] = 0xff;
|
||||
direction[11] = 0xff;
|
||||
direction[12] = 0xff;
|
||||
direction[13] = 0xff;
|
||||
direction[14] = 0xff;
|
||||
direction[15] = 0xff;
|
||||
direction[16] = 0xff;
|
||||
uint8_t *data = direction + 17;
|
||||
data[0] = 0xff;
|
||||
data[1] = 0xff;
|
||||
data[2] = 0xff;
|
||||
data[3] = 0xff;
|
||||
data[4] = 0xff;
|
||||
data[5] = 0xff;
|
||||
data[6] = 0xff;
|
||||
data[7] = 0x9e;
|
||||
data[8] = 0xe7;
|
||||
data[9] = 0xff;
|
||||
data[10] = 0xff;
|
||||
data[11] = 0xff;
|
||||
data[12] = 0xff;
|
||||
data[13] = 0xff;
|
||||
data[14] = 0xff;
|
||||
data[15] = 0;
|
||||
data[16] = 0;
|
||||
|
||||
uint8_t res[18];
|
||||
send_recv(info->usb_link, cmd, 38, res, 17);
|
||||
send_recv(info->usb_link, NULL, 0, res, 1);
|
||||
|
||||
if (res[0] != 0) {
|
||||
DEBUG_WARN( "Line reset failed\n");
|
||||
return 0;
|
||||
}
|
||||
dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0);
|
||||
dp->dp_read = jlink_adiv5_swdp_read;
|
||||
dp->error = jlink_adiv5_swdp_error;
|
||||
dp->low_access = jlink_adiv5_swdp_low_access;
|
||||
dp->abort = jlink_adiv5_swdp_abort;
|
||||
|
||||
jlink_adiv5_swdp_error(dp);
|
||||
adiv5_dp_init(dp);
|
||||
return target_list?1:0;
|
||||
}
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
if (addr & ADIV5_APnDP) {
|
||||
adiv5_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
return adiv5_dp_low_access(dp, ADIV5_LOW_READ,
|
||||
ADIV5_DP_RDBUFF, 0);
|
||||
} else {
|
||||
return jlink_adiv5_swdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
uint32_t err, clr = 0;
|
||||
err = jlink_adiv5_swdp_read(dp, ADIV5_DP_CTRLSTAT) &
|
||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
||||
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYORUN)
|
||||
clr |= ADIV5_DP_ABORT_ORUNERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYCMP)
|
||||
clr |= ADIV5_DP_ABORT_STKCMPCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_STICKYERR)
|
||||
clr |= ADIV5_DP_ABORT_STKERRCLR;
|
||||
if(err & ADIV5_DP_CTRLSTAT_WDATAERR)
|
||||
clr |= ADIV5_DP_ABORT_WDERRCLR;
|
||||
if (clr)
|
||||
adiv5_dp_write(dp, ADIV5_DP_ABORT, clr);
|
||||
if (dp->fault)
|
||||
err |= 0x8000;
|
||||
dp->fault = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
uint8_t addr8 = addr & 0xff;
|
||||
uint8_t request = 0x81;
|
||||
uint32_t response = 0;
|
||||
uint8_t ack;
|
||||
platform_timeout timeout;
|
||||
|
||||
if(APnDP && dp->fault) return 0;
|
||||
|
||||
if(APnDP) request ^= 0x22;
|
||||
if(RnW) request ^= 0x24;
|
||||
|
||||
addr8 &= 0xC;
|
||||
request |= (addr8 << 1) & 0x18;
|
||||
if((addr8 == 4) || (addr8 == 8))
|
||||
request ^= 0x20;
|
||||
uint8_t cmd[16];
|
||||
uint8_t res[8];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = 13;
|
||||
cmd[3] = 0;
|
||||
cmd[4] = 0xff;
|
||||
cmd[5] = 0xe3;
|
||||
cmd[6] = request << 2;
|
||||
cmd[7] = request >> 6;
|
||||
platform_timeout_set(&timeout, 2000);
|
||||
do {
|
||||
send_recv(info.usb_link, cmd, 8, res, 2);
|
||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||
if (res[0] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "Low access setup failed");
|
||||
ack = res[1] >> 2;
|
||||
ack &= 7;
|
||||
} while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout));
|
||||
if (ack == SWDP_ACK_WAIT)
|
||||
raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout");
|
||||
|
||||
if(ack == SWDP_ACK_FAULT) {
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET)
|
||||
DEBUG_WARN( "Fault\n");
|
||||
dp->fault = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ack != SWDP_ACK_OK) {
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET)
|
||||
DEBUG_WARN( "Protocol\n");
|
||||
line_reset(&info);
|
||||
return 0;
|
||||
}
|
||||
cmd[3] = 0;
|
||||
/* Always prepend an idle cycle (SWDIO = 0)!*/
|
||||
if(RnW) {
|
||||
memset(cmd + 4, 0, 10);
|
||||
cmd[2] = 34;
|
||||
cmd[8] = 0xfe;
|
||||
cmd[13] = 0;
|
||||
send_recv(info.usb_link, cmd, 14, res, 5);
|
||||
send_recv(info.usb_link, NULL, 0, res + 5, 1);
|
||||
if (res[5] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "Low access read failed");
|
||||
response = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24;
|
||||
int parity = res[4] & 1;
|
||||
int bit_count = __builtin_popcount (response) + parity;
|
||||
if (bit_count & 1) /* Give up on parity error */
|
||||
raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
|
||||
} else {
|
||||
cmd[2] = 35;
|
||||
memset(cmd + 4, 0xff, 5);
|
||||
cmd[ 9] = ((value << 2) & 0xfc);
|
||||
cmd[10] = ((value >> 6) & 0xff);
|
||||
cmd[11] = ((value >> 14) & 0xff);
|
||||
cmd[12] = ((value >> 22) & 0xff);
|
||||
cmd[13] = ((value >> 30) & 0x03);
|
||||
int bit_count = __builtin_popcount(value);
|
||||
cmd[13] |= ((bit_count & 1) ? 4 : 0);
|
||||
send_recv(info.usb_link, cmd, 14, res, 5);
|
||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||
if (res[0] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "Low access write failed");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
static void jlink_adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
{
|
||||
adiv5_dp_write(dp, ADIV5_DP_ABORT, abort);
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Low level JTAG implementation using jlink.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "exception.h"
|
||||
|
||||
#include "jlink.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
static void jtagtap_reset(void)
|
||||
{
|
||||
jtagtap_soft_reset();
|
||||
}
|
||||
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
DEBUG_PROBE("jtagtap_tms_seq 0x%08" PRIx32 ", ticks %d\n", MS, ticks);
|
||||
int len = (ticks + 7) / 8;
|
||||
uint8_t cmd[12];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = ticks;
|
||||
cmd[3] = 0;
|
||||
uint8_t *tms = cmd + 4;
|
||||
for (int i = 0; i < len; i++) {
|
||||
*tms = MS & 0xff;
|
||||
*(tms + len) = *tms;
|
||||
tms++;
|
||||
MS >>= 8;
|
||||
}
|
||||
uint8_t res[4];
|
||||
send_recv(info.usb_link, cmd, 4 + 2 * len, res, len);
|
||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||
if (res[0] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "tagtap_tms_seq failed");
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks)
|
||||
{
|
||||
if (!ticks)
|
||||
return;
|
||||
int len = (ticks + 7) / 8;
|
||||
if (cl_debuglevel & BMP_DEBUG_PROBE) {
|
||||
DEBUG_PROBE("jtagtap_tdi_tdo %s, ticks %d, DI: ",
|
||||
(final_tms) ? "Final TMS" : "", ticks);
|
||||
for (int i = 0; i < len; i++) {
|
||||
DEBUG_PROBE("%02x", DI[i]);
|
||||
}
|
||||
DEBUG_PROBE("\n");
|
||||
}
|
||||
uint8_t *cmd = alloca(4 + 2 * len);
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = ticks;
|
||||
cmd[3] = 0;
|
||||
uint8_t *tms = cmd + 4;
|
||||
for (int i = 0; i < len; i++)
|
||||
*tms++ = 0;
|
||||
if (final_tms)
|
||||
cmd[4 + (ticks - 1) / 8] |= (1 << ((ticks - 1) % 8));
|
||||
uint8_t *tdi = tms;
|
||||
if (DI)
|
||||
for (int i = 0; i < len; i++)
|
||||
*tdi++ = DI[i];
|
||||
if (DO)
|
||||
send_recv(info.usb_link, cmd, 4 + 2 * len, DO, len);
|
||||
else
|
||||
send_recv(info.usb_link, cmd, 4 + 2 * len, cmd, len);
|
||||
uint8_t res[1];
|
||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||
if (res[0] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "jtagtap_tdi_tdi failed");
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI,
|
||||
int ticks)
|
||||
{
|
||||
if (cl_debuglevel & BMP_DEBUG_PROBE) {
|
||||
DEBUG_PROBE("jtagtap_tdi_seq %s:", (final_tms)? "final_tms" : "");
|
||||
const uint8_t *p = DI;
|
||||
unsigned int i = (ticks & 7) & ~7 ;
|
||||
if (i > 16)
|
||||
i = 16;
|
||||
while (i--)
|
||||
DEBUG_PROBE(" %02x", *p++);
|
||||
if (ticks > (16 * 8))
|
||||
DEBUG_PROBE(" ...");
|
||||
DEBUG_PROBE("\n");
|
||||
}
|
||||
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
}
|
||||
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
DEBUG_PROBE("jtagtap_next TMS 0x%02x, TDI %02x\n", dTMS, dTDI);
|
||||
uint8_t cmd[6];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = 1;
|
||||
cmd[3] = 0;
|
||||
cmd[4] = (dTMS) ? 0xff : 0;
|
||||
cmd[5] = (dTDI) ? 0xff : 0;
|
||||
uint8_t ret[1];
|
||||
send_recv(info.usb_link, cmd, 6, ret, 1);
|
||||
uint8_t res[1];
|
||||
send_recv(info.usb_link, NULL, 0, res, 1);
|
||||
if (res[0] != 0)
|
||||
raise_exception(EXCEPTION_ERROR, "jtagtap_next failed");
|
||||
return (ret[0] & 1);
|
||||
}
|
||||
|
||||
int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc)
|
||||
{
|
||||
DEBUG_PROBE("jtap_init\n");
|
||||
uint8_t cmd_switch[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE};
|
||||
uint8_t res[4];
|
||||
send_recv(info->usb_link, cmd_switch, 2, res, sizeof(res));
|
||||
if (!(res[0] & JLINK_IF_JTAG)) {
|
||||
DEBUG_WARN("JTAG not available\n");
|
||||
return -1;
|
||||
}
|
||||
cmd_switch[1] = SELECT_IF_JTAG;
|
||||
send_recv(info->usb_link, cmd_switch, 2, res, sizeof(res));
|
||||
platform_delay(10);
|
||||
/* Set speed 256 kHz*/
|
||||
unsigned int speed = 2000;
|
||||
uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8};
|
||||
send_recv(info->usb_link, jtag_speed, 3, NULL, 0);
|
||||
uint8_t cmd[44];
|
||||
cmd[0] = CMD_HW_JTAG3;
|
||||
cmd[1] = 0;
|
||||
/* write 8 Bytes.*/
|
||||
cmd[2] = 9 * 8;
|
||||
cmd[3] = 0;
|
||||
uint8_t *tms = cmd + 4;
|
||||
tms[0] = 0xff;
|
||||
tms[1] = 0xff;
|
||||
tms[2] = 0xff;
|
||||
tms[3] = 0xff;
|
||||
tms[4] = 0xff;
|
||||
tms[5] = 0xff;
|
||||
tms[6] = 0xff;
|
||||
tms[7] = 0x3c;
|
||||
tms[8] = 0xe7;
|
||||
send_recv(info->usb_link, cmd, 4 + 2 * 9, cmd, 9);
|
||||
send_recv(info->usb_link, NULL, 0, res, 1);
|
||||
|
||||
if (res[0] != 0) {
|
||||
DEBUG_WARN("Switch to JTAG failed\n");
|
||||
return 0;
|
||||
}
|
||||
jtag_proc->jtagtap_reset = jtagtap_reset;
|
||||
jtag_proc->jtagtap_next =jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
|
||||
return 0;
|
||||
}
|
|
@ -31,30 +31,41 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "jtagtap.h"
|
||||
#include "ftdi_bmp.h"
|
||||
|
||||
int jtagtap_init(void)
|
||||
extern cable_desc_t *active_cable;
|
||||
extern struct ftdi_context *ftdic;
|
||||
|
||||
static void jtagtap_reset(void);
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks);
|
||||
static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
|
||||
const uint8_t *DI, int ticks);
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
|
||||
|
||||
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
assert(ftdic != NULL);
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
}
|
||||
/* Reset MPSSE controller. */
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x00, 0x00, SET_BITS_LOW, 0,0,
|
||||
SET_BITS_HIGH, 0,0};
|
||||
|
@ -62,58 +73,59 @@ int jtagtap_init(void)
|
|||
ftdi_init[5]= active_cable->dbus_ddr;
|
||||
ftdi_init[7]= active_cable->cbus_data;
|
||||
ftdi_init[8]= active_cable->cbus_ddr;
|
||||
platform_buffer_write(ftdi_init, 9);
|
||||
platform_buffer_flush();
|
||||
libftdi_buffer_write(ftdi_init, 9);
|
||||
libftdi_buffer_flush();
|
||||
|
||||
/* Go to JTAG mode for SWJ-DP */
|
||||
for (int i = 0; i <= 50; i++)
|
||||
jtagtap_next(1, 0); /* Reset SW-DP */
|
||||
jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */
|
||||
jtagtap_soft_reset();
|
||||
jtag_proc->jtagtap_reset = jtagtap_reset;
|
||||
jtag_proc->jtagtap_next =jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jtagtap_reset(void)
|
||||
static void jtagtap_reset(void)
|
||||
{
|
||||
jtagtap_soft_reset();
|
||||
}
|
||||
|
||||
void
|
||||
jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0};
|
||||
uint8_t tmp[3] = {
|
||||
MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0};
|
||||
while(ticks >= 0) {
|
||||
tmp[1] = ticks<7?ticks-1:6;
|
||||
tmp[2] = 0x80 | (MS & 0x7F);
|
||||
|
||||
platform_buffer_write(tmp, 3);
|
||||
libftdi_buffer_write(tmp, 3);
|
||||
MS >>= 7; ticks -= 7;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
int rsize, rticks;
|
||||
|
||||
if(!ticks) return;
|
||||
if (!DI && !DO) return;
|
||||
|
||||
// printf("ticks: %d\n", ticks);
|
||||
// DEBUG_PROBE("ticks: %d\n", ticks);
|
||||
if(final_tms) ticks--;
|
||||
rticks = ticks & 7;
|
||||
ticks >>= 3;
|
||||
uint8_t data[3];
|
||||
uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) | ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
|
||||
uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) |
|
||||
((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
|
||||
rsize = ticks;
|
||||
if(ticks) {
|
||||
data[0] = cmd;
|
||||
data[1] = ticks - 1;
|
||||
data[2] = 0;
|
||||
platform_buffer_write(data, 3);
|
||||
libftdi_buffer_write(data, 3);
|
||||
if (DI)
|
||||
platform_buffer_write(DI, ticks);
|
||||
libftdi_buffer_write(DI, ticks);
|
||||
}
|
||||
if(rticks) {
|
||||
int index = 0;
|
||||
|
@ -122,25 +134,26 @@ jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int
|
|||
data[index++] = rticks - 1;
|
||||
if (DI)
|
||||
data[index++] = DI[ticks];
|
||||
platform_buffer_write(data, index);
|
||||
libftdi_buffer_write(data, index);
|
||||
}
|
||||
if(final_tms) {
|
||||
int index = 0;
|
||||
rsize++;
|
||||
data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
||||
data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) |
|
||||
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
|
||||
data[index++] = 0;
|
||||
if (DI)
|
||||
data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
|
||||
platform_buffer_write(data, index);
|
||||
libftdi_buffer_write(data, index);
|
||||
}
|
||||
if (DO) {
|
||||
int index = 0;
|
||||
uint8_t *tmp = alloca(ticks);
|
||||
platform_buffer_read(tmp, rsize);
|
||||
libftdi_buffer_read(tmp, rsize);
|
||||
if(final_tms) rsize--;
|
||||
|
||||
while(rsize--) {
|
||||
/*if(rsize) printf("%02X ", tmp[index]);*/
|
||||
if(rsize) DEBUG_WIRE("%02X ", tmp[index]);
|
||||
*DO++ = tmp[index++];
|
||||
}
|
||||
if (rticks == 0)
|
||||
|
@ -153,22 +166,24 @@ jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int
|
|||
if(rticks) {
|
||||
*DO >>= (8-rticks);
|
||||
}
|
||||
/*printf("%02X\n", *DO);*/
|
||||
DEBUG_WIRE("%02X\n", *DO);
|
||||
}
|
||||
}
|
||||
|
||||
void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
}
|
||||
|
||||
uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint8_t ret;
|
||||
uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
|
||||
uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB |
|
||||
MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
|
||||
tmp[2] = (dTDI?0x80:0) | (dTMS?0x01:0);
|
||||
platform_buffer_write(tmp, 3);
|
||||
platform_buffer_read(&ret, 1);
|
||||
libftdi_buffer_write(tmp, 3);
|
||||
libftdi_buffer_read(&ret, 1);
|
||||
|
||||
ret &= 0x80;
|
||||
|
||||
|
@ -176,4 +191,3 @@ uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "swdptap.h"
|
||||
#include "ftdi_bmp.h"
|
||||
|
||||
static uint8_t olddir = 0;
|
||||
|
||||
|
@ -35,31 +35,36 @@ static uint8_t olddir = 0;
|
|||
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
|
||||
MPSSE_BITMODE | MPSSE_WRITE_NEG)
|
||||
|
||||
int swdptap_init(void)
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks);
|
||||
static uint32_t swdptap_seq_in(int ticks);
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks);
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||
|
||||
int libftdi_swdptap_init(swd_proc_t *swd_proc)
|
||||
{
|
||||
if (!active_cable->bitbang_tms_in_pin) {
|
||||
DEBUG("SWD not possible or missing item in cable description.\n");
|
||||
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
|
||||
return -1;
|
||||
}
|
||||
int err = ftdi_usb_purge_buffers(ftdic);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
/* Reset MPSSE controller. */
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
/* Enable MPSSE controller. Pin directions are set later.*/
|
||||
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
|
||||
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
|
||||
err, ftdi_get_error_string(ftdic));
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
|
||||
SET_BITS_HIGH, 0,0};
|
||||
|
@ -67,8 +72,13 @@ int swdptap_init(void)
|
|||
ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||
ftdi_init[7]= active_cable->cbus_data;
|
||||
ftdi_init[8]= active_cable->cbus_ddr;
|
||||
platform_buffer_write(ftdi_init, 9);
|
||||
platform_buffer_flush();
|
||||
libftdi_buffer_write(ftdi_init, 9);
|
||||
libftdi_buffer_flush();
|
||||
|
||||
swd_proc->swdptap_seq_in = swdptap_seq_in;
|
||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -99,37 +109,10 @@ static void swdptap_turnaround(uint8_t dir)
|
|||
cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
|
||||
cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK;
|
||||
}
|
||||
platform_buffer_write(cmd, index);
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
|
||||
bool swdptap_bit_in(void)
|
||||
{
|
||||
swdptap_turnaround(1);
|
||||
uint8_t cmd[4];
|
||||
int index = 0;
|
||||
|
||||
cmd[index++] = active_cable->bitbang_tms_in_port_cmd;
|
||||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = 0;
|
||||
platform_buffer_write(cmd, index);
|
||||
uint8_t data[1];
|
||||
platform_buffer_read(data, 1);
|
||||
return (data[0] &= active_cable->bitbang_tms_in_pin);
|
||||
}
|
||||
|
||||
void swdptap_bit_out(bool val)
|
||||
{
|
||||
swdptap_turnaround(0);
|
||||
uint8_t cmd[3];
|
||||
|
||||
cmd[0] = MPSSE_TMS_SHIFT;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = (val)? 1 : 0;
|
||||
platform_buffer_write(cmd, 3);
|
||||
}
|
||||
|
||||
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
{
|
||||
int index = ticks + 1;
|
||||
uint8_t cmd[4];
|
||||
|
@ -141,11 +124,11 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
|||
cmd[3] = 0;
|
||||
swdptap_turnaround(1);
|
||||
while (index--) {
|
||||
platform_buffer_write(cmd, 4);
|
||||
libftdi_buffer_write(cmd, 4);
|
||||
}
|
||||
uint8_t data[33];
|
||||
unsigned int ret = 0;
|
||||
platform_buffer_read(data, ticks + 1);
|
||||
libftdi_buffer_read(data, ticks + 1);
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin)
|
||||
parity ^= 1;
|
||||
while (ticks--) {
|
||||
|
@ -158,7 +141,7 @@ bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
|||
return parity;
|
||||
}
|
||||
|
||||
uint32_t swdptap_seq_in(int ticks)
|
||||
static uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
int index = ticks;
|
||||
uint8_t cmd[4];
|
||||
|
@ -170,11 +153,11 @@ uint32_t swdptap_seq_in(int ticks)
|
|||
|
||||
swdptap_turnaround(1);
|
||||
while (index--) {
|
||||
platform_buffer_write(cmd, 4);
|
||||
libftdi_buffer_write(cmd, 4);
|
||||
}
|
||||
uint8_t data[32];
|
||||
uint32_t ret = 0;
|
||||
platform_buffer_read(data, ticks);
|
||||
libftdi_buffer_read(data, ticks);
|
||||
while (ticks--) {
|
||||
if (data[ticks] & active_cable->bitbang_tms_in_pin)
|
||||
ret |= (1 << ticks);
|
||||
|
@ -182,7 +165,7 @@ uint32_t swdptap_seq_in(int ticks)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t cmd[15];
|
||||
unsigned int index = 0;
|
||||
|
@ -200,10 +183,10 @@ void swdptap_seq_out(uint32_t MS, int ticks)
|
|||
ticks = 0;
|
||||
}
|
||||
}
|
||||
platform_buffer_write(cmd, index);
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
||||
|
||||
void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t parity = 0;
|
||||
int steps = ticks;
|
||||
|
@ -231,5 +214,5 @@ void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
|||
cmd[index++] = MPSSE_TMS_SHIFT;
|
||||
cmd[index++] = 0;
|
||||
cmd[index++] = parity;
|
||||
platform_buffer_write(cmd, index);
|
||||
libftdi_buffer_write(cmd, index);
|
||||
}
|
|
@ -0,0 +1,618 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Handle different BMP pc-hosted platforms/
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "swdptap.h"
|
||||
#include "jtagtap.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "adiv5.h"
|
||||
#include "timing.h"
|
||||
#include "cl_utils.h"
|
||||
#include "gdb_if.h"
|
||||
#include <signal.h>
|
||||
|
||||
#include "bmp_remote.h"
|
||||
#include "stlinkv2.h"
|
||||
#include "ftdi_bmp.h"
|
||||
#include "jlink.h"
|
||||
#include "cmsis_dap.h"
|
||||
|
||||
#define VENDOR_ID_BMP 0x1d50
|
||||
#define PRODUCT_ID_BMP 0x6018
|
||||
|
||||
#define VENDOR_ID_STLINK 0x0483
|
||||
#define PRODUCT_ID_STLINK_MASK 0xffe0
|
||||
#define PRODUCT_ID_STLINK_GROUP 0x3740
|
||||
#define PRODUCT_ID_STLINKV1 0x3744
|
||||
#define PRODUCT_ID_STLINKV2 0x3748
|
||||
#define PRODUCT_ID_STLINKV21 0x374b
|
||||
#define PRODUCT_ID_STLINKV21_MSD 0x3752
|
||||
#define PRODUCT_ID_STLINKV3 0x374f
|
||||
#define PRODUCT_ID_STLINKV3E 0x374e
|
||||
|
||||
#define VENDOR_ID_SEGGER 0x1366
|
||||
|
||||
bmp_info_t info;
|
||||
|
||||
swd_proc_t swd_proc;
|
||||
jtag_proc_t jtag_proc;
|
||||
|
||||
static void exit_function(void)
|
||||
{
|
||||
if(info.usb_link) {
|
||||
libusb_free_transfer(info.usb_link->req_trans);
|
||||
libusb_free_transfer(info.usb_link->rep_trans);
|
||||
if (info.usb_link->ul_libusb_device_handle) {
|
||||
libusb_release_interface (
|
||||
info.usb_link->ul_libusb_device_handle, 0);
|
||||
libusb_close(info.usb_link->ul_libusb_device_handle);
|
||||
}
|
||||
}
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
dap_exit_function();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* SIGTERM handler. */
|
||||
static void sigterm_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
||||
{
|
||||
libusb_device **devs;
|
||||
int n_devs = libusb_get_device_list(info->libusb_ctx, &devs);
|
||||
if (n_devs < 0) {
|
||||
DEBUG_WARN( "WARN:libusb_get_device_list() failed");
|
||||
return -1;
|
||||
}
|
||||
bool report = false;
|
||||
int found_debuggers;
|
||||
struct libusb_device_descriptor desc;
|
||||
char serial[64];
|
||||
char manufacturer[128];
|
||||
char product[128];
|
||||
bmp_type_t type = BMP_TYPE_NONE;
|
||||
bool access_problems = false;
|
||||
rescan:
|
||||
found_debuggers = 0;
|
||||
for (int i = 0; devs[i]; i++) {
|
||||
libusb_device *dev = devs[i];
|
||||
int res = libusb_get_device_descriptor(dev, &desc);
|
||||
if (res < 0) {
|
||||
DEBUG_WARN( "WARN: libusb_get_device_descriptor() failed: %s",
|
||||
libusb_strerror(res));
|
||||
libusb_free_device_list(devs, 1);
|
||||
continue;
|
||||
}
|
||||
libusb_device_handle *handle;
|
||||
res = libusb_open(dev, &handle);
|
||||
if (res != LIBUSB_SUCCESS) {
|
||||
if (!access_problems) {
|
||||
DEBUG_INFO("INFO: Open USB %04x:%04x failed\n",
|
||||
desc.idVendor, desc.idProduct);
|
||||
access_problems = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
res = libusb_get_string_descriptor_ascii(
|
||||
handle, desc.iSerialNumber, (uint8_t*)serial,
|
||||
sizeof(serial));
|
||||
if (res <= 0) {
|
||||
/* This can fail for many devices. Continue silent!*/
|
||||
libusb_close(handle);
|
||||
continue;
|
||||
}
|
||||
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
|
||||
libusb_close(handle);
|
||||
continue;
|
||||
}
|
||||
res = libusb_get_string_descriptor_ascii(
|
||||
handle, desc.iManufacturer, (uint8_t*)manufacturer,
|
||||
sizeof(manufacturer));
|
||||
if (res > 0) {
|
||||
res = libusb_get_string_descriptor_ascii(
|
||||
handle, desc.iProduct, (uint8_t*)product,
|
||||
sizeof(product));
|
||||
if (res <= 0) {
|
||||
DEBUG_WARN( "WARN:"
|
||||
"libusb_get_string_descriptor_ascii "
|
||||
"for ident_string failed: %s\n",
|
||||
libusb_strerror(res));
|
||||
libusb_close(handle);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
libusb_close(handle);
|
||||
if (cl_opts->opt_ident_string) {
|
||||
char *match_manu = NULL;
|
||||
char *match_product = NULL;
|
||||
match_manu = strstr(manufacturer, cl_opts->opt_ident_string);
|
||||
match_product = strstr(product, cl_opts->opt_ident_string);
|
||||
if (!match_manu && !match_product) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Either serial and/or ident_string match or are not given.
|
||||
* Check type.*/
|
||||
if ((desc.idVendor == VENDOR_ID_BMP) &&
|
||||
(desc.idProduct == PRODUCT_ID_BMP)) {
|
||||
type = BMP_TYPE_BMP;
|
||||
} else if (desc.idVendor == VENDOR_ID_STLINK) {
|
||||
if ((desc.idProduct == PRODUCT_ID_STLINKV2) ||
|
||||
(desc.idProduct == PRODUCT_ID_STLINKV21) ||
|
||||
(desc.idProduct == PRODUCT_ID_STLINKV21_MSD) ||
|
||||
(desc.idProduct == PRODUCT_ID_STLINKV3) ||
|
||||
(desc.idProduct == PRODUCT_ID_STLINKV3E)) {
|
||||
type = BMP_TYPE_STLINKV2;
|
||||
} else {
|
||||
if (desc.idProduct == PRODUCT_ID_STLINKV1)
|
||||
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
|
||||
continue;
|
||||
}
|
||||
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
|
||||
type = BMP_TYPE_CMSIS_DAP;
|
||||
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
|
||||
type = BMP_TYPE_JLINK;
|
||||
} else{
|
||||
continue;
|
||||
}
|
||||
found_debuggers ++;
|
||||
if (report) {
|
||||
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers,
|
||||
serial,
|
||||
manufacturer,product);
|
||||
}
|
||||
info->vid = desc.idVendor;
|
||||
info->pid = desc.idProduct;
|
||||
info->bmp_type = type;
|
||||
strncpy(info->serial, serial, sizeof(info->serial));
|
||||
strncpy(info->product, product, sizeof(info->product));
|
||||
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
|
||||
if (cl_opts->opt_position &&
|
||||
(cl_opts->opt_position == found_debuggers)) {
|
||||
found_debuggers = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((found_debuggers > 1) ||
|
||||
((found_debuggers == 1) && (cl_opts->opt_list_only))) {
|
||||
if (!report) {
|
||||
if (found_debuggers > 1)
|
||||
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, "
|
||||
"-s <(partial)serial no.> "
|
||||
"and/or -S <(partial)description>\n",
|
||||
found_debuggers);
|
||||
report = true;
|
||||
goto rescan;
|
||||
} else {
|
||||
found_debuggers = 0;
|
||||
}
|
||||
}
|
||||
if (!found_debuggers && access_problems)
|
||||
DEBUG_WARN(
|
||||
"No debugger found. Please check access rights to USB devices!\n");
|
||||
libusb_free_device_list(devs, 1);
|
||||
return (found_debuggers == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void platform_init(int argc, char **argv)
|
||||
{
|
||||
BMP_CL_OPTIONS_t cl_opts = {0};
|
||||
cl_opts.opt_idstring = "Blackmagic PC-Hosted";
|
||||
cl_init(&cl_opts, argc, argv);
|
||||
atexit(exit_function);
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
signal(SIGINT, sigterm_handler);
|
||||
int res = libusb_init(&info.libusb_ctx);
|
||||
if (res) {
|
||||
DEBUG_WARN( "Fatal: Failed to get USB context: %s\n",
|
||||
libusb_strerror(res));
|
||||
exit(-1);
|
||||
}
|
||||
if (cl_opts.opt_device) {
|
||||
info.bmp_type = BMP_TYPE_BMP;
|
||||
} else if (cl_opts.opt_cable) {
|
||||
/* check for libftdi devices*/
|
||||
res = ftdi_bmp_init(&cl_opts, &info);
|
||||
if (res)
|
||||
exit(-1);
|
||||
else
|
||||
info.bmp_type = BMP_TYPE_LIBFTDI;
|
||||
} else if (find_debuggers(&cl_opts, &info)) {
|
||||
exit(-1);
|
||||
}
|
||||
DEBUG_WARN("Using %04x:%04x %s %s %s\n", info.vid, info.pid, info.serial,
|
||||
info.manufacturer,
|
||||
info.product);
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
if (serial_open(&cl_opts, info.serial))
|
||||
exit(-1);
|
||||
remote_init(true);
|
||||
break;
|
||||
case BMP_TYPE_STLINKV2:
|
||||
if (stlink_init( &info))
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
if (dap_init( &info))
|
||||
exit(-1);
|
||||
break;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
break;
|
||||
case BMP_TYPE_JLINK:
|
||||
if (jlink_init(&info))
|
||||
exit(-1);
|
||||
break;
|
||||
default:
|
||||
exit(-1);
|
||||
}
|
||||
int ret = -1;
|
||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||
ret = cl_execute(&cl_opts);
|
||||
} else {
|
||||
gdb_if_init();
|
||||
return;
|
||||
}
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
int platform_adiv5_swdp_scan(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return adiv5_swdp_scan();
|
||||
break;
|
||||
case BMP_TYPE_STLINKV2:
|
||||
{
|
||||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!stlink_enter_debug_swd(&info, dp)) {
|
||||
adiv5_dp_init(dp);
|
||||
if (target_list)
|
||||
return 1;
|
||||
}
|
||||
free(dp);
|
||||
break;
|
||||
}
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
{
|
||||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!dap_enter_debug_swd(dp)) {
|
||||
adiv5_dp_init(dp);
|
||||
if (target_list)
|
||||
return 1;
|
||||
}
|
||||
free(dp);
|
||||
break;
|
||||
}
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_swdp_scan(&info);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int platform_swdptap_init(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_swdptap_init(&swd_proc);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
case BMP_TYPE_JLINK:
|
||||
return 0;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return libftdi_swdptap_init(&swd_proc);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int platform_jtag_scan(const uint8_t *lrlens)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
case BMP_TYPE_JLINK:
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return jtag_scan(lrlens);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return jtag_scan_stlinkv2(&info, lrlens);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int platform_jtagtap_init(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_jtagtap_init(&jtag_proc);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return 0;
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return libftdi_jtagtap_init(&jtag_proc);
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_jtagtap_init(&info, &jtag_proc);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return cmsis_dap_jtagtap_init(&jtag_proc);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void platform_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_adiv5_dp_defaults(dp);
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_adiv5_dp_defaults(dp);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return dap_adiv5_dp_defaults(dp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int platform_jtag_dp_init(ADIv5_DP_t *dp)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
case BMP_TYPE_JLINK:
|
||||
return 0;
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_jtag_dp_init(dp);
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return dap_jtag_dp_init(dp);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *platform_ident(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_NONE:
|
||||
return "NONE";
|
||||
case BMP_TYPE_BMP:
|
||||
return "BMP";
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return "STLINKV2";
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return "LIBFTDI";
|
||||
case BMP_TYPE_CMSIS_DAP:
|
||||
return "CMSIS_DAP";
|
||||
case BMP_TYPE_JLINK:
|
||||
return "JLINK";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *platform_target_voltage(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_target_voltage();
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_target_voltage(&info);
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return libftdi_target_voltage();
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_target_voltage(&info);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void platform_srst_set_val(bool assert)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_srst_set_val(&info, assert);
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_srst_set_val(assert);
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_srst_set_val(&info, assert);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool platform_srst_get_val(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_BMP:
|
||||
return remote_srst_get_val();
|
||||
case BMP_TYPE_STLINKV2:
|
||||
return stlink_srst_get_val();
|
||||
case BMP_TYPE_JLINK:
|
||||
return jlink_srst_get_val(&info);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void platform_buffer_flush(void)
|
||||
{
|
||||
switch (info.bmp_type) {
|
||||
case BMP_TYPE_LIBFTDI:
|
||||
return libftdi_buffer_flush();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ap_decode_access(uint16_t addr, uint8_t RnW)
|
||||
{
|
||||
if (RnW)
|
||||
fprintf(stderr, "Read ");
|
||||
else
|
||||
fprintf(stderr, "Write ");
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
if (RnW)
|
||||
fprintf(stderr, "DP_DPIDR :");
|
||||
else
|
||||
fprintf(stderr, "DP_ABORT :");
|
||||
break;
|
||||
case 0x004: fprintf(stderr, "CTRL/STAT:");
|
||||
break;
|
||||
case 0x008:
|
||||
if (RnW)
|
||||
fprintf(stderr, "RESEND :");
|
||||
else
|
||||
fprintf(stderr, "DP_SELECT:");
|
||||
break;
|
||||
case 0x00c: fprintf(stderr, "DP_RDBUFF:");
|
||||
break;
|
||||
case 0x100: fprintf(stderr, "AP_CSW :");
|
||||
break;
|
||||
case 0x104: fprintf(stderr, "AP_TAR :");
|
||||
break;
|
||||
case 0x10c: fprintf(stderr, "AP_DRW :");
|
||||
break;
|
||||
case 0x1f8: fprintf(stderr, "AP_BASE :");
|
||||
break;
|
||||
case 0x1fc: fprintf(stderr, "AP_IDR :");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value)
|
||||
{
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
ap_decode_access(addr, ADIV5_LOW_WRITE);
|
||||
fprintf(stderr, " 0x%08" PRIx32 "\n", value);
|
||||
}
|
||||
dp->low_access(dp, ADIV5_LOW_WRITE, addr, value);
|
||||
}
|
||||
|
||||
uint32_t adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
uint32_t ret = dp->dp_read(dp, addr);
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
ap_decode_access(addr, ADIV5_LOW_READ);
|
||||
fprintf(stderr, " 0x%08" PRIx32 "\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t adiv5_dp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
uint32_t ret = dp->error(dp);
|
||||
DEBUG_TARGET( "DP Error 0x%08" PRIx32 "\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t adiv5_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
uint32_t ret = dp->low_access(dp, RnW, addr, value);
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
ap_decode_access(addr, RnW);
|
||||
fprintf(stderr, " 0x%08" PRIx32 "\n", (RnW)? ret : value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
uint32_t ret = ap->dp->ap_read(ap, addr);
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
ap_decode_access(addr, ADIV5_LOW_READ);
|
||||
fprintf(stderr, " 0x%08" PRIx32 "\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
ap_decode_access(addr, ADIV5_LOW_WRITE);
|
||||
fprintf(stderr, " 0x%08" PRIx32 "\n", value);
|
||||
}
|
||||
return ap->dp->ap_write(ap, addr, value);
|
||||
}
|
||||
|
||||
void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
ap->dp->mem_read(ap, dest, src, len);
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
fprintf(stderr, "ap_memread @ %" PRIx32 " len %" PRIx32 ":",
|
||||
src, (uint32_t)len);
|
||||
uint8_t *p = (uint8_t *) dest;
|
||||
unsigned int i = len;
|
||||
if (i > 16)
|
||||
i = 16;
|
||||
while (i--)
|
||||
fprintf(stderr, " %02x", *p++);
|
||||
if (len > 16)
|
||||
fprintf(stderr, " ...");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
void adiv5_mem_write_sized( ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
if (cl_debuglevel & BMP_DEBUG_TARGET) {
|
||||
fprintf(stderr, "ap_mem_write_sized @ %" PRIx32 " len %" PRIx32
|
||||
", align %d:", dest, (uint32_t)len, 1 << align);
|
||||
uint8_t *p = (uint8_t *) src;
|
||||
unsigned int i = len;
|
||||
if (i > 16)
|
||||
i = 16;
|
||||
while (i--)
|
||||
fprintf(stderr, " %02x", *p++);
|
||||
if (len > 16)
|
||||
fprintf(stderr, " ...");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return ap->dp->mem_write_sized(ap, dest, src, len, align);
|
||||
}
|
||||
|
||||
void adiv5_dp_abort(struct ADIv5_DP_s *dp, uint32_t abort)
|
||||
{
|
||||
DEBUG_TARGET("Abort: %08" PRIx32 "\n", abort);
|
||||
return dp->abort(dp, abort);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef __PLATFORM_H
|
||||
#define __PLATFORM_H
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include "libusb_utils.h"
|
||||
#include <libftdi1/ftdi.h>
|
||||
|
||||
#include "timing.h"
|
||||
|
||||
char *platform_ident(void);
|
||||
void platform_buffer_flush(void);
|
||||
|
||||
#define PLATFORM_IDENT() "NONE"
|
||||
#define SET_IDLE_STATE(x)
|
||||
#define SET_RUN_STATE(x)
|
||||
|
||||
typedef enum bmp_type_s {
|
||||
BMP_TYPE_NONE = 0,
|
||||
BMP_TYPE_BMP,
|
||||
BMP_TYPE_STLINKV2,
|
||||
BMP_TYPE_LIBFTDI,
|
||||
BMP_TYPE_CMSIS_DAP,
|
||||
BMP_TYPE_JLINK
|
||||
} bmp_type_t;
|
||||
|
||||
typedef struct bmp_info_s {
|
||||
bmp_type_t bmp_type;
|
||||
libusb_context *libusb_ctx;
|
||||
struct ftdi_context *ftdic;
|
||||
usb_link_t *usb_link;
|
||||
unsigned int vid;
|
||||
unsigned int pid;
|
||||
char dev;
|
||||
char serial[64];
|
||||
char manufacturer[128];
|
||||
char product[128];
|
||||
} bmp_info_t;
|
||||
|
||||
extern bmp_info_t info;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2008 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Modified by Dave Marples <dave@marples.net>
|
||||
* Modified (c) 2020 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Low level JTAG implementation using FT2232 with libftdi.
|
||||
*
|
||||
* Issues:
|
||||
* Should share interface with swdptap.c or at least clean up...
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "remote.h"
|
||||
#include "jtagtap.h"
|
||||
#include "bmp_remote.h"
|
||||
|
||||
static void jtagtap_reset(void);
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks);
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks);
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
|
||||
|
||||
int remote_jtagtap_init(jtag_proc_t *jtag_proc)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
|
||||
REMOTE_JTAG_INIT_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("jtagtap_init failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
jtag_proc->jtagtap_reset = jtagtap_reset;
|
||||
jtag_proc->jtagtap_next =jtagtap_next;
|
||||
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq;
|
||||
jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
|
||||
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See remote.c/.h for protocol information */
|
||||
|
||||
static void jtagtap_reset(void)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
|
||||
REMOTE_JTAG_RESET_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("jtagtap_reset failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_JTAG_TMS_STR, ticks, MS);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("jtagtap_tms_seq failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_tdo_seq(
|
||||
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
uint64_t DIl=*(uint64_t *)DI;
|
||||
|
||||
if(!ticks || !DI) return;
|
||||
|
||||
/* Reduce the length of DI according to the bits we're transmitting */
|
||||
DIl &= (1LL << (ticks + 1))-1;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
|
||||
REMOTE_JTAG_TDIDO_STR,
|
||||
final_tms ? REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS,
|
||||
ticks, DIl);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("jtagtap_tms_seq failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (DO) {
|
||||
uint64_t DOl = remotehston(-1, (char *)&construct[1]);
|
||||
*(uint64_t *)DO = DOl;
|
||||
}
|
||||
}
|
||||
|
||||
static void jtagtap_tdi_seq(
|
||||
const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_JTAG_NEXT,
|
||||
dTMS ? '1' : '0', dTDI ? '1' : '0');
|
||||
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("jtagtap_next failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return remotehston(-1, (char *)&construct[1]);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Modified by Dave Marples <dave@marples.net>
|
||||
* Modification (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
|
||||
* Speed is sensible.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "remote.h"
|
||||
#include "bmp_remote.h"
|
||||
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks);
|
||||
static uint32_t swdptap_seq_in(int ticks);
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks);
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
|
||||
|
||||
int remote_swdptap_init(swd_proc_t *swd_proc)
|
||||
{
|
||||
DEBUG_WIRE("remote_swdptap_init\n");
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
s = sprintf((char *)construct,"%s", REMOTE_SWDP_INIT_STR);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("swdptap_init failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
swd_proc->swdptap_seq_in = swdptap_seq_in;
|
||||
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
|
||||
swd_proc->swdptap_seq_out = swdptap_seq_out;
|
||||
swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = sprintf((char *)construct, REMOTE_SWDP_IN_PAR_STR, ticks);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s<2) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("swdptap_seq_in_parity failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "short response");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
*res=remotehston(-1, (char *)&construct[1]);
|
||||
DEBUG_PROBE("swdptap_seq_in_parity %2d ticks: %08" PRIx32 " %s\n",
|
||||
ticks, *res, (construct[0] != REMOTE_RESP_OK) ? "ERR" : "OK");
|
||||
return (construct[0] != REMOTE_RESP_OK);
|
||||
}
|
||||
|
||||
static uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s = sprintf((char *)construct, REMOTE_SWDP_IN_STR, ticks);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s<2) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("swdptap_seq_in failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "short response");
|
||||
exit(-1);
|
||||
}
|
||||
uint32_t res = remotehston(-1,(char *)&construct[1]);
|
||||
DEBUG_PROBE("swdptap_seq_in %2d ticks: %08" PRIx32 "\n",
|
||||
ticks, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
DEBUG_PROBE("swdptap_seq_out %2d ticks: %08" PRIx32 "\n",
|
||||
ticks, MS);
|
||||
s = sprintf((char *)construct,REMOTE_SWDP_OUT_STR, ticks, MS);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s=platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||
DEBUG_WARN("swdptap_seq_out failed, error %s\n",
|
||||
s ? (char *)&(construct[1]) : "short response");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
DEBUG_PROBE("swdptap_seq_out_parity %2d ticks: %08" PRIx32 "\n",
|
||||
ticks, MS);
|
||||
s = sprintf((char *)construct, REMOTE_SWDP_OUT_PAR_STR, ticks, MS);
|
||||
platform_buffer_write(construct, s);
|
||||
|
||||
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
|
||||
if ((s < 1) || (construct[1] == REMOTE_RESP_ERR)){
|
||||
DEBUG_WARN("swdptap_seq_out_parity failed, error %s\n",
|
||||
s ? (char *)&(construct[2]) : "short response");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__STLINKV2_H_)
|
||||
|
||||
#define STLINK_ERROR_FAIL -1
|
||||
#define STLINK_ERROR_OK 0
|
||||
#define STLINK_ERROR_WAIT 1
|
||||
|
||||
#define STLINK_DEBUG_PORT_ACCESS 0xffff
|
||||
|
||||
int stlink_init(bmp_info_t *info);
|
||||
int stlink_hwversion(void);
|
||||
const char *stlink_target_voltage(bmp_info_t *info);
|
||||
void stlink_srst_set_val(bmp_info_t *info, bool assert);
|
||||
bool stlink_srst_get_val(void);
|
||||
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp);
|
||||
|
||||
const char *stlink_target_voltage(bmp_info_t *info);
|
||||
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||
int stlink_jtag_dp_init(ADIv5_DP_t *dp);
|
||||
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
|
||||
void stlink_exit_function(bmp_info_t *info);
|
||||
#endif
|
|
@ -85,7 +85,7 @@ bool platform_srst_get_val(void) { return false; }
|
|||
|
||||
const char *platform_target_voltage(void)
|
||||
{
|
||||
return "ABSENT!";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void platform_request_boot(void)
|
||||
|
|
|
@ -135,8 +135,6 @@
|
|||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||
#define TRACE_ISR tim3_isr
|
||||
|
||||
#define DEBUG(...)
|
||||
|
||||
#define gpio_set_val(port, pin, val) do { \
|
||||
if(val) \
|
||||
gpio_set((port), (pin)); \
|
||||
|
|
|
@ -115,7 +115,7 @@ void platform_delay(uint32_t ms)
|
|||
|
||||
const char *platform_target_voltage(void)
|
||||
{
|
||||
return "not supported";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *serialno_read(char *s)
|
||||
|
|
|
@ -98,8 +98,6 @@ extern const usbd_driver lm4f_usb_driver;
|
|||
#define vasprintf vasiprintf
|
||||
#define snprintf sniprintf
|
||||
|
||||
#define DEBUG(...)
|
||||
|
||||
#define SET_RUN_STATE(state) {running_status = (state);}
|
||||
#define SET_IDLE_STATE(state) {}
|
||||
#define SET_ERROR_STATE(state) SET_IDLE_STATE(state)
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DENABLE_DEBUG
|
||||
CFLAGS += $(shell pkg-config --cflags libftdi1)
|
||||
LDFLAGS += $(shell pkg-config --libs libftdi1)
|
||||
ifneq (, $(findstring mingw, $(SYS)))
|
||||
LDFLAGS += -lusb-1.0 -lws2_32
|
||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||
LDFLAGS += -lusb-1.0 -lws2_32
|
||||
endif
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c cl_utils.c utils.c
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
|
@ -1,14 +0,0 @@
|
|||
Compiling on windows
|
||||
|
||||
You can crosscompile blackmagic for windows with mingw or on windows
|
||||
with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are
|
||||
needed. For running, libftdi1.dll and libusb-1.0.dll are needed and
|
||||
the executable must be able to find them. Mingw on cygwin does not provide
|
||||
a libftdi package yet.
|
||||
|
||||
To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/.
|
||||
Choose WinUSB(libusb-1.0) for the BMP Ftdi device.
|
||||
|
||||
Running cygwin/blackmagic in a cygwin console, the program does not react
|
||||
on ^C. In another console, run "ps ax" to find the WINPID of the process
|
||||
and then "taskkill /F ?PID (WINPID)".
|
|
@ -30,7 +30,7 @@ SRC += cdcacm.c \
|
|||
|
||||
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
||||
|
||||
blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o
|
||||
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
||||
|
||||
|
|
|
@ -30,10 +30,14 @@
|
|||
|
||||
#define PLATFORM_HAS_TRACESWO
|
||||
#define PLATFORM_HAS_POWER_SWITCH
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
#define PLATFORM_HAS_DEBUG
|
||||
#define USBUART_DEBUG
|
||||
# define PLATFORM_HAS_DEBUG
|
||||
# define USBUART_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
#endif
|
||||
|
||||
#define BOARD_IDENT "Black Magic Probe"
|
||||
#define BOARD_IDENT_DFU "Black Magic Probe (Upgrade)"
|
||||
#define BOARD_IDENT_UPD "Black Magic Probe (DFU Upgrade)"
|
||||
|
@ -165,15 +169,6 @@
|
|||
#define TRACE_IRQ NVIC_TIM3_IRQ
|
||||
#define TRACE_ISR tim3_isr
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
|
||||
#define DEBUG printf
|
||||
#else
|
||||
#define DEBUG(...)
|
||||
#endif
|
||||
|
||||
#define SET_RUN_STATE(state) {running_status = (state);}
|
||||
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
|
||||
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
TARGET=blackmagic_hosted
|
||||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DENABLE_DEBUG
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
ifneq (, $(findstring mingw, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||
SRC += serial_win.c
|
||||
LDFLAGS += -lws2_32
|
||||
else
|
||||
SRC += serial_unix.c
|
||||
endif
|
||||
VPATH += platforms/pc
|
||||
SRC += cl_utils.c timing.c utils.c
|
|
@ -1,40 +0,0 @@
|
|||
PC Hosted variant
|
||||
|
||||
THIS IS INCOMPLETE - ONLY SUPPORTS SWD AT THE MOMENT
|
||||
|
||||
This variant will use any BMP probe with recent firmware as a remote
|
||||
actuator, with the actual probe code running on the PC. The BMP itself
|
||||
is 'dumb' and doesn't do anything (although any secondary serial port
|
||||
remains available).
|
||||
|
||||
To use it, compile for the pc-hosted target and then connect to your normal
|
||||
BMP GDB port;
|
||||
|
||||
src/blackmagic -s /dev/ttyACM0
|
||||
|
||||
...you can then connect your gdb session to localhost:2000 for all your
|
||||
debugging goodness;
|
||||
|
||||
$arm-eabi-none-gdb
|
||||
(gdb) monitor swdp_scan
|
||||
Target voltage: not supported
|
||||
Available Targets:
|
||||
No. Att Driver
|
||||
1 STM32F1 medium density M3/M4
|
||||
(gdb) attach 1
|
||||
Attaching to program: Builds/blackmagic/src/blackmagic, Remote target
|
||||
0x08001978 in ?? ()
|
||||
(gdb) file src/blackmagic
|
||||
A program is being debugged already.
|
||||
Are you sure you want to change the file? (y or n) y
|
||||
Load new symbol table from "src/blackmagic"? (y or n) y
|
||||
Reading symbols from src/blackmagic...
|
||||
(gdb) load
|
||||
Loading section .text, size 0x1201c lma 0x8002000
|
||||
Loading section .data, size 0xd8 lma 0x801401c
|
||||
Start address 0x800d9fc, load size 73972
|
||||
Transfer rate: 2 KB/sec, 960 bytes/write.
|
||||
(gdb)
|
||||
|
||||
...note that the speed of the probe in this way is about 10 times less than
|
||||
running native. This build is intended for debug and development only.
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2008 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Modified by Dave Marples <dave@marples.net>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Low level JTAG implementation using FT2232 with libftdi.
|
||||
*
|
||||
* Issues:
|
||||
* Should share interface with swdptap.c or at least clean up...
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "remote.h"
|
||||
#include "jtagtap.h"
|
||||
|
||||
/* See remote.c/.h for protocol information */
|
||||
|
||||
int jtagtap_init(void)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_INIT_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"jtagtap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jtagtap_reset(void)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_RESET_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"jtagtap_reset failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void jtagtap_tms_seq(uint32_t MS, int ticks)
|
||||
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TMS_STR,ticks,MS);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
uint64_t DIl=*(uint64_t *)DI;
|
||||
|
||||
if(!ticks || !DI) return;
|
||||
|
||||
/* Reduce the length of DI according to the bits we're transmitting */
|
||||
DIl &= (1LL << (ticks + 1)) - 1;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TDIDO_STR,final_tms?REMOTE_TDITDO_TMS:REMOTE_TDITDO_NOTMS,ticks,DIl);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (DO) {
|
||||
uint64_t DOl = remotehston(-1, (char *)&construct[1]);
|
||||
*(uint64_t *)DO = DOl;
|
||||
}
|
||||
}
|
||||
|
||||
void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
|
||||
|
||||
{
|
||||
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
|
||||
}
|
||||
|
||||
|
||||
uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
|
||||
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_NEXT,dTMS?'1':'0',dTDI?'1':'0');
|
||||
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"jtagtap_next failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return remotehston(-1,(char *)&construct[1]);
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Additions by Dave Marples <dave@marples.net>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "platform.h"
|
||||
#include "remote.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cl_utils.h"
|
||||
static BMP_CL_OPTIONS_t cl_opts; /* Portable way to nullify the struct*/
|
||||
|
||||
void platform_init(int argc, char **argv)
|
||||
{
|
||||
cl_opts.opt_idstring = "Blackmagic Debug Probe Remote";
|
||||
cl_init(&cl_opts, argc, argv);
|
||||
char construct[PLATFORM_MAX_MSG_SIZE];
|
||||
|
||||
printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n");
|
||||
printf("Copyright (C) 2019 Black Sphere Technologies Ltd.\n");
|
||||
printf("License GPLv3+: GNU GPL version 3 or later "
|
||||
"<http://gnu.org/licenses/gpl.html>\n\n");
|
||||
|
||||
if (serial_open(&cl_opts))
|
||||
exit(-1);
|
||||
int c=snprintf(construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_START_STR);
|
||||
platform_buffer_write((uint8_t *)construct,c);
|
||||
c=platform_buffer_read((uint8_t *)construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!c) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"Remote Start failed, error %s\n",c?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Remote is %s\n",&construct[1]);
|
||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||
int ret = cl_execute(&cl_opts);
|
||||
if (cl_opts.opt_tpwr)
|
||||
platform_target_set_power(0);
|
||||
serial_close();
|
||||
exit(ret);
|
||||
} else {
|
||||
assert(gdb_if_init() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool platform_target_get_power(void)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_PWR_GET_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"platform_target_get_power failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return (construct[1]=='1');
|
||||
}
|
||||
|
||||
void platform_target_set_power(bool power)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_PWR_SET_STR,power?'1':'0');
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"platform_target_set_power failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void platform_srst_set_val(bool assert)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_SRST_SET_STR,assert?'1':'0');
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
bool platform_srst_get_val(void)
|
||||
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_SRST_GET_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return (construct[1]=='1');
|
||||
}
|
||||
|
||||
void platform_buffer_flush(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char *platform_target_voltage(void)
|
||||
|
||||
{
|
||||
static uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_VOLTAGE_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"platform_target_voltage failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return (char *)&construct[1];
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Additions by Dave Marples <dave@marples.net>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PLATFORM_H
|
||||
#define __PLATFORM_H
|
||||
|
||||
#include "timing.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <alloca.h>
|
||||
#else
|
||||
# ifndef alloca
|
||||
# define alloca __builtin_alloca
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PLATFORM_HAS_DEBUG
|
||||
#define PLATFORM_HAS_POWER_SWITCH
|
||||
#define PLATFORM_MAX_MSG_SIZE (256)
|
||||
#define PLATFORM_IDENT "PC-HOSTED"
|
||||
#define BOARD_IDENT PLATFORM_IDENT
|
||||
#define SET_RUN_STATE(state)
|
||||
#define SET_IDLE_STATE(state)
|
||||
#define SET_ERROR_STATE(state)
|
||||
|
||||
/* Allow 100mS for responses to reach us */
|
||||
#define RESP_TIMEOUT (100)
|
||||
|
||||
void platform_buffer_flush(void);
|
||||
int platform_buffer_write(const uint8_t *data, int size);
|
||||
int platform_buffer_read(uint8_t *data, int size);
|
||||
static inline int platform_hwversion(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Modified by Dave Marples <dave@marples.net>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
|
||||
* Speed is sensible.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "swdptap.h"
|
||||
#include "remote.h"
|
||||
|
||||
int swdptap_init(void)
|
||||
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=sprintf((char *)construct,"%s",REMOTE_SWDP_INIT_STR);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"swdptap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
|
||||
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=sprintf((char *)construct,REMOTE_SWDP_IN_PAR_STR,ticks);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((s<2) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"swdptap_seq_in_parity failed, error %s\n",s?(char *)&(construct[1]):"short response");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
*res=remotehston(-1,(char *)&construct[1]);
|
||||
return (construct[0]!=REMOTE_RESP_OK);
|
||||
}
|
||||
|
||||
|
||||
uint32_t swdptap_seq_in(int ticks)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=sprintf((char *)construct,REMOTE_SWDP_IN_STR,ticks);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((s<2) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"swdptap_seq_in failed, error %s\n",s?(char *)&(construct[1]):"short response");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return remotehston(-1,(char *)&construct[1]);
|
||||
}
|
||||
|
||||
void swdptap_seq_out(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=sprintf((char *)construct,REMOTE_SWDP_OUT_STR,ticks,MS);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((s<1) || (construct[0]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"swdptap_seq_out failed, error %s\n",s?(char *)&(construct[1]):"short response");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void swdptap_seq_out_parity(uint32_t MS, int ticks)
|
||||
{
|
||||
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
|
||||
int s;
|
||||
|
||||
s=sprintf((char *)construct,REMOTE_SWDP_OUT_PAR_STR,ticks,MS);
|
||||
platform_buffer_write(construct,s);
|
||||
|
||||
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
|
||||
if ((s<1) || (construct[1]==REMOTE_RESP_ERR))
|
||||
{
|
||||
fprintf(stderr,"swdptap_seq_out_parity failed, error %s\n",s?(char *)&(construct[2]):"short response");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
TARGET=blackmagic_stlinkv2
|
||||
SYS = $(shell $(CC) -dumpmachine)
|
||||
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG
|
||||
CFLAGS +=-I ./target -I./platforms/pc
|
||||
LDFLAGS += -lusb-1.0
|
||||
ifneq (, $(findstring mingw, $(SYS)))
|
||||
LDFLAGS += -lws2_32
|
||||
else ifneq (, $(findstring cygwin, $(SYS)))
|
||||
LDFLAGS += -lws2_32
|
||||
endif
|
||||
VPATH += platforms/pc
|
||||
SRC += timing.c stlinkv2.c cl_utils.c utils.c
|
||||
OWN_HL = 1
|
|
@ -1,25 +0,0 @@
|
|||
ST-Link V2/3 with original STM firmware as Blackmagic Debug Probes
|
||||
|
||||
Recent STM ST-LINK firmware revision (V3 and V2 >= J32) expose all
|
||||
functionality that BMP needs. This platform implements blackmagic debug
|
||||
probe for the STM ST-LINK.
|
||||
Use at your own risk, but report or better fix problems.
|
||||
|
||||
Compile with "make PROBE_HOST=pc-stlinkv2"
|
||||
|
||||
Run the resulting blackmagic_stlinkv2 executable to start the gdb server.
|
||||
|
||||
You can also use on the command line alone, e.g
|
||||
- "blackmagic_stlinkv2 -t" to scan and display the results of the scan
|
||||
- "blackmagic_stlinkv2 <file.bin>" to flash <file.bin> at 0x08000000
|
||||
- "blackmagic_stlinkv2 -h" for more options
|
||||
|
||||
Cross-compling for windows with mingw succeeds.
|
||||
|
||||
Drawback:
|
||||
- JTAG does not work for chains with multiple devices.
|
||||
- ST-LINKV3 seem to only work on STM32 devices.
|
||||
- St-LINKV3 needs connect under reset on more devices than V2
|
||||
|
||||
ToDo:
|
||||
- Implement an SWO server
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file implements a subset of JTAG-DP specific functions of the
|
||||
* ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A
|
||||
* used in BMP.
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "adiv5.h"
|
||||
#include "stlinkv2.h"
|
||||
#include "jtag_devs.h"
|
||||
|
||||
struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1];
|
||||
int jtag_dev_count;
|
||||
|
||||
int jtag_scan(const uint8_t *irlens)
|
||||
{
|
||||
uint32_t idcodes[JTAG_MAX_DEVS+1];
|
||||
(void) *irlens;
|
||||
target_list_free();
|
||||
|
||||
jtag_dev_count = 0;
|
||||
memset(&jtag_devs, 0, sizeof(jtag_devs));
|
||||
if (stlink_enter_debug_jtag())
|
||||
return 0;
|
||||
jtag_dev_count = stlink_read_idcodes(idcodes);
|
||||
/* Check for known devices and handle accordingly */
|
||||
for(int i = 0; i < jtag_dev_count; i++)
|
||||
jtag_devs[i].idcode = idcodes[i];
|
||||
for(int i = 0; i < jtag_dev_count; i++)
|
||||
for(int j = 0; dev_descr[j].idcode; j++)
|
||||
if((jtag_devs[i].idcode & dev_descr[j].idmask) ==
|
||||
dev_descr[j].idcode) {
|
||||
if(dev_descr[j].handler)
|
||||
dev_descr[j].handler(&jtag_devs[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
return jtag_dev_count;
|
||||
}
|
||||
|
||||
void adiv5_jtag_dp_handler(jtag_dev_t *dev)
|
||||
{
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
|
||||
dp->dev = dev;
|
||||
dp->idcode = dev->idcode;
|
||||
|
||||
dp->dp_read = stlink_dp_read;
|
||||
dp->error = stlink_dp_error;
|
||||
dp->low_access = stlink_dp_low_access;
|
||||
dp->abort = stlink_dp_abort;
|
||||
|
||||
adiv5_dp_init(dp);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Copyright (C) 2019 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file implements the SW-DP specific functions of the
|
||||
* ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A.
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "target.h"
|
||||
#include "target_internal.h"
|
||||
#include "adiv5.h"
|
||||
#include "stlinkv2.h"
|
||||
|
||||
int adiv5_swdp_scan(void)
|
||||
{
|
||||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (stlink_enter_debug_swd())
|
||||
return 0;
|
||||
dp->idcode = stlink_read_coreid();
|
||||
dp->dp_read = stlink_dp_read;
|
||||
dp->error = stlink_dp_error;
|
||||
dp->low_access = stlink_dp_low_access;
|
||||
dp->abort = stlink_dp_abort;
|
||||
|
||||
stlink_dp_error(dp);
|
||||
adiv5_dp_init(dp);
|
||||
|
||||
return target_list?1:0;
|
||||
return 0;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 2019 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "general.h"
|
||||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "adiv5.h"
|
||||
#include "stlinkv2.h"
|
||||
|
||||
int platform_hwversion(void)
|
||||
{
|
||||
return stlink_hwversion();
|
||||
}
|
||||
|
||||
const char *platform_target_voltage(void)
|
||||
{
|
||||
return stlink_target_voltage();
|
||||
}
|
||||
|
||||
void platform_init(int argc, char **argv)
|
||||
{
|
||||
stlink_init(argc, argv);
|
||||
}
|
||||
|
||||
static bool srst_status = false;
|
||||
void platform_srst_set_val(bool assert)
|
||||
{
|
||||
stlink_srst_set_val(assert);
|
||||
srst_status = assert;
|
||||
}
|
||||
|
||||
bool platform_srst_get_val(void) { return srst_status; }
|
||||
|
||||
void platform_buffer_flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
int platform_buffer_write(const uint8_t *data, int size)
|
||||
{
|
||||
(void) data;
|
||||
(void) size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int platform_buffer_read(uint8_t *data, int size)
|
||||
{
|
||||
(void) data;
|
||||
return size;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PLATFORM_H
|
||||
#define __PLATFORM_H
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#include "timing.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <alloca.h>
|
||||
#else
|
||||
# ifndef alloca
|
||||
# define alloca __builtin_alloca
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PLATFORM_HAS_DEBUG
|
||||
|
||||
#define PLATFORM_IDENT "StlinkV2/3"
|
||||
#define SET_RUN_STATE(state)
|
||||
void stlink_check_detach(int state);
|
||||
#define SET_IDLE_STATE(state) stlink_check_detach(state)
|
||||
//#define SET_ERROR_STATE(state)
|
||||
|
||||
void platform_buffer_flush(void);
|
||||
int platform_buffer_write(const uint8_t *data, int size);
|
||||
int platform_buffer_read(uint8_t *data, int size);
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__STLINKV2_H_)
|
||||
|
||||
#define STLINK_ERROR_FAIL -1
|
||||
#define STLINK_ERROR_OK 0
|
||||
#define STLINK_ERROR_WAIT 1
|
||||
|
||||
#define STLINK_DEBUG_PORT_ACCESS 0xffff
|
||||
|
||||
void stlink_init(int argc, char **argv);
|
||||
int stlink_hwversion(void);
|
||||
void stlink_leave_state(void);
|
||||
const char *stlink_target_voltage(void);
|
||||
void stlink_srst_set_val(bool assert);
|
||||
int stlink_enter_debug_swd(void);
|
||||
int stlink_enter_debug_jtag(void);
|
||||
int stlink_read_idcodes(uint32_t *);
|
||||
uint32_t stlink_read_coreid(void);
|
||||
int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *res);
|
||||
int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val);
|
||||
|
||||
uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
uint32_t stlink_dp_error(ADIv5_DP_t *dp);
|
||||
void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort);
|
||||
int stlink_open_ap(uint8_t ap);
|
||||
void stlink_close_ap(uint8_t ap);
|
||||
void stlink_regs_read(ADIv5_AP_t *ap, void *data);
|
||||
uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx);
|
||||
void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val);
|
||||
extern int debug_level;
|
||||
# define DEBUG_STLINK if (debug_level > 0) printf
|
||||
# define DEBUG_USB if (debug_level > 1) printf
|
||||
#endif
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019
|
||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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
|
||||
|
@ -63,7 +63,7 @@ static int bmp_mmap(char *file, struct mmap_data *map)
|
|||
map->hFile = CreateFile(file, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_ALWAYS, 0, NULL);
|
||||
if (map->hFile == INVALID_HANDLE_VALUE) {
|
||||
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
|
||||
DEBUG_WARN("Open file %s failed: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
map->size = GetFileSize(map->hFile, NULL);
|
||||
|
@ -76,13 +76,13 @@ static int bmp_mmap(char *file, struct mmap_data *map)
|
|||
NULL); /* name of mapping object */
|
||||
|
||||
if (map->hMapFile == NULL || map->hMapFile == INVALID_HANDLE_VALUE) {
|
||||
DEBUG("Map file %s failed: %s\n", file, strerror(errno));
|
||||
DEBUG_WARN("Map file %s failed: %s\n", file, strerror(errno));
|
||||
CloseHandle(map->hFile);
|
||||
return -1;
|
||||
}
|
||||
map->data = MapViewOfFile(map->hMapFile, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!map->data) {
|
||||
printf("Could not create file mapping object (%s).\n",
|
||||
DEBUG_WARN("Could not create file mapping object (%s).\n",
|
||||
strerror(errno));
|
||||
CloseHandle(map->hMapFile);
|
||||
return -1;
|
||||
|
@ -90,7 +90,7 @@ static int bmp_mmap(char *file, struct mmap_data *map)
|
|||
#else
|
||||
map->fd = open(file, O_RDONLY | O_BINARY);
|
||||
if (map->fd < 0) {
|
||||
DEBUG("Open file %s failed: %s\n", file, strerror(errno));
|
||||
DEBUG_WARN("Open file %s failed: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct stat stat;
|
||||
|
@ -115,31 +115,37 @@ static void bmp_munmap(struct mmap_data *map)
|
|||
|
||||
static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
|
||||
{
|
||||
printf("%s\n\n", opt->opt_idstring);
|
||||
printf("Usage: %s [options]\n", argv[0]);
|
||||
printf("\t-h\t\t: This help.\n");
|
||||
printf("\t-v[1|2]\t\t: Increasing verbosity\n");
|
||||
printf("\t-d \"path\"\t: Use serial device at \"path\"\n");
|
||||
printf("\t-s \"string\"\t: Use dongle with (partial) "
|
||||
"serial number \"string\"\n");
|
||||
printf("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
|
||||
printf("\t-C\t\t: Connect under reset\n");
|
||||
printf("\t-n\t\t: Exit immediate if no device found\n");
|
||||
printf("\tRun mode related options:\n");
|
||||
printf("\t-t\t\t: Scan SWD, with no target found scan jtag and exit\n");
|
||||
printf("\t-E\t\t: Erase flash until flash end or for given size\n");
|
||||
printf("\t-V\t\t: Verify flash against binary file\n");
|
||||
printf("\t-r\t\t: Read flash and write to binary file\n");
|
||||
printf("\t-p\t\t: Supplies power to the target (where applicable)\n");
|
||||
printf("\t-R\t\t: Reset device\n");
|
||||
printf("\t\tDefault mode is starting the debug server\n");
|
||||
printf("\tFlash operation modifiers options:\n");
|
||||
printf("\t-a <num>\t: Start flash operation at flash address <num>\n"
|
||||
"\t\t\tDefault start is 0x08000000\n");
|
||||
printf("\t-S <num>\t: Read <num> bytes. Default is until read fails.\n");
|
||||
printf("\t-j\t\t: Use JTAG. SWD is default.\n");
|
||||
printf("\t <file>\t\t: Use (binary) file <file> for flash operation\n"
|
||||
"\t\t\tGiven <file> writes to flash if neither -r or -V is given\n");
|
||||
DEBUG_WARN("%s for: \n", opt->opt_idstring);
|
||||
DEBUG_WARN("\tBMP Firmware, ST-Link V2/3, CMSIS_DAP, JLINK and "
|
||||
"LIBFTDI/MPSSE\n\n");
|
||||
DEBUG_WARN("Usage: %s [options]\n", argv[0]);
|
||||
DEBUG_WARN("\t-h\t\t: This help.\n");
|
||||
DEBUG_WARN("\t-v[bitmask]\t: Increasing verbosity. Bitmask:\n");
|
||||
DEBUG_WARN("\t\t\t 1 = INFO, 2 = GDB, 4 = TARGET, 8 = PROBE, 16 = WIRE\n");
|
||||
DEBUG_WARN("Probe selection arguments:\n");
|
||||
DEBUG_WARN("\t-d \"path\"\t: Use serial device at \"path\"\n");
|
||||
DEBUG_WARN("\t-P <pos>\t: Use debugger found at position <pos>\n");
|
||||
DEBUG_WARN("\t-n <num>\t: Use target device found at position <num>\n");
|
||||
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
|
||||
"serial number \"serial\"\n");
|
||||
DEBUG_WARN("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
|
||||
DEBUG_WARN("Run mode related options:\n");
|
||||
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
|
||||
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
|
||||
DEBUG_WARN("\t-C\t\t: Connect under reset\n");
|
||||
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
|
||||
"\t\t\t connected devices\n");
|
||||
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
|
||||
DEBUG_WARN("\t-V\t\t: Verify flash against binary file\n");
|
||||
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
|
||||
DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\n");
|
||||
DEBUG_WARN("\t-R\t\t: Reset device\n");
|
||||
DEBUG_WARN("Flash operation modifiers options:\n");
|
||||
DEBUG_WARN("\tDefault action with given file is to write to flash\n");
|
||||
DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n"
|
||||
"\t\t\t Default start is start of flash in memory map\n");
|
||||
DEBUG_WARN("\t-S <num>\t: Read <num> bytes. Default is until read fails.\n");
|
||||
DEBUG_WARN("\t <file>\t\t: Use (binary) file <file> for flash operation\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -147,9 +153,8 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
{
|
||||
int c;
|
||||
opt->opt_target_dev = 1;
|
||||
opt->opt_flash_start = 0x08000000;
|
||||
opt->opt_flash_size = 16 * 1024 *1024;
|
||||
while((c = getopt(argc, argv, "Ehv::d:s:c:CnN:tVta:S:jprR")) != -1) {
|
||||
while((c = getopt(argc, argv, "Ehv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
if (optarg)
|
||||
|
@ -160,19 +165,18 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
break;
|
||||
case 'v':
|
||||
if (optarg)
|
||||
cl_debuglevel = strtol(optarg, NULL, 0);
|
||||
else
|
||||
cl_debuglevel = -1;
|
||||
cl_debuglevel = strtol(optarg, NULL, 0) & (BMP_DEBUG_MAX - 1);
|
||||
break;
|
||||
case 'j':
|
||||
opt->opt_usejtag = true;
|
||||
break;
|
||||
case 'l':
|
||||
opt->opt_list_only = true;
|
||||
cl_debuglevel |= BMP_DEBUG_STDOUT;
|
||||
break;
|
||||
case 'C':
|
||||
opt->opt_connect_under_reset = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt->opt_no_wait = true;
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg)
|
||||
opt->opt_device = optarg;
|
||||
|
@ -181,11 +185,16 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
if (optarg)
|
||||
opt->opt_serial = optarg;
|
||||
break;
|
||||
case 'I':
|
||||
if (optarg)
|
||||
opt->opt_ident_string = optarg;
|
||||
break;
|
||||
case 'E':
|
||||
opt->opt_mode = BMP_MODE_FLASH_ERASE;
|
||||
break;
|
||||
case 't':
|
||||
opt->opt_mode = BMP_MODE_TEST;
|
||||
cl_debuglevel |= BMP_DEBUG_INFO | BMP_DEBUG_STDOUT;
|
||||
break;
|
||||
case 'V':
|
||||
opt->opt_mode = BMP_MODE_FLASH_VERIFY;
|
||||
|
@ -203,10 +212,14 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
if (optarg)
|
||||
opt->opt_flash_start = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'N':
|
||||
case 'n':
|
||||
if (optarg)
|
||||
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'P':
|
||||
if (optarg)
|
||||
opt->opt_position = atoi(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
if (optarg) {
|
||||
char *endptr;
|
||||
|
@ -234,7 +247,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
/* Checks */
|
||||
if ((opt->opt_flash_file) && ((opt->opt_mode == BMP_MODE_TEST ) ||
|
||||
(opt->opt_mode == BMP_MODE_RESET))) {
|
||||
printf("Ignoring filename in reset/test mode\n");
|
||||
DEBUG_WARN("Ignoring filename in reset/test mode\n");
|
||||
opt->opt_flash_file = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +255,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||
static void display_target(int i, target *t, void *context)
|
||||
{
|
||||
(void)context;
|
||||
DEBUG("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
||||
DEBUG_INFO("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ',
|
||||
target_driver_name(t),
|
||||
(target_core_name(t)) ? target_core_name(t): "");
|
||||
}
|
||||
|
@ -253,55 +266,102 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||
int num_targets;
|
||||
#if defined(PLATFORM_HAS_POWER_SWITCH)
|
||||
if (opt->opt_tpwr) {
|
||||
printf("Powering up device");
|
||||
DEBUG_INFO("Powering up device");
|
||||
platform_target_set_power(true);
|
||||
platform_delay(500);
|
||||
}
|
||||
#endif
|
||||
if (opt->opt_connect_under_reset)
|
||||
printf("Connecting under reset\n");
|
||||
DEBUG_INFO("Connecting under reset\n");
|
||||
connect_assert_srst = opt->opt_connect_under_reset;
|
||||
platform_srst_set_val(opt->opt_connect_under_reset);
|
||||
if (opt->opt_mode == BMP_MODE_TEST)
|
||||
printf("Running in Test Mode\n");
|
||||
printf("Target voltage: %s Volt\n", platform_target_voltage());
|
||||
DEBUG_INFO("Running in Test Mode\n");
|
||||
if (platform_target_voltage())
|
||||
DEBUG_INFO("Target voltage: %s Volt\n", platform_target_voltage());
|
||||
if (opt->opt_usejtag) {
|
||||
num_targets = jtag_scan(NULL);
|
||||
num_targets = platform_jtag_scan(NULL);
|
||||
} else {
|
||||
num_targets = adiv5_swdp_scan();
|
||||
num_targets = platform_adiv5_swdp_scan();
|
||||
}
|
||||
if (!num_targets) {
|
||||
DEBUG("No target found\n");
|
||||
DEBUG_WARN("No target found\n");
|
||||
return res;
|
||||
} else {
|
||||
target_foreach(display_target, NULL);
|
||||
}
|
||||
if (opt->opt_mode == BMP_MODE_TEST)
|
||||
return 0;
|
||||
if (opt->opt_target_dev > num_targets) {
|
||||
DEBUG("Given target nummer %d not available\n", opt->opt_target_dev);
|
||||
DEBUG_WARN("Given target nummer %d not available\n",
|
||||
opt->opt_target_dev);
|
||||
return res;
|
||||
}
|
||||
target *t = target_attach_n(opt->opt_target_dev, NULL);
|
||||
if (!t) {
|
||||
DEBUG("Can not attach to target %d\n", opt->opt_target_dev);
|
||||
DEBUG_WARN("Can not attach to target %d\n", opt->opt_target_dev);
|
||||
goto target_detach;
|
||||
}
|
||||
/* Always scan memory map to find lowest flash */
|
||||
char memory_map [1024], *p = memory_map;
|
||||
uint32_t flash_start = 0xffffffff;
|
||||
if (target_mem_map(t, memory_map, sizeof(memory_map))) {
|
||||
while (*p && (*p == '<')) {
|
||||
unsigned int start, size;
|
||||
char *res;
|
||||
int match;
|
||||
match = strncmp(p, "<memory-map>", strlen("<memory-map>"));
|
||||
if (!match) {
|
||||
p += strlen("<memory-map>");
|
||||
continue;
|
||||
}
|
||||
match = strncmp(p, "<memory type=\"flash\" ", strlen("<memory type=\"flash\" "));
|
||||
if (!match) {
|
||||
unsigned int blocksize;
|
||||
if (sscanf(p, "<memory type=\"flash\" start=\"%x\" length=\"%x\">"
|
||||
"<property name=\"blocksize\">%x</property></memory>",
|
||||
&start, &size, &blocksize)) {
|
||||
if (opt->opt_mode == BMP_MODE_TEST)
|
||||
DEBUG_INFO("Flash Start: 0x%08x, length %#9x, "
|
||||
"blocksize %#8x\n", start, size, blocksize);
|
||||
if (start < flash_start)
|
||||
flash_start = start;
|
||||
}
|
||||
res = strstr(p, "</memory>");
|
||||
p = res + strlen("</memory>");
|
||||
continue;
|
||||
}
|
||||
match = strncmp(p, "<memory type=\"ram\" ", strlen("<memory type=\"ram\" "));
|
||||
if (!match) {
|
||||
if (sscanf(p, "<memory type=\"ram\" start=\"%x\" length=\"%x\"/",
|
||||
&start, &size))
|
||||
if (opt->opt_mode == BMP_MODE_TEST)
|
||||
DEBUG_INFO("Ram Start: 0x%08x, length %#9x\n",
|
||||
start, size);
|
||||
res = strstr(p, "/>");
|
||||
p = res + strlen("/>");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (opt->opt_flash_start < flash_start)
|
||||
opt->opt_flash_start = flash_start;
|
||||
if (opt->opt_mode == BMP_MODE_TEST)
|
||||
goto target_detach;
|
||||
int read_file = -1;
|
||||
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
|
||||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY)) {
|
||||
int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
|
||||
if (mmap_res) {
|
||||
DEBUG("Can not map file: %s. Aborting!\n", strerror(errno));
|
||||
DEBUG_WARN("Can not map file: %s. Aborting!\n", strerror(errno));
|
||||
goto target_detach;
|
||||
}
|
||||
} else if (opt->opt_mode == BMP_MODE_FLASH_READ) {
|
||||
/* Open as binary */
|
||||
read_file = open(opt->opt_flash_file, O_CREAT | O_RDWR | O_BINARY,
|
||||
read_file = open(opt->opt_flash_file, O_TRUNC | O_CREAT | O_RDWR | O_BINARY,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (read_file == -1) {
|
||||
printf("Error opening flashfile %s for read: %s\n",
|
||||
opt->opt_flash_file, strerror(errno));
|
||||
DEBUG_WARN("Error opening flashfile %s for read: %s\n",
|
||||
opt->opt_flash_file, strerror(errno));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -311,47 +371,52 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||
if (opt->opt_mode == BMP_MODE_RESET) {
|
||||
target_reset(t);
|
||||
} else if (opt->opt_mode == BMP_MODE_FLASH_ERASE) {
|
||||
DEBUG("Erase %zu bytes at 0x%08" PRIx32 "\n", opt->opt_flash_size,
|
||||
DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", opt->opt_flash_size,
|
||||
opt->opt_flash_start);
|
||||
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
||||
opt->opt_flash_size);
|
||||
if (erased) {
|
||||
DEBUG("Erased failed!\n");
|
||||
DEBUG_WARN("Erased failed!\n");
|
||||
goto free_map;
|
||||
}
|
||||
target_reset(t);
|
||||
} else if (opt->opt_mode == BMP_MODE_FLASH_WRITE) {
|
||||
DEBUG("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
|
||||
DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
|
||||
opt->opt_flash_start);
|
||||
uint32_t start_time = platform_time_ms();
|
||||
unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
|
||||
map.size);
|
||||
if (erased) {
|
||||
DEBUG("Erased failed!\n");
|
||||
DEBUG_WARN("Erased failed!\n");
|
||||
goto free_map;
|
||||
} else {
|
||||
DEBUG("Flashing %zu bytes at 0x%08" PRIx32 "\n",
|
||||
DEBUG_INFO("Flashing %zu bytes at 0x%08" PRIx32 "\n",
|
||||
map.size, opt->opt_flash_start);
|
||||
unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
|
||||
map.data, map.size);
|
||||
/* Buffered write cares for padding*/
|
||||
if (flashed) {
|
||||
DEBUG("Flashing failed!\n");
|
||||
DEBUG_WARN("Flashing failed!\n");
|
||||
} else {
|
||||
DEBUG("Success!\n");
|
||||
DEBUG_INFO("Success!\n");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
target_flash_done(t);
|
||||
target_reset(t);
|
||||
uint32_t end_time = platform_time_ms();
|
||||
DEBUG_WARN("Flash Write succeeded for %d bytes, %8.3f kiB/s\n",
|
||||
(int)map.size, (((map.size * 1.0)/(end_time - start_time))));
|
||||
} else {
|
||||
#define WORKSIZE 1024
|
||||
uint8_t *data = malloc(WORKSIZE);
|
||||
uint8_t *data = alloca(WORKSIZE);
|
||||
if (!data) {
|
||||
printf("Can not malloc memory for flash read/verify operation\n");
|
||||
DEBUG_WARN("Can not malloc memory for flash read/verify "
|
||||
"operation\n");
|
||||
return res;
|
||||
}
|
||||
if (opt->opt_mode == BMP_MODE_FLASH_READ)
|
||||
printf("Reading flash from 0x%08" PRIx32 " for %zu"
|
||||
DEBUG_INFO("Reading flash from 0x%08" PRIx32 " for %zu"
|
||||
" bytes to %s\n", opt->opt_flash_start, opt->opt_flash_size,
|
||||
opt->opt_flash_file);
|
||||
uint32_t flash_src = opt->opt_flash_start;
|
||||
|
@ -359,16 +424,17 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||
map.size;
|
||||
int bytes_read = 0;
|
||||
void *flash = map.data;
|
||||
uint32_t start_time = platform_time_ms();
|
||||
while (size) {
|
||||
int worksize = (size > WORKSIZE) ? WORKSIZE : size;
|
||||
int n_read = target_mem_read(t, data, flash_src, worksize);
|
||||
if (n_read) {
|
||||
if (opt->opt_flash_size == 0) {/* we reached end of flash */
|
||||
printf("Reached end of flash at size %" PRId32 "\n",
|
||||
DEBUG_INFO("Reached end of flash at size %" PRId32 "\n",
|
||||
flash_src - opt->opt_flash_start);
|
||||
break;
|
||||
} else {
|
||||
printf("Read failed at flash address 0x%08" PRIx32 "\n",
|
||||
DEBUG_WARN("Read failed at flash address 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
break;
|
||||
}
|
||||
|
@ -378,15 +444,15 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY) {
|
||||
int difference = memcmp(data, flash, worksize);
|
||||
if (difference){
|
||||
printf("Verify failed at flash region 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
DEBUG_WARN("Verify failed at flash region 0x%08"
|
||||
PRIx32 "\n", flash_src);
|
||||
return -1;
|
||||
}
|
||||
flash += worksize;
|
||||
} else if (read_file != -1) {
|
||||
int written = write(read_file, data, worksize);
|
||||
if (written < worksize) {
|
||||
printf("Read failed at flash region 0x%08" PRIx32 "\n",
|
||||
DEBUG_WARN("Read failed at flash region 0x%08" PRIx32 "\n",
|
||||
flash_src);
|
||||
return -1;
|
||||
}
|
||||
|
@ -396,9 +462,11 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||
if (size <= 0)
|
||||
res = 0;
|
||||
}
|
||||
uint32_t end_time = platform_time_ms();
|
||||
if (read_file != -1)
|
||||
close(read_file);
|
||||
printf("Read/Verifed succeeded for %d bytes\n", bytes_read);
|
||||
DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n",
|
||||
bytes_read, (((bytes_read * 1.0)/(end_time - start_time))));
|
||||
}
|
||||
free_map:
|
||||
if (map.size)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Uwe Bonnes
|
||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -24,6 +24,8 @@
|
|||
#if !defined(__CL_UTILS_H)
|
||||
#define __CL_UTILS_H
|
||||
|
||||
#define RESP_TIMEOUT (100)
|
||||
|
||||
enum bmp_cl_mode {
|
||||
BMP_MODE_DEBUG,
|
||||
BMP_MODE_TEST,
|
||||
|
@ -37,12 +39,14 @@ enum bmp_cl_mode {
|
|||
typedef struct BMP_CL_OPTIONS_s {
|
||||
enum bmp_cl_mode opt_mode;
|
||||
bool opt_usejtag;
|
||||
bool opt_no_wait;
|
||||
bool opt_tpwr;
|
||||
bool opt_list_only;
|
||||
bool opt_connect_under_reset;
|
||||
char *opt_flash_file;
|
||||
char *opt_device;
|
||||
char *opt_serial;
|
||||
char *opt_ident_string;
|
||||
int opt_position;
|
||||
char *opt_cable;
|
||||
int opt_debuglevel;
|
||||
int opt_target_dev;
|
||||
|
@ -53,6 +57,6 @@ typedef struct BMP_CL_OPTIONS_s {
|
|||
|
||||
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);
|
||||
int cl_execute(BMP_CL_OPTIONS_t *opt);
|
||||
int serial_open(BMP_CL_OPTIONS_t *opt);
|
||||
int serial_open(BMP_CL_OPTIONS_t *opt, char *serial);
|
||||
void serial_close(void);
|
||||
#endif
|
||||
|
|
|
@ -89,7 +89,7 @@ int gdb_if_init(void)
|
|||
}
|
||||
break;
|
||||
} while(1);
|
||||
DEBUG("Listening on TCP: %4d\n", port);
|
||||
DEBUG_WARN("Listening on TCP: %4d\n", port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -125,9 +125,11 @@ unsigned char gdb_if_getchar(void)
|
|||
platform_delay(100);
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
DEBUG("error when accepting connection: %d", WSAGetLastError());
|
||||
DEBUG_WARN("error when accepting connection: %d",
|
||||
WSAGetLastError());
|
||||
#else
|
||||
DEBUG("error when accepting connection: %s", strerror(errno));
|
||||
DEBUG_WARN("error when accepting connection: %s",
|
||||
strerror(errno));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
@ -141,7 +143,7 @@ unsigned char gdb_if_getchar(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
DEBUG("Got connection\n");
|
||||
DEBUG_INFO("Got connection\n");
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
opt = 0;
|
||||
ioctlsocket(gdb_if_conn, FIONBIO, &opt);
|
||||
|
@ -154,9 +156,9 @@ unsigned char gdb_if_getchar(void)
|
|||
if(i <= 0) {
|
||||
gdb_if_conn = -1;
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
DEBUG("Dropped broken connection: %d\n", WSAGetLastError());
|
||||
DEBUG_INFO("Dropped broken connection: %d\n", WSAGetLastError());
|
||||
#else
|
||||
DEBUG("Dropped broken connection: %s\n", strerror(errno));
|
||||
DEBUG_INFO("Dropped broken connection: %s\n", strerror(errno));
|
||||
#endif
|
||||
/* Return '+' in case we were waiting for an ACK */
|
||||
return '+';
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "general.h"
|
||||
#include "cl_utils.h"
|
||||
|
||||
static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans)
|
||||
{
|
||||
struct trans_ctx * const ctx = trans->user_data;
|
||||
|
||||
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
{
|
||||
DEBUG_WARN("on_trans_done: ");
|
||||
if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) {
|
||||
DEBUG_WARN(" Timeout\n");
|
||||
} else if (trans->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||
DEBUG_WARN(" cancelled\n");
|
||||
} else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) {
|
||||
DEBUG_WARN(" no device\n");
|
||||
} else {
|
||||
DEBUG_WARN(" unknown\n");
|
||||
}
|
||||
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
|
||||
}
|
||||
ctx->flags |= TRANS_FLAGS_IS_DONE;
|
||||
}
|
||||
|
||||
static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) {
|
||||
struct trans_ctx trans_ctx;
|
||||
enum libusb_error error;
|
||||
|
||||
trans_ctx.flags = 0;
|
||||
|
||||
/* brief intrusion inside the libusb interface */
|
||||
trans->callback = on_trans_done;
|
||||
trans->user_data = &trans_ctx;
|
||||
|
||||
if ((error = libusb_submit_transfer(trans))) {
|
||||
DEBUG_WARN("libusb_submit_transfer(%d): %s\n", error,
|
||||
libusb_strerror(error));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
uint32_t start_time = platform_time_ms();
|
||||
while (trans_ctx.flags == 0) {
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) {
|
||||
DEBUG_WARN("libusb_handle_events()\n");
|
||||
return -1;
|
||||
}
|
||||
uint32_t now = platform_time_ms();
|
||||
if (now - start_time > 1000) {
|
||||
libusb_cancel_transfer(trans);
|
||||
DEBUG_WARN("libusb_handle_events() timeout\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
|
||||
DEBUG_WARN("libusb_handle_events() | has_error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* One USB transaction */
|
||||
int send_recv(usb_link_t *link,
|
||||
uint8_t *txbuf, size_t txsize,
|
||||
uint8_t *rxbuf, size_t rxsize)
|
||||
{
|
||||
int res = 0;
|
||||
if( txsize) {
|
||||
int txlen = txsize;
|
||||
libusb_fill_bulk_transfer(link->req_trans,
|
||||
link->ul_libusb_device_handle,
|
||||
link->ep_tx | LIBUSB_ENDPOINT_OUT,
|
||||
txbuf, txlen,
|
||||
NULL, NULL, 0);
|
||||
int i = 0;
|
||||
DEBUG_WIRE(" Send (%3d): ", txlen);
|
||||
for (; i < txlen; i++) {
|
||||
DEBUG_WIRE("%02x", txbuf[i]);
|
||||
if ((i & 7) == 7)
|
||||
DEBUG_WIRE(".");
|
||||
if ((i & 31) == 31)
|
||||
DEBUG_WIRE("\n ");
|
||||
}
|
||||
if (!(i & 31))
|
||||
DEBUG_WIRE("\n");
|
||||
if (submit_wait(link, link->req_trans)) {
|
||||
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* send_only */
|
||||
if (rxsize != 0) {
|
||||
/* read the response */
|
||||
libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle,
|
||||
link->ep_rx | LIBUSB_ENDPOINT_IN,
|
||||
rxbuf, rxsize, NULL, NULL, 0);
|
||||
|
||||
if (submit_wait(link, link->rep_trans)) {
|
||||
DEBUG_WARN("clear 1\n");
|
||||
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx);
|
||||
return -1;
|
||||
}
|
||||
res = link->rep_trans->actual_length;
|
||||
if (res >0) {
|
||||
int i;
|
||||
uint8_t *p = rxbuf;
|
||||
DEBUG_WIRE(" Rec (%zu/%d)", rxsize, res);
|
||||
for (i = 0; i < res && i < 32 ; i++) {
|
||||
if ( i && ((i & 7) == 0))
|
||||
DEBUG_WIRE(".");
|
||||
DEBUG_WIRE("%02x", p[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_WIRE("\n");
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__LIBUSB_UTILS_H)
|
||||
#define __LIBUSB_UTILS_H
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
struct trans_ctx {
|
||||
#define TRANS_FLAGS_IS_DONE (1 << 0)
|
||||
#define TRANS_FLAGS_HAS_ERROR (1 << 1)
|
||||
volatile unsigned long flags;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
libusb_context *ul_libusb_ctx;
|
||||
libusb_device_handle *ul_libusb_device_handle;
|
||||
unsigned char ep_tx;
|
||||
unsigned char ep_rx;
|
||||
struct libusb_transfer* req_trans;
|
||||
struct libusb_transfer* rep_trans;
|
||||
void *priv;
|
||||
} usb_link_t;
|
||||
|
||||
int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize,
|
||||
uint8_t *rxbuf, size_t rxsize);
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2019 Dave Marples <dave@marples.net>
|
||||
* with additions from Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
* Modifications (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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
|
||||
|
@ -31,7 +31,7 @@
|
|||
#include "cl_utils.h"
|
||||
|
||||
static int fd; /* File descriptor for connection to GDB remote */
|
||||
extern int cl_debuglevel;
|
||||
|
||||
/* A nice routine grabbed from
|
||||
* https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
|
||||
*/
|
||||
|
@ -40,7 +40,7 @@ static int set_interface_attribs(void)
|
|||
struct termios tty;
|
||||
memset (&tty, 0, sizeof tty);
|
||||
if (tcgetattr (fd, &tty) != 0) {
|
||||
fprintf(stderr,"error %d from tcgetattr", errno);
|
||||
DEBUG_WARN("error %d from tcgetattr", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -62,22 +62,22 @@ static int set_interface_attribs(void)
|
|||
tty.c_cflag &= ~CRTSCTS;
|
||||
|
||||
if (tcsetattr (fd, TCSANOW, &tty) != 0) {
|
||||
fprintf(stderr,"error %d from tcsetattr", errno);
|
||||
DEBUG_WARN("error %d from tcsetattr", errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#define BMP_IDSTRING "usb-Black_Sphere_Technologies_Black_Magic_Probe"
|
||||
#define DEVICE_BY_ID "/dev/serial/by-id/"
|
||||
int serial_open(BMP_CL_OPTIONS_t *opt)
|
||||
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
|
||||
{
|
||||
char name[4096];
|
||||
if (!opt->opt_device) {
|
||||
if (!cl_opts->opt_device) {
|
||||
/* Try to find some BMP if0*/
|
||||
struct dirent *dp;
|
||||
DIR *dir = opendir(DEVICE_BY_ID);
|
||||
if (!dir) {
|
||||
fprintf(stderr, "No serial device found\n");
|
||||
DEBUG_WARN("No serial device found\n");
|
||||
return -1;
|
||||
}
|
||||
int num_devices = 0;
|
||||
|
@ -86,8 +86,7 @@ int serial_open(BMP_CL_OPTIONS_t *opt)
|
|||
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
|
||||
(strstr(dp->d_name, "-if00"))) {
|
||||
num_total++;
|
||||
if (((opt->opt_serial) &&
|
||||
(!strstr(dp->d_name, opt->opt_serial))))
|
||||
if ((serial) && (!strstr(dp->d_name, serial)))
|
||||
continue;
|
||||
num_devices++;
|
||||
strcpy(name, DEVICE_BY_ID);
|
||||
|
@ -96,33 +95,34 @@ int serial_open(BMP_CL_OPTIONS_t *opt)
|
|||
}
|
||||
closedir(dir);
|
||||
if ((num_devices == 0) && (num_total == 0)){
|
||||
fprintf(stderr, "No BMP probe found\n");
|
||||
DEBUG_WARN("No BMP probe found\n");
|
||||
return -1;
|
||||
} else if (num_devices != 1) {
|
||||
fprintf(stderr, "Available Probes:\n");
|
||||
DEBUG_INFO("Available Probes:\n");
|
||||
dir = opendir(DEVICE_BY_ID);
|
||||
if (dir) {
|
||||
while ((dp = readdir(dir)) != NULL) {
|
||||
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
|
||||
(strstr(dp->d_name, "-if00")))
|
||||
fprintf(stderr, "%s\n", dp->d_name);
|
||||
DEBUG_WARN("%s\n", dp->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
if (opt->opt_serial)
|
||||
fprintf(stderr, "Do no match given serial \"%s\"\n", opt->opt_serial);
|
||||
if (serial)
|
||||
DEBUG_WARN("Do no match given serial \"%s\"\n", serial);
|
||||
else
|
||||
fprintf(stderr, "Select Probe with -s <(Partial) Serial Number\n");
|
||||
DEBUG_WARN("Select Probe with -s <(Partial) Serial "
|
||||
"Number\n");
|
||||
} else {
|
||||
fprintf(stderr, "Could not opendir %s: %s\n", name, strerror(errno));
|
||||
DEBUG_WARN("Could not opendir %s: %s\n", name, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
strncpy(name, opt->opt_device, sizeof(name) - 1);
|
||||
strncpy(name, cl_opts->opt_device, sizeof(name) - 1);
|
||||
}
|
||||
fd = open(name, O_RDWR | O_SYNC | O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,"Couldn't open serial port %s\n", name);
|
||||
DEBUG_WARN("Couldn't open serial port %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
/* BMP only offers an USB-Serial connection with no real serial
|
||||
|
@ -140,12 +140,11 @@ int platform_buffer_write(const uint8_t *data, int size)
|
|||
{
|
||||
int s;
|
||||
|
||||
if (cl_debuglevel)
|
||||
printf("%s\n",data);
|
||||
DEBUG_WIRE("%s\n", data);
|
||||
s = write(fd, data, size);
|
||||
if (s < 0) {
|
||||
fprintf(stderr, "Failed to write\n");
|
||||
exit(-2);
|
||||
DEBUG_WARN("Failed to write\n");
|
||||
return(-2);
|
||||
}
|
||||
|
||||
return size;
|
||||
|
@ -156,15 +155,13 @@ int platform_buffer_read(uint8_t *data, int maxsize)
|
|||
uint8_t *c;
|
||||
int s;
|
||||
int ret;
|
||||
uint32_t endTime;
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
|
||||
c = data;
|
||||
tv.tv_sec = 0;
|
||||
|
||||
endTime = platform_time_ms() + RESP_TIMEOUT;
|
||||
tv.tv_usec = 1000 * (endTime - platform_time_ms());
|
||||
tv.tv_usec = 1000 * RESP_TIMEOUT;
|
||||
|
||||
/* Look for start of response */
|
||||
do {
|
||||
|
@ -173,12 +170,12 @@ int platform_buffer_read(uint8_t *data, int maxsize)
|
|||
|
||||
ret = select(fd + 1, &rset, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,"Failed on select\n");
|
||||
exit(-4);
|
||||
DEBUG_WARN("Failed on select\n");
|
||||
return(-3);
|
||||
}
|
||||
if(ret == 0) {
|
||||
fprintf(stderr,"Timeout on read RESP\n");
|
||||
exit(-3);
|
||||
DEBUG_WARN("Timeout on read RESP\n");
|
||||
return(-4);
|
||||
}
|
||||
|
||||
s = read(fd, c, 1);
|
||||
|
@ -190,25 +187,24 @@ int platform_buffer_read(uint8_t *data, int maxsize)
|
|||
FD_SET(fd, &rset);
|
||||
ret = select(fd + 1, &rset, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,"Failed on select\n");
|
||||
DEBUG_WARN("Failed on select\n");
|
||||
exit(-4);
|
||||
}
|
||||
if(ret == 0) {
|
||||
fprintf(stderr,"Timeout on read\n");
|
||||
exit(-3);
|
||||
DEBUG_WARN("Timeout on read\n");
|
||||
return(-5);
|
||||
}
|
||||
s = read(fd, c, 1);
|
||||
if (*c==REMOTE_EOM) {
|
||||
*c = 0;
|
||||
if (cl_debuglevel)
|
||||
printf(" %s\n",data);
|
||||
DEBUG_WIRE(" %s\n",data);
|
||||
return (c - data);
|
||||
} else {
|
||||
c++;
|
||||
}
|
||||
}while ((s >= 0) && ((c - data) < maxsize));
|
||||
|
||||
fprintf(stderr,"Failed to read\n");
|
||||
exit(-3);
|
||||
DEBUG_WARN("Failed to read\n");
|
||||
return(-6);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,20 +24,21 @@
|
|||
#include "cl_utils.h"
|
||||
|
||||
HANDLE hComm;
|
||||
extern int cl_debuglevel;
|
||||
|
||||
int serial_open(BMP_CL_OPTIONS_t *opt)
|
||||
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial)
|
||||
{
|
||||
if (!opt->opt_device) {
|
||||
fprintf(stderr,"Specify the serial device to use!\n");
|
||||
(void) serial; /* FIXME: Does Windows allow open with USB serial no? */
|
||||
if (!cl_opts->opt_device) {
|
||||
DEBUG_WARN("Specify the serial device to use!\n");
|
||||
return -1;
|
||||
}
|
||||
char device[256];
|
||||
if (strstr(opt->opt_device, "\\\\.\\")) {
|
||||
strncpy(device, opt->opt_device, sizeof(device) - 1);
|
||||
if (strstr(device, "\\\\.\\")) {
|
||||
strncpy(device, cl_opts->opt_device, sizeof(cl_opts->opt_device) - 1);
|
||||
} else {
|
||||
strcpy(device, "\\\\.\\");
|
||||
strncat(device, opt->opt_device, sizeof(device) - strlen(device) - 1);
|
||||
strncat(device, cl_opts->opt_device,
|
||||
sizeof(cl_opts->opt_device) - strlen(cl_opts->opt_device) - 1);
|
||||
}
|
||||
hComm = CreateFile(device, //port name
|
||||
GENERIC_READ | GENERIC_WRITE, //Read/Write
|
||||
|
@ -47,19 +48,19 @@ int serial_open(BMP_CL_OPTIONS_t *opt)
|
|||
0, // Non Overlapped I/O
|
||||
NULL); // Null for Comm Devices}
|
||||
if (hComm == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Could not open %s: %ld\n", device,
|
||||
DEBUG_WARN("Could not open %s: %ld\n", device,
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
DCB dcbSerialParams;
|
||||
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
|
||||
if (!GetCommState(hComm, &dcbSerialParams)) {
|
||||
fprintf(stderr, "GetCommState failed %ld\n", GetLastError());
|
||||
DEBUG_WARN("GetCommState failed %ld\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
if (!SetCommState(hComm, &dcbSerialParams)) {
|
||||
fprintf(stderr, "SetCommState failed %ld\n", GetLastError());
|
||||
DEBUG_WARN("SetCommState failed %ld\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
|
@ -69,7 +70,7 @@ int serial_open(BMP_CL_OPTIONS_t *opt)
|
|||
timeouts.WriteTotalTimeoutConstant = 10;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||
if (!SetCommTimeouts(hComm, &timeouts)) {
|
||||
fprintf(stderr, "SetCommTimeouts failed %ld\n", GetLastError());
|
||||
DEBUG_WARN("SetCommTimeouts failed %ld\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -82,14 +83,13 @@ void serial_close(void)
|
|||
|
||||
int platform_buffer_write(const uint8_t *data, int size)
|
||||
{
|
||||
if (cl_debuglevel)
|
||||
printf("%s\n",data);
|
||||
DEBUG_WIRE("%s\n",data);
|
||||
int s = 0;
|
||||
|
||||
do {
|
||||
DWORD written;
|
||||
if (!WriteFile(hComm, data + s, size - s, &written, NULL)) {
|
||||
fprintf(stderr, "Serial write failed %ld, written %d\n",
|
||||
DEBUG_WARN("Serial write failed %ld, written %d\n",
|
||||
GetLastError(), s);
|
||||
return -1;
|
||||
}
|
||||
|
@ -105,34 +105,32 @@ int platform_buffer_read(uint8_t *data, int maxsize)
|
|||
uint32_t endTime = platform_time_ms() + RESP_TIMEOUT;
|
||||
do {
|
||||
if (!ReadFile(hComm, &response, 1, &s, NULL)) {
|
||||
fprintf(stderr,"ERROR on read RESP\n");
|
||||
DEBUG_WARN("ERROR on read RESP\n");
|
||||
exit(-3);
|
||||
}
|
||||
if (platform_time_ms() > endTime) {
|
||||
fprintf(stderr,"Timeout on read RESP\n");
|
||||
DEBUG_WARN("Timeout on read RESP\n");
|
||||
exit(-4);
|
||||
}
|
||||
} while (response != REMOTE_RESP);
|
||||
uint8_t *c = data;
|
||||
do {
|
||||
if (!ReadFile(hComm, c, 1, &s, NULL)) {
|
||||
fprintf(stderr,"Error on read\n");
|
||||
DEBUG_WARN("Error on read\n");
|
||||
exit(-3);
|
||||
}
|
||||
if (s > 0 ) {
|
||||
if (cl_debuglevel)
|
||||
printf("%c", *c);
|
||||
DEBUG_WIRE("%c", *c);
|
||||
if (*c == REMOTE_EOM) {
|
||||
*c = 0;
|
||||
if (cl_debuglevel)
|
||||
printf("\n");
|
||||
DEBUG_WIRE("\n");
|
||||
return (c - data);
|
||||
} else {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
} while (((c - data) < maxsize) && (platform_time_ms() < endTime));
|
||||
fprintf(stderr,"Failed to read EOM at %d\n",
|
||||
DEBUG_WARN("Failed to read EOM at %d\n",
|
||||
platform_time_ms() - startTime);
|
||||
exit(-3);
|
||||
return 0;
|
||||
|
|
|
@ -37,18 +37,18 @@ SRC += cdcacm.c \
|
|||
stlink_common.c \
|
||||
|
||||
ifeq ($(ST_BOOTLOADER), 1)
|
||||
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
|
||||
all: blackmagic.bin
|
||||
else
|
||||
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex
|
||||
endif
|
||||
blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o stlink_common.o
|
||||
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o stlink_common.o
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
||||
|
||||
dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o stlink_common.o
|
||||
dfu_upgrade.elf: dfu_upgrade.o dfucore.o dfu_f1.o stlink_common.o
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
host_clean:
|
||||
-$(Q)$(RM) blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade dfu_upgrade.bin dfu_upgrade.hex
|
||||
-$(Q)$(RM) *.bin *elf *hex
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#ifdef ENABLE_DEBUG
|
||||
# define PLATFORM_HAS_DEBUG
|
||||
# define USBUART_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
#endif
|
||||
|
||||
#define BOARD_IDENT "Black Magic Probe (STLINK), (Firmware " FIRMWARE_VERSION ")"
|
||||
|
@ -118,14 +120,6 @@
|
|||
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
|
||||
#define USBUSART_TIM_ISR tim4_isr
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
# define DEBUG printf
|
||||
#else
|
||||
# define DEBUG(...)
|
||||
#endif
|
||||
|
||||
/* On F103, only USART1 is on AHB2 and can reach 4.5 MBaud at 72 MHz.*/
|
||||
#define SWO_UART USART1
|
||||
#define SWO_UART_DR USART1_DR
|
||||
|
|
|
@ -263,7 +263,7 @@ enum {
|
|||
int rdi_write(int fn, const char *buf, size_t len)
|
||||
{
|
||||
(void)fn;
|
||||
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
|
||||
#if defined(PLATFORM_HAS_DEBUG)
|
||||
if (debug_bmp)
|
||||
return len - usbuart_debug_write(buf, len);
|
||||
#else
|
||||
|
|
|
@ -31,11 +31,11 @@ SRC += cdcacm.c \
|
|||
|
||||
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex
|
||||
|
||||
blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o platform_common.o
|
||||
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o platform_common.o
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)
|
||||
|
||||
dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o platform_common.o
|
||||
dfu_upgrade.elf: dfu_upgrade.o dfucore.o dfu_f1.o platform_common.o
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ const char *platform_target_voltage(void)
|
|||
ret[2] = '0' + val_in_100mV % 10;
|
||||
return ret;
|
||||
}
|
||||
return "ABSENT!";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_idle_state(int state)
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#ifdef ENABLE_DEBUG
|
||||
# define PLATFORM_HAS_DEBUG
|
||||
# define USBUART_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
#endif
|
||||
|
||||
#define BOARD_IDENT "Black Magic Probe (SWLINK), (Firmware " FIRMWARE_VERSION ")"
|
||||
|
@ -122,14 +124,6 @@
|
|||
#define TRACE_IC_IN TIM_IC_IN_TI2
|
||||
#define TRACE_TRIG_IN TIM_SMCR_TS_IT1FP2
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
extern bool debug_bmp;
|
||||
int usbuart_debug_write(const char *buf, size_t len);
|
||||
# define DEBUG printf
|
||||
#else
|
||||
# define DEBUG(...)
|
||||
#endif
|
||||
|
||||
/* On F103, only USART1 is on AHB2 and can reach 4.5 MBaud at 72 MHz.
|
||||
* USART1 is already used. sp maximum speed is 2.25 MBaud. */
|
||||
#define SWO_UART USART2
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
#include "general.h"
|
||||
#include "jtagtap.h"
|
||||
|
||||
int
|
||||
jtagtap_init(void)
|
||||
{
|
||||
TMS_SET_MODE();
|
||||
|
||||
for(int i = 0; i <= 50; i++) jtagtap_next(1,0);
|
||||
jtagtap_tms_seq(0xE73C, 16);
|
||||
jtagtap_soft_reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
jtagtap_reset(void)
|
||||
{
|
||||
#ifdef TRST_PORT
|
||||
volatile int i;
|
||||
gpio_clear(TRST_PORT, TRST_PIN);
|
||||
for(i = 0; i < 10000; i++) asm("nop");
|
||||
gpio_set(TRST_PORT, TRST_PIN);
|
||||
#endif
|
||||
jtagtap_soft_reset();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
jtagtap_next(const uint8_t dTMS, const uint8_t dTDI)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
gpio_set_val(TMS_PORT, TMS_PIN, dTMS);
|
||||
gpio_set_val(TDI_PORT, TDI_PIN, dTDI);
|
||||
gpio_set(TCK_PORT, TCK_PIN);
|
||||
ret = gpio_get(TDO_PORT, TDO_PIN);
|
||||
gpio_clear(TCK_PORT, TCK_PIN);
|
||||
|
||||
DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret);
|
||||
|
||||
return ret != 0;
|
||||
}
|
||||
|
162
src/remote.c
162
src/remote.c
|
@ -25,7 +25,11 @@
|
|||
#include "jtagtap.h"
|
||||
#include "gdb_if.h"
|
||||
#include "version.h"
|
||||
#include "exception.h"
|
||||
#include <stdarg.h>
|
||||
#include "target/adiv5.h"
|
||||
#include "target.h"
|
||||
#include "hex_utils.h"
|
||||
|
||||
|
||||
#define NTOH(x) ((x<=9)?x+'0':'a'+x-10)
|
||||
|
@ -56,6 +60,31 @@ uint64_t remotehston(uint32_t limit, char *s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if PC_HOSTED == 0
|
||||
static void _send_buf(uint8_t* buffer, size_t len)
|
||||
{
|
||||
uint8_t* p = buffer;
|
||||
char hex[2];
|
||||
do {
|
||||
hexify(hex, (const void*)p++, 1);
|
||||
|
||||
gdb_if_putchar(hex[0], 0);
|
||||
gdb_if_putchar(hex[1], 0);
|
||||
|
||||
} while (p<(buffer+len));
|
||||
}
|
||||
|
||||
static void _respond_buf(char respCode, uint8_t* buffer, size_t len)
|
||||
{
|
||||
gdb_if_putchar(REMOTE_RESP, 0);
|
||||
gdb_if_putchar(respCode, 0);
|
||||
|
||||
_send_buf(buffer, len);
|
||||
|
||||
gdb_if_putchar(REMOTE_EOM, 1);
|
||||
}
|
||||
|
||||
|
||||
static void _respond(char respCode, uint64_t param)
|
||||
|
||||
/* Send response to far end */
|
||||
|
@ -96,6 +125,16 @@ static void _respondS(char respCode, const char *s)
|
|||
gdb_if_putchar(REMOTE_EOM,1);
|
||||
}
|
||||
|
||||
static ADIv5_DP_t remote_dp = {
|
||||
.dp_read = firmware_swdp_read,
|
||||
.ap_read = firmware_ap_read,
|
||||
.ap_write = firmware_ap_write,
|
||||
.mem_read = firmware_mem_read,
|
||||
.mem_write_sized = firmware_mem_write_sized,
|
||||
.low_access = firmware_swdp_low_access,
|
||||
};
|
||||
|
||||
|
||||
void remotePacketProcessSWD(uint8_t i, char *packet)
|
||||
{
|
||||
uint8_t ticks;
|
||||
|
@ -114,27 +153,27 @@ void remotePacketProcessSWD(uint8_t i, char *packet)
|
|||
|
||||
case REMOTE_IN_PAR: /* = In parity ================================== */
|
||||
ticks=remotehston(2,&packet[2]);
|
||||
badParity=swdptap_seq_in_parity(¶m, ticks);
|
||||
badParity = swd_proc.swdptap_seq_in_parity(¶m, ticks);
|
||||
_respond(badParity?REMOTE_RESP_PARERR:REMOTE_RESP_OK,param);
|
||||
break;
|
||||
|
||||
case REMOTE_IN: /* = In ========================================= */
|
||||
ticks=remotehston(2,&packet[2]);
|
||||
param=swdptap_seq_in(ticks);
|
||||
param = swd_proc.swdptap_seq_in(ticks);
|
||||
_respond(REMOTE_RESP_OK,param);
|
||||
break;
|
||||
|
||||
case REMOTE_OUT: /* = Out ======================================== */
|
||||
ticks=remotehston(2,&packet[2]);
|
||||
param=remotehston(-1, &packet[4]);
|
||||
swdptap_seq_out(param, ticks);
|
||||
swd_proc.swdptap_seq_out(param, ticks);
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
|
||||
case REMOTE_OUT_PAR: /* = Out parity ================================= */
|
||||
ticks=remotehston(2,&packet[2]);
|
||||
param=remotehston(-1, &packet[4]);
|
||||
swdptap_seq_out_parity(param, ticks);
|
||||
swd_proc.swdptap_seq_out_parity(param, ticks);
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
|
||||
|
@ -154,11 +193,13 @@ void remotePacketProcessJTAG(uint8_t i, char *packet)
|
|||
switch (packet[1]) {
|
||||
case REMOTE_INIT: /* = initialise ================================= */
|
||||
jtagtap_init();
|
||||
remote_dp.dp_read = fw_adiv5_jtagdp_read;
|
||||
remote_dp.low_access = fw_adiv5_jtagdp_low_access;
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
|
||||
case REMOTE_RESET: /* = reset ================================= */
|
||||
jtagtap_reset();
|
||||
jtag_proc.jtagtap_reset();
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
|
||||
|
@ -169,7 +210,7 @@ void remotePacketProcessJTAG(uint8_t i, char *packet)
|
|||
if (i<4) {
|
||||
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
|
||||
} else {
|
||||
jtagtap_tms_seq( MS, ticks);
|
||||
jtag_proc.jtagtap_tms_seq( MS, ticks);
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -182,7 +223,7 @@ void remotePacketProcessJTAG(uint8_t i, char *packet)
|
|||
} else {
|
||||
ticks=remotehston(2,&packet[2]);
|
||||
DI=remotehston(-1,&packet[4]);
|
||||
jtagtap_tdi_tdo_seq((void *)&DO, (packet[1]==REMOTE_TDITDO_TMS), (void *)&DI, ticks);
|
||||
jtag_proc.jtagtap_tdi_tdo_seq((void *)&DO, (packet[1]==REMOTE_TDITDO_TMS), (void *)&DI, ticks);
|
||||
|
||||
/* Mask extra bits on return value... */
|
||||
DO &= (1LL << (ticks + 1)) - 1;
|
||||
|
@ -195,7 +236,7 @@ void remotePacketProcessJTAG(uint8_t i, char *packet)
|
|||
if (i!=4) {
|
||||
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
|
||||
} else {
|
||||
uint32_t dat=jtagtap_next( (packet[2]=='1'), (packet[3]=='1'));
|
||||
uint32_t dat=jtag_proc.jtagtap_next( (packet[2]=='1'), (packet[3]=='1'));
|
||||
_respond(REMOTE_RESP_OK,dat);
|
||||
}
|
||||
break;
|
||||
|
@ -242,7 +283,7 @@ void remotePacketProcessGEN(uint8_t i, char *packet)
|
|||
break;
|
||||
|
||||
#if !defined(BOARD_IDENT) && defined(PLATFORM_IDENT)
|
||||
# define BOARD_IDENT PLATFORM_IDENT
|
||||
# define BOARD_IDENT() PLATFORM_IDENT
|
||||
#endif
|
||||
case REMOTE_START:
|
||||
_respondS(REMOTE_RESP_OK, BOARD_IDENT " " FIRMWARE_VERSION);
|
||||
|
@ -254,6 +295,104 @@ void remotePacketProcessGEN(uint8_t i, char *packet)
|
|||
}
|
||||
}
|
||||
|
||||
void remotePacketProcessHL(uint8_t i, char *packet)
|
||||
|
||||
{
|
||||
(void)i;
|
||||
SET_IDLE_STATE(0);
|
||||
|
||||
ADIv5_AP_t remote_ap;
|
||||
/* Re-use packet buffer. Align to DWORD! */
|
||||
void *src = (void *)(((uint32_t)packet + 7) & ~7);
|
||||
char index = packet[1];
|
||||
packet += 2;
|
||||
remote_ap.apsel = remotehston(2, packet);
|
||||
remote_ap.dp = &remote_dp;
|
||||
switch (index) {
|
||||
case REMOTE_DP_READ:
|
||||
packet += 2;
|
||||
uint16_t addr16 = remotehston(4, packet);
|
||||
uint32_t data = adiv5_dp_read(&remote_dp, addr16);
|
||||
_respond_buf(REMOTE_RESP_OK, (uint8_t*)&data, 4);
|
||||
break;
|
||||
case REMOTE_LOW_ACCESS:
|
||||
packet += 2;
|
||||
addr16 = remotehston(4, packet);
|
||||
packet += 4;
|
||||
uint32_t value = remotehston(8, packet);
|
||||
data = remote_dp.low_access(&remote_dp, remote_ap.apsel, addr16, value);
|
||||
_respond_buf(REMOTE_RESP_OK, (uint8_t*)&data, 4);
|
||||
break;
|
||||
case REMOTE_AP_READ:
|
||||
packet += 2;
|
||||
addr16 = remotehston(4, packet);
|
||||
data = adiv5_ap_read(&remote_ap, addr16);
|
||||
_respond_buf(REMOTE_RESP_OK, (uint8_t*)&data, 4);
|
||||
break;
|
||||
case REMOTE_AP_WRITE:
|
||||
packet += 2;
|
||||
addr16 = remotehston(4, packet);
|
||||
packet += 4;
|
||||
value = remotehston(8, packet);
|
||||
adiv5_ap_write(&remote_ap, addr16, value);
|
||||
_respond(REMOTE_RESP_OK, 0);
|
||||
break;
|
||||
case REMOTE_AP_MEM_READ:
|
||||
packet += 2;
|
||||
remote_ap.csw = remotehston(8, packet);
|
||||
packet += 6;
|
||||
/*fall through*/
|
||||
case REMOTE_MEM_READ:
|
||||
packet += 2;
|
||||
uint32_t address = remotehston(8, packet);
|
||||
packet += 8;
|
||||
uint32_t count = remotehston(8, packet);
|
||||
packet += 8;
|
||||
adiv5_mem_read(&remote_ap, src, address, count);
|
||||
if (remote_ap.dp->fault == 0) {
|
||||
_respond_buf(REMOTE_RESP_OK, src, count);
|
||||
break;
|
||||
}
|
||||
_respond(REMOTE_RESP_ERR, 0);
|
||||
remote_ap.dp->fault = 0;
|
||||
break;
|
||||
case REMOTE_AP_MEM_WRITE_SIZED:
|
||||
packet += 2;
|
||||
remote_ap.csw = remotehston(8, packet);
|
||||
packet += 6;
|
||||
/*fall through*/
|
||||
case REMOTE_MEM_WRITE_SIZED:
|
||||
packet += 2;
|
||||
enum align align = remotehston(2, packet);
|
||||
packet += 2;
|
||||
uint32_t dest = remotehston(8, packet);
|
||||
packet+= 8;
|
||||
size_t len = remotehston(8, packet);
|
||||
packet += 8;
|
||||
if (len & ((1 << align) - 1)) {
|
||||
/* len and align do not fit*/
|
||||
_respond(REMOTE_RESP_ERR, 0);
|
||||
break;
|
||||
}
|
||||
/* Read as stream of hexified bytes*/
|
||||
unhexify(src, packet, len);
|
||||
adiv5_mem_write_sized(&remote_ap, dest, src, len, align);
|
||||
if (remote_ap.dp->fault) {
|
||||
/* Errors handles on hosted side.*/
|
||||
_respond(REMOTE_RESP_ERR, 0);
|
||||
remote_ap.dp->fault = 0;
|
||||
break;
|
||||
}
|
||||
_respond_buf(REMOTE_RESP_OK, src, len);
|
||||
break;
|
||||
default:
|
||||
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
|
||||
break;
|
||||
}
|
||||
SET_IDLE_STATE(1);
|
||||
}
|
||||
|
||||
|
||||
void remotePacketProcess(uint8_t i, char *packet)
|
||||
{
|
||||
switch (packet[0]) {
|
||||
|
@ -269,8 +408,13 @@ void remotePacketProcess(uint8_t i, char *packet)
|
|||
remotePacketProcessGEN(i,packet);
|
||||
break;
|
||||
|
||||
case REMOTE_HL_PACKET:
|
||||
remotePacketProcessHL(i, packet);
|
||||
break;
|
||||
|
||||
default: /* Oh dear, unrecognised, return an error */
|
||||
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
34
src/remote.h
34
src/remote.h
|
@ -83,6 +83,18 @@
|
|||
#define REMOTE_RESP_ERR 'E'
|
||||
#define REMOTE_RESP_NOTSUP 'N'
|
||||
|
||||
/* High level protocol elements */
|
||||
#define REMOTE_HL_PACKET 'H'
|
||||
#define REMOTE_DP_READ 'd'
|
||||
#define REMOTE_LOW_ACCESS 'L'
|
||||
#define REMOTE_AP_READ 'a'
|
||||
#define REMOTE_AP_WRITE 'A'
|
||||
#define REMOTE_AP_MEM_READ 'M'
|
||||
#define REMOTE_MEM_READ 'h'
|
||||
#define REMOTE_MEM_WRITE_SIZED 'H'
|
||||
#define REMOTE_AP_MEM_WRITE_SIZED 'm'
|
||||
|
||||
|
||||
/* Generic protocol elements */
|
||||
#define REMOTE_GEN_PACKET 'G'
|
||||
|
||||
|
@ -125,6 +137,28 @@
|
|||
#define REMOTE_JTAG_NEXT (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_NEXT, \
|
||||
'%','c','%','c',REMOTE_EOM, 0 }
|
||||
|
||||
/* HL protocol elements */
|
||||
#define HEX '%', '0', '2', 'x'
|
||||
#define HEX_U32(x) '%', '0', '8', 'x'
|
||||
#define CHR(x) '%', 'c'
|
||||
|
||||
#define REMOTE_MEM_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_MEM_READ, \
|
||||
HEX_U32(address), HEX_U32(count), REMOTE_EOM, 0 }
|
||||
#define REMOTE_DP_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_DP_READ, \
|
||||
'f', 'f','%', '0', '4', 'x', REMOTE_EOM, 0 }
|
||||
#define REMOTE_LOW_ACCESS_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_LOW_ACCESS, \
|
||||
'%','0', '2', 'x', '%', '0', '4', 'x', HEX_U32(csw), REMOTE_EOM, 0 }
|
||||
#define REMOTE_AP_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_AP_READ, \
|
||||
'%','0','2','x', '%', '0', '4', 'x', REMOTE_EOM, 0 }
|
||||
#define REMOTE_AP_WRITE_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_AP_WRITE, \
|
||||
'%','0','2','x', '%', '0', '4', 'x', HEX_U32(csw), REMOTE_EOM, 0 }
|
||||
#define REMOTE_AP_MEM_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_AP_MEM_READ, \
|
||||
'%','0','2','x',HEX_U32(csw), HEX_U32(address), HEX_U32(count), REMOTE_EOM, 0 }
|
||||
#define REMOTE_AP_MEM_WRITE_SIZED_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_AP_MEM_WRITE_SIZED, \
|
||||
'%', '0', '2', 'x', HEX_U32(csw), '%', '0', '2', 'x', HEX_U32(address), HEX_U32(count), 0}
|
||||
#define REMOTE_MEM_WRITE_SIZED_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_AP_MEM_WRITE_SIZED, \
|
||||
'%','0','2','x', HEX_U32(address), HEX_U32(count), 0}
|
||||
|
||||
uint64_t remotehston(uint32_t limit, char *s);
|
||||
void remotePacketProcess(uint8_t i, char *packet);
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* Copyright (C) 2015 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* Copyright (C) 2018 - 2020 Uwe Bonnes
|
||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||
*
|
||||
* 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
|
||||
|
@ -74,7 +76,7 @@ enum cid_class {
|
|||
cidc_unknown = 0x10
|
||||
};
|
||||
|
||||
#ifdef PLATFORM_HAS_DEBUG
|
||||
#ifdef ENABLE_DEBUG
|
||||
/* The reserved ones only have an R in them, to save a bit of space. */
|
||||
static const char * const cidc_debug_strings[] =
|
||||
{
|
||||
|
@ -111,7 +113,7 @@ enum arm_arch {
|
|||
aa_end
|
||||
};
|
||||
|
||||
#ifdef PLATFORM_HAS_DEBUG
|
||||
#ifdef ENABLE_DEBUG
|
||||
#define PIDR_PN_BIT_STRINGS(...) __VA_ARGS__
|
||||
#else
|
||||
#define PIDR_PN_BIT_STRINGS(...)
|
||||
|
@ -155,7 +157,7 @@ static const struct {
|
|||
uint16_t part_number;
|
||||
enum arm_arch arch;
|
||||
enum cid_class cidc;
|
||||
#ifdef PLATFORM_HAS_DEBUG
|
||||
#ifdef ENABLE_DEBUG
|
||||
const char *type;
|
||||
const char *full;
|
||||
#endif
|
||||
|
@ -241,11 +243,6 @@ void adiv5_ap_unref(ADIv5_AP_t *ap)
|
|||
}
|
||||
}
|
||||
|
||||
void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value)
|
||||
{
|
||||
dp->low_access(dp, ADIV5_LOW_WRITE, addr, value);
|
||||
}
|
||||
|
||||
static uint32_t adiv5_mem_read32(ADIv5_AP_t *ap, uint32_t addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
@ -277,7 +274,7 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
uint64_t pidr = adiv5_ap_read_pidr(ap, addr);
|
||||
uint32_t cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET);
|
||||
bool res = false;
|
||||
#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG)
|
||||
#if defined(ENABLE_DEBUG)
|
||||
char indent[recursion + 1];
|
||||
|
||||
for(int i = 0; i < recursion; i++) indent[i] = ' ';
|
||||
|
@ -285,13 +282,13 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
#endif
|
||||
|
||||
if (adiv5_dp_error(ap->dp)) {
|
||||
DEBUG("%sFault reading ID registers\n", indent);
|
||||
DEBUG_WARN("%sFault reading ID registers\n", indent);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* CIDR preamble sanity check */
|
||||
if ((cidr & ~CID_CLASS_MASK) != CID_PREAMBLE) {
|
||||
DEBUG("%s%d 0x%08" PRIx32": 0x%08" PRIx32
|
||||
DEBUG_WARN("%s%d 0x%08" PRIx32": 0x%08" PRIx32
|
||||
" <- does not match preamble (0x%X)\n",
|
||||
indent + 1, num_entry, addr, cidr, CID_PREAMBLE);
|
||||
return false;
|
||||
|
@ -303,30 +300,32 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
/* ROM table */
|
||||
if (cid_class == cidc_romtab) {
|
||||
/* Check SYSMEM bit */
|
||||
#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG)
|
||||
#if defined(ENABLE_DEBUG)
|
||||
uint32_t memtype = adiv5_mem_read32(ap, addr | ADIV5_ROM_MEMTYPE) &
|
||||
ADIV5_ROM_MEMTYPE_SYSMEM;
|
||||
|
||||
if (adiv5_dp_error(ap->dp)) {
|
||||
DEBUG("Fault reading ROM table entry\n");
|
||||
DEBUG_WARN("Fault reading ROM table entry\n");
|
||||
}
|
||||
|
||||
DEBUG("ROM: Table BASE=0x%" PRIx32 " SYSMEM=0x%" PRIx32 ", PIDR 0x%02"
|
||||
PRIx32 "%08" PRIx32 "\n", addr, memtype, (uint32_t)(pidr >> 32),
|
||||
(uint32_t)pidr);
|
||||
DEBUG_INFO("ROM: Table BASE=0x%" PRIx32 " SYSMEM=0x%" PRIx32
|
||||
", PIDR 0x%02" PRIx32 "%08" PRIx32 "\n", addr,
|
||||
memtype, (uint32_t)(pidr >> 32), (uint32_t)pidr);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 960; i++) {
|
||||
adiv5_dp_error(ap->dp);
|
||||
uint32_t entry = adiv5_mem_read32(ap, addr + i*4);
|
||||
if (adiv5_dp_error(ap->dp)) {
|
||||
DEBUG("%sFault reading ROM table entry\n", indent);
|
||||
DEBUG_WARN("%sFault reading ROM table entry %d\n", indent, i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry == 0)
|
||||
break;
|
||||
|
||||
if (!(entry & ADIV5_ROM_ROMENTRY_PRESENT)) {
|
||||
DEBUG("%s%d Entry 0x%" PRIx32 " -> Not present\n", indent,
|
||||
DEBUG_INFO("%s%d Entry 0x%" PRIx32 " -> Not present\n", indent,
|
||||
i, entry);
|
||||
continue;
|
||||
}
|
||||
|
@ -336,13 +335,13 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
ap, addr + (entry & ADIV5_ROM_ROMENTRY_OFFSET),
|
||||
recursion + 1, i);
|
||||
}
|
||||
DEBUG("%sROM: Table END\n", indent);
|
||||
DEBUG_INFO("%sROM: Table END\n", indent);
|
||||
} else {
|
||||
/* Check if the component was designed by ARM, we currently do not support,
|
||||
* any components by other designers.
|
||||
*/
|
||||
if ((pidr & ~(PIDR_REV_MASK | PIDR_PN_MASK)) != PIDR_ARM_BITS) {
|
||||
DEBUG("%s0x%" PRIx32 ": 0x%02" PRIx32 "%08" PRIx32
|
||||
DEBUG_WARN("%s0x%" PRIx32 ": 0x%02" PRIx32 "%08" PRIx32
|
||||
" <- does not match ARM JEP-106\n",
|
||||
indent, addr, (uint32_t)(pidr >> 32), (uint32_t)pidr);
|
||||
return false;
|
||||
|
@ -356,7 +355,7 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
int i;
|
||||
for (i = 0; pidr_pn_bits[i].arch != aa_end; i++) {
|
||||
if (pidr_pn_bits[i].part_number == part_number) {
|
||||
DEBUG("%s%d 0x%" PRIx32 ": %s - %s %s (PIDR = 0x%02" PRIx32
|
||||
DEBUG_INFO("%s%d 0x%" PRIx32 ": %s - %s %s (PIDR = 0x%02" PRIx32
|
||||
"%08" PRIx32 ")",
|
||||
indent + 1, num_entry, addr,
|
||||
cidc_debug_strings[cid_class],
|
||||
|
@ -367,29 +366,30 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
*/
|
||||
if ((pidr_pn_bits[i].cidc != cidc_unknown) &&
|
||||
(cid_class != pidr_pn_bits[i].cidc)) {
|
||||
DEBUG("%sWARNING: \"%s\" !match expected \"%s\"\n", indent + 1,
|
||||
cidc_debug_strings[cid_class],
|
||||
cidc_debug_strings[pidr_pn_bits[i].cidc]);
|
||||
DEBUG_WARN("%sWARNING: \"%s\" !match expected \"%s\"\n",
|
||||
indent + 1,
|
||||
cidc_debug_strings[cid_class],
|
||||
cidc_debug_strings[pidr_pn_bits[i].cidc]);
|
||||
}
|
||||
res = true;
|
||||
switch (pidr_pn_bits[i].arch) {
|
||||
case aa_cortexm:
|
||||
DEBUG("%s-> cortexm_probe\n", indent + 1);
|
||||
DEBUG_INFO("%s-> cortexm_probe\n", indent + 1);
|
||||
cortexm_probe(ap, false);
|
||||
break;
|
||||
case aa_cortexa:
|
||||
DEBUG("\n -> cortexa_probe\n");
|
||||
DEBUG_INFO("\n -> cortexa_probe\n");
|
||||
cortexa_probe(ap, addr);
|
||||
break;
|
||||
default:
|
||||
DEBUG("\n");
|
||||
DEBUG_INFO("\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pidr_pn_bits[i].arch == aa_end) {
|
||||
DEBUG("%s0x%" PRIx32 ": %s - Unknown (PIDR = 0x%02" PRIx32
|
||||
DEBUG_WARN("%s0x%" PRIx32 ": %s - Unknown (PIDR = 0x%02" PRIx32
|
||||
"%08" PRIx32 ")\n",
|
||||
indent, addr, cidc_debug_strings[cid_class],
|
||||
(uint32_t)(pidr >> 32), (uint32_t)pidr);
|
||||
|
@ -397,8 +397,6 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||
}
|
||||
return res;
|
||||
}
|
||||
bool adiv5_ap_setup(int i);
|
||||
void adiv5_ap_cleanup(int i);
|
||||
|
||||
ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel)
|
||||
{
|
||||
|
@ -415,25 +413,27 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel)
|
|||
/* It's valid to so create a heap copy */
|
||||
ap = malloc(sizeof(*ap));
|
||||
if (!ap) { /* malloc failed: heap exhaustion */
|
||||
DEBUG("malloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("malloc: failed in %s\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ap, &tmpap, sizeof(*ap));
|
||||
adiv5_dp_ref(dp);
|
||||
|
||||
ap->cfg = adiv5_ap_read(ap, ADIV5_AP_CFG);
|
||||
ap->base = adiv5_ap_read(ap, ADIV5_AP_BASE);
|
||||
ap->csw = adiv5_ap_read(ap, ADIV5_AP_CSW) &
|
||||
~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK);
|
||||
|
||||
if (ap->csw & ADIV5_AP_CSW_TRINPROG) {
|
||||
DEBUG("AP transaction in progress. Target may not be usable.\n");
|
||||
DEBUG_WARN("AP transaction in progress. Target may not be usable.\n");
|
||||
ap->csw &= ~ADIV5_AP_CSW_TRINPROG;
|
||||
}
|
||||
|
||||
DEBUG("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08"PRIx32" CSW=%08"PRIx32"\n",
|
||||
apsel, ap->idr, ap->cfg, ap->base, ap->csw);
|
||||
#if defined(ENABLE_DEBUG)
|
||||
uint32_t cfg = adiv5_ap_read(ap, ADIV5_AP_CFG);
|
||||
DEBUG_INFO("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08" PRIx32
|
||||
" CSW=%08"PRIx32"\n", apsel, ap->idr, cfg, ap->base, ap->csw);
|
||||
#endif
|
||||
return ap;
|
||||
}
|
||||
|
||||
|
@ -442,13 +442,28 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||
volatile bool probed = false;
|
||||
volatile uint32_t ctrlstat = 0;
|
||||
adiv5_dp_ref(dp);
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
platform_adiv5_dp_defaults(dp);
|
||||
if (!dp->ap_write)
|
||||
dp->ap_write = firmware_ap_write;
|
||||
if (!dp->ap_read)
|
||||
dp->ap_read = firmware_ap_read;
|
||||
if (!dp->mem_read)
|
||||
dp->mem_read = firmware_mem_read;
|
||||
if (!dp->mem_write_sized)
|
||||
dp->mem_write_sized = firmware_mem_write_sized;
|
||||
#else
|
||||
dp->ap_write = firmware_ap_write;
|
||||
dp->ap_read = firmware_ap_read;
|
||||
dp->mem_read = firmware_mem_read;
|
||||
dp->mem_write_sized = firmware_mem_write_sized;
|
||||
#endif
|
||||
volatile struct exception e;
|
||||
TRY_CATCH (e, EXCEPTION_TIMEOUT) {
|
||||
ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
||||
}
|
||||
if (e.type) {
|
||||
DEBUG("DP not responding! Trying abort sequence...\n");
|
||||
DEBUG_WARN("DP not responding! Trying abort sequence...\n");
|
||||
adiv5_dp_abort(dp, ADIV5_DP_ABORT_DAPABORT);
|
||||
ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
||||
}
|
||||
|
@ -466,56 +481,67 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||
* correctly on STM32. CDBGRSTACK is never asserted, and we
|
||||
* just wait forever. This scenario is described in B2.4.1
|
||||
* so we have a timeout mechanism in addition to the sensing one.
|
||||
*/
|
||||
|
||||
/* Write request for debug reset */
|
||||
*
|
||||
* Write request for debug reset */
|
||||
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
|
||||
ctrlstat |= ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
|
||||
|
||||
platform_timeout timeout;
|
||||
platform_timeout_set(&timeout,200);
|
||||
/* Wait for acknowledge */
|
||||
while ((!platform_timeout_is_expired(&timeout)) &&
|
||||
(!((ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT)) & ADIV5_DP_CTRLSTAT_CDBGRSTACK))
|
||||
);
|
||||
|
||||
platform_timeout_set(&timeout, 101);
|
||||
/* Write request for debug reset release */
|
||||
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
|
||||
ctrlstat &= ~ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
|
||||
|
||||
platform_timeout_set(&timeout,200);
|
||||
/* Wait for acknowledge */
|
||||
while ((!platform_timeout_is_expired(&timeout)) &&
|
||||
(adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT) & ADIV5_DP_CTRLSTAT_CDBGRSTACK)
|
||||
);
|
||||
DEBUG("RESET_SEQ %s\n", (platform_timeout_is_expired(&timeout)) ? "failed": "succeeded");
|
||||
while(1) {
|
||||
platform_delay(20);
|
||||
ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
||||
if (ctrlstat & ADIV5_DP_CTRLSTAT_CDBGRSTACK) {
|
||||
DEBUG_INFO("RESET_SEQ succeeded.\n");
|
||||
break;
|
||||
}
|
||||
if (platform_timeout_is_expired(&timeout)) {
|
||||
DEBUG_INFO("RESET_SEQ failed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dp->dp_idcode = adiv5_dp_read(dp, ADIV5_DP_IDCODE);
|
||||
if ((dp->dp_idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
||||
uint32_t dp_idcode = adiv5_dp_read(dp, ADIV5_DP_IDCODE);
|
||||
if ((dp_idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
|
||||
/* Read TargetID. Can be done with device in WFI, sleep or reset!*/
|
||||
adiv5_dp_write(dp, ADIV5_DP_SELECT, ADIV5_DP_BANK2);
|
||||
dp->targetid = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
|
||||
adiv5_dp_write(dp, ADIV5_DP_SELECT, ADIV5_DP_BANK0);
|
||||
DEBUG("TARGETID %08" PRIx32 "\n", dp->targetid);
|
||||
DEBUG_INFO("TARGETID %08" PRIx32 "\n", dp->targetid);
|
||||
}
|
||||
/* Probe for APs on this DP */
|
||||
uint32_t last_base = 0;
|
||||
int void_aps = 0;
|
||||
for(int i = 0; (i < 256) && (void_aps < 8); i++) {
|
||||
ADIv5_AP_t *ap = NULL;
|
||||
if (adiv5_ap_setup(i))
|
||||
#if PC_HOSTED == 1
|
||||
if ((!dp->ap_setup) || dp->ap_setup(i))
|
||||
ap = adiv5_new_ap(dp, i);
|
||||
#else
|
||||
ap = adiv5_new_ap(dp, i);
|
||||
#endif
|
||||
if (ap == NULL) {
|
||||
void_aps++;
|
||||
adiv5_ap_cleanup(i);
|
||||
#if PC_HOSTED == 1
|
||||
if (dp->ap_cleanup)
|
||||
dp->ap_cleanup(i);
|
||||
#endif
|
||||
if (i == 0)
|
||||
return;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (ap->base == last_base) {
|
||||
DEBUG("AP %d: Duplicate base\n", i);
|
||||
adiv5_ap_cleanup(i);
|
||||
DEBUG_WARN("AP %d: Duplicate base\n", i);
|
||||
#if PC_HOSTED == 1
|
||||
if (dp->ap_cleanup)
|
||||
dp->ap_cleanup(i);
|
||||
#endif
|
||||
free(ap);
|
||||
/* FIXME: Should we expect valid APs behind duplicate ones? */
|
||||
return;
|
||||
}
|
||||
|
@ -546,7 +572,7 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||
/* The rest should only be added after checking ROM table */
|
||||
probed |= adiv5_component_probe(ap, ap->base, 0, 0);
|
||||
if (!probed && (dp->idcode & 0xfff) == 0x477) {
|
||||
DEBUG("-> cortexm_probe forced\n");
|
||||
DEBUG_INFO("-> cortexm_probe forced\n");
|
||||
cortexm_probe(ap, true);
|
||||
probed = true;
|
||||
}
|
||||
|
@ -557,11 +583,6 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
|
|||
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
|
||||
(((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE))
|
||||
|
||||
#if !defined(JTAG_HL)
|
||||
|
||||
bool adiv5_ap_setup(int i) {(void)i; return true;}
|
||||
void adiv5_ap_cleanup(int i) {(void)i;}
|
||||
|
||||
/* Program the CSW and TAR for sequencial access at a given width */
|
||||
static void ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
|
||||
{
|
||||
|
@ -584,7 +605,7 @@ static void ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
|
|||
}
|
||||
|
||||
/* Extract read data from data lane based on align and src address */
|
||||
static void * extract(void *dest, uint32_t src, uint32_t val, enum align align)
|
||||
void * extract(void *dest, uint32_t src, uint32_t val, enum align align)
|
||||
{
|
||||
switch (align) {
|
||||
case ALIGN_BYTE:
|
||||
|
@ -601,7 +622,7 @@ static void * extract(void *dest, uint32_t src, uint32_t val, enum align align)
|
|||
return (uint8_t *)dest + (1 << align);
|
||||
}
|
||||
|
||||
void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
void firmware_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
||||
{
|
||||
uint32_t tmp;
|
||||
uint32_t osrc = src;
|
||||
|
@ -631,8 +652,8 @@ void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
|
|||
extract(dest, src, tmp, align);
|
||||
}
|
||||
|
||||
void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
void firmware_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align)
|
||||
{
|
||||
uint32_t odest = dest;
|
||||
|
||||
|
@ -666,14 +687,14 @@ void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
|||
}
|
||||
}
|
||||
|
||||
void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
void firmware_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
|
||||
((uint32_t)ap->apsel << 24)|(addr & 0xF0));
|
||||
adiv5_dp_write(ap->dp, addr, value);
|
||||
}
|
||||
|
||||
uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
uint32_t firmware_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
adiv5_dp_write(ap->dp, ADIV5_DP_SELECT,
|
||||
|
@ -681,7 +702,6 @@ uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
|||
ret = adiv5_dp_read(ap->dp, addr);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len)
|
||||
{
|
||||
|
|
|
@ -129,12 +129,13 @@ enum align {
|
|||
ALIGN_DWORD = 3
|
||||
};
|
||||
|
||||
typedef struct ADIv5_AP_s ADIv5_AP_t;
|
||||
|
||||
/* Try to keep this somewhat absract for later adding SW-DP */
|
||||
typedef struct ADIv5_DP_s {
|
||||
int refcnt;
|
||||
|
||||
uint32_t idcode;
|
||||
uint32_t dp_idcode; /* Contains DPvX revision*/
|
||||
uint32_t targetid; /* Contains IDCODE for DPv2 devices.*/
|
||||
|
||||
uint32_t (*dp_read)(struct ADIv5_DP_s *dp, uint16_t addr);
|
||||
|
@ -143,12 +144,46 @@ typedef struct ADIv5_DP_s {
|
|||
uint16_t addr, uint32_t value);
|
||||
void (*abort)(struct ADIv5_DP_s *dp, uint32_t abort);
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
bool (*ap_setup)(int i);
|
||||
void (*ap_cleanup)(int i);
|
||||
void (*ap_regs_read)(ADIv5_AP_t *ap, void *data);
|
||||
uint32_t(*ap_reg_read)(ADIv5_AP_t *ap, int num);
|
||||
void (*ap_reg_write)(ADIv5_AP_t *ap, int num, uint32_t value);
|
||||
void (*read_block)(uint32_t addr, uint8_t *data, int size);
|
||||
void (*dap_write_block_sized)(uint32_t addr, uint8_t *data,
|
||||
int size, enum align align);
|
||||
|
||||
#endif
|
||||
uint32_t (*ap_read)(ADIv5_AP_t *ap, uint16_t addr);
|
||||
void (*ap_write)(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
|
||||
void (*mem_read)(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len);
|
||||
void (*mem_write_sized)(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align);
|
||||
#if PC_HOSTED == 1
|
||||
jtag_dev_t *dev;
|
||||
uint8_t fault;
|
||||
#else
|
||||
union {
|
||||
jtag_dev_t *dev;
|
||||
uint8_t fault;
|
||||
};
|
||||
#endif
|
||||
} ADIv5_DP_t;
|
||||
|
||||
struct ADIv5_AP_s {
|
||||
int refcnt;
|
||||
|
||||
ADIv5_DP_t *dp;
|
||||
uint8_t apsel;
|
||||
|
||||
uint32_t idr;
|
||||
uint32_t base;
|
||||
uint32_t csw;
|
||||
};
|
||||
|
||||
#if PC_HOSTED == 0
|
||||
static inline uint32_t adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
return dp->dp_read(dp, addr);
|
||||
|
@ -170,33 +205,75 @@ static inline void adiv5_dp_abort(struct ADIv5_DP_s *dp, uint32_t abort)
|
|||
return dp->abort(dp, abort);
|
||||
}
|
||||
|
||||
typedef struct ADIv5_AP_s {
|
||||
int refcnt;
|
||||
static inline uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
|
||||
{
|
||||
return ap->dp->ap_read(ap, addr);
|
||||
}
|
||||
|
||||
ADIv5_DP_t *dp;
|
||||
uint8_t apsel;
|
||||
static inline void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
|
||||
{
|
||||
return ap->dp->ap_write(ap, addr, value);
|
||||
}
|
||||
|
||||
uint32_t idr;
|
||||
uint32_t cfg;
|
||||
uint32_t base;
|
||||
uint32_t csw;
|
||||
} ADIv5_AP_t;
|
||||
static inline void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len)
|
||||
{
|
||||
return ap->dp->mem_read(ap, dest, src, len);
|
||||
}
|
||||
|
||||
static inline void adiv5_mem_write_sized(
|
||||
ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len,
|
||||
enum align align)
|
||||
{
|
||||
return ap->dp->mem_write_sized(ap, dest, src, len, align);
|
||||
}
|
||||
|
||||
static inline void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value)
|
||||
{
|
||||
dp->low_access(dp, ADIV5_LOW_WRITE, addr, value);
|
||||
}
|
||||
|
||||
#else
|
||||
uint32_t adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
uint32_t adiv5_dp_error(ADIv5_DP_t *dp);
|
||||
uint32_t adiv5_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
void adiv5_dp_abort(struct ADIv5_DP_s *dp, uint32_t abort);
|
||||
uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr);
|
||||
void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len);
|
||||
void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest,
|
||||
const void *src, size_t len, enum align align);
|
||||
void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value);
|
||||
#endif
|
||||
|
||||
void adiv5_dp_init(ADIv5_DP_t *dp);
|
||||
void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value);
|
||||
|
||||
void platform_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||
ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel);
|
||||
void adiv5_ap_ref(ADIv5_AP_t *ap);
|
||||
void adiv5_ap_unref(ADIv5_AP_t *ap);
|
||||
|
||||
void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr);
|
||||
|
||||
void adiv5_jtag_dp_handler(jtag_dev_t *dev);
|
||||
int platform_jtag_dp_init(ADIv5_DP_t *dp);
|
||||
|
||||
void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len);
|
||||
void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len);
|
||||
void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align);
|
||||
uint64_t adiv5_ap_read_pidr(ADIv5_AP_t *ap, uint32_t addr);
|
||||
void * extract(void *dest, uint32_t src, uint32_t val, enum align align);
|
||||
|
||||
void firmware_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src,
|
||||
size_t len, enum align align);
|
||||
void firmware_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src,
|
||||
size_t len);
|
||||
void firmware_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value);
|
||||
uint32_t firmware_ap_read(ADIv5_AP_t *ap, uint16_t addr);
|
||||
uint32_t firmware_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
uint32_t fw_adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
uint32_t firmware_swdp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
uint32_t fw_adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
|
||||
uint32_t firmware_swdp_error(ADIv5_DP_t *dp);
|
||||
|
||||
void firmware_swdp_abort(ADIv5_DP_t *dp, uint32_t abort);
|
||||
#endif
|
||||
|
|
|
@ -37,49 +37,44 @@
|
|||
#define IR_DPACC 0xA
|
||||
#define IR_APACC 0xB
|
||||
|
||||
static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
|
||||
static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp);
|
||||
|
||||
static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
|
||||
static void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort);
|
||||
|
||||
void adiv5_jtag_dp_handler(jtag_dev_t *dev)
|
||||
{
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!dp) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dp->dev = dev;
|
||||
dp->idcode = dev->idcode;
|
||||
|
||||
dp->dp_read = adiv5_jtagdp_read;
|
||||
dp->error = adiv5_jtagdp_error;
|
||||
dp->low_access = adiv5_jtagdp_low_access;
|
||||
dp->abort = adiv5_jtagdp_abort;
|
||||
|
||||
if ((PC_HOSTED == 0 ) || (!platform_jtag_dp_init(dp))) {
|
||||
dp->idcode = dev->idcode;
|
||||
dp->dp_read = fw_adiv5_jtagdp_read;
|
||||
dp->error = adiv5_jtagdp_error;
|
||||
dp->low_access = fw_adiv5_jtagdp_low_access;
|
||||
dp->abort = adiv5_jtagdp_abort;
|
||||
}
|
||||
adiv5_dp_init(dp);
|
||||
}
|
||||
|
||||
static uint32_t adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
uint32_t fw_adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
return adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ,
|
||||
fw_adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
return fw_adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ,
|
||||
ADIV5_DP_RDBUFF, 0);
|
||||
}
|
||||
|
||||
static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, ADIV5_DP_CTRLSTAT, 0);
|
||||
return adiv5_jtagdp_low_access(dp, ADIV5_LOW_WRITE,
|
||||
fw_adiv5_jtagdp_low_access(dp, ADIV5_LOW_READ, ADIV5_DP_CTRLSTAT, 0);
|
||||
return fw_adiv5_jtagdp_low_access(dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_DP_CTRLSTAT, 0xF0000032) & 0x32;
|
||||
}
|
||||
|
||||
static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint32_t fw_adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
|
@ -90,11 +85,12 @@ static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||
|
||||
request = ((uint64_t)value << 3) | ((addr >> 1) & 0x06) | (RnW?1:0);
|
||||
|
||||
jtag_dev_write_ir(dp->dev, APnDP ? IR_APACC : IR_DPACC);
|
||||
jtag_dev_write_ir(&jtag_proc, dp->dev, APnDP ? IR_APACC : IR_DPACC);
|
||||
|
||||
platform_timeout_set(&timeout, 2000);
|
||||
do {
|
||||
jtag_dev_shift_dr(dp->dev, (uint8_t*)&response, (uint8_t*)&request, 35);
|
||||
jtag_dev_shift_dr(&jtag_proc, dp->dev, (uint8_t*)&response,
|
||||
(uint8_t*)&request, 35);
|
||||
ack = response & 0x07;
|
||||
} while(!platform_timeout_is_expired(&timeout) && (ack == JTAGDP_ACK_WAIT));
|
||||
|
||||
|
@ -110,6 +106,6 @@ static uint32_t adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||
static void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
{
|
||||
uint64_t request = (uint64_t)abort << 3;
|
||||
jtag_dev_write_ir(dp->dev, IR_ABORT);
|
||||
jtag_dev_shift_dr(dp->dev, NULL, (const uint8_t*)&request, 35);
|
||||
jtag_dev_write_ir(&jtag_proc, dp->dev, IR_ABORT);
|
||||
jtag_dev_shift_dr(&jtag_proc, dp->dev, NULL, (const uint8_t*)&request, 35);
|
||||
}
|
||||
|
|
|
@ -33,15 +33,6 @@
|
|||
#define SWDP_ACK_WAIT 0x02
|
||||
#define SWDP_ACK_FAULT 0x04
|
||||
|
||||
static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr);
|
||||
|
||||
static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp);
|
||||
|
||||
static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value);
|
||||
|
||||
static void adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort);
|
||||
|
||||
int adiv5_swdp_scan(void)
|
||||
{
|
||||
uint32_t ack;
|
||||
|
@ -49,60 +40,64 @@ int adiv5_swdp_scan(void)
|
|||
target_list_free();
|
||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||
if (!dp) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if PC_HOSTED == 1
|
||||
if (platform_swdptap_init())
|
||||
#else
|
||||
if (swdptap_init())
|
||||
#endif
|
||||
return -1;
|
||||
|
||||
/* Switch from JTAG to SWD mode */
|
||||
swdptap_seq_out(0xFFFFFFFF, 16);
|
||||
swdptap_seq_out(0xFFFFFFFF, 32);
|
||||
swdptap_seq_out(0xFFFFFFFF, 18);
|
||||
swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
|
||||
swdptap_seq_out(0xFFFFFFFF, 32);
|
||||
swdptap_seq_out(0xFFFFFFFF, 18);
|
||||
swdptap_seq_out(0, 16);
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 16);
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 18);
|
||||
swd_proc.swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 32);
|
||||
swd_proc.swdptap_seq_out(0xFFFFFFFF, 18);
|
||||
swd_proc.swdptap_seq_out(0, 16);
|
||||
|
||||
/* Read the SW-DP IDCODE register to syncronise */
|
||||
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
||||
* allow the ack to be checked here. */
|
||||
swdptap_seq_out(0xA5, 8);
|
||||
ack = swdptap_seq_in(3);
|
||||
if((ack != SWDP_ACK_OK) || swdptap_seq_in_parity(&dp->idcode, 32)) {
|
||||
DEBUG("\n");
|
||||
swd_proc.swdptap_seq_out(0xA5, 8);
|
||||
ack = swd_proc.swdptap_seq_in(3);
|
||||
if((ack != SWDP_ACK_OK) || swd_proc.swdptap_seq_in_parity(&dp->idcode, 32)) {
|
||||
DEBUG_WARN("Read SW-DP IDCODE failed %1" PRIx32 "\n", ack);
|
||||
free(dp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dp->dp_read = adiv5_swdp_read;
|
||||
dp->error = adiv5_swdp_error;
|
||||
dp->low_access = adiv5_swdp_low_access;
|
||||
dp->abort = adiv5_swdp_abort;
|
||||
dp->dp_read = firmware_swdp_read;
|
||||
dp->error = firmware_swdp_error;
|
||||
dp->low_access = firmware_swdp_low_access;
|
||||
dp->abort = firmware_swdp_abort;
|
||||
|
||||
adiv5_swdp_error(dp);
|
||||
firmware_swdp_error(dp);
|
||||
adiv5_dp_init(dp);
|
||||
|
||||
return target_list?1:0;
|
||||
}
|
||||
|
||||
static uint32_t adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
uint32_t firmware_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
||||
{
|
||||
if (addr & ADIV5_APnDP) {
|
||||
adiv5_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
return adiv5_dp_low_access(dp, ADIV5_LOW_READ,
|
||||
ADIV5_DP_RDBUFF, 0);
|
||||
} else {
|
||||
return adiv5_swdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
return firmware_swdp_low_access(dp, ADIV5_LOW_READ, addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp)
|
||||
uint32_t firmware_swdp_error(ADIv5_DP_t *dp)
|
||||
{
|
||||
uint32_t err, clr = 0;
|
||||
|
||||
err = adiv5_swdp_read(dp, ADIV5_DP_CTRLSTAT) &
|
||||
err = firmware_swdp_read(dp, ADIV5_DP_CTRLSTAT) &
|
||||
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
|
||||
ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR);
|
||||
|
||||
|
@ -121,7 +116,7 @@ static uint32_t adiv5_swdp_error(ADIv5_DP_t *dp)
|
|||
return err;
|
||||
}
|
||||
|
||||
static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint32_t firmware_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
||||
uint16_t addr, uint32_t value)
|
||||
{
|
||||
bool APnDP = addr & ADIV5_APnDP;
|
||||
|
@ -143,8 +138,8 @@ static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||
|
||||
platform_timeout_set(&timeout, 2000);
|
||||
do {
|
||||
swdptap_seq_out(request, 8);
|
||||
ack = swdptap_seq_in(3);
|
||||
swd_proc.swdptap_seq_out(request, 8);
|
||||
ack = swd_proc.swdptap_seq_in(3);
|
||||
} while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout));
|
||||
|
||||
if (ack == SWDP_ACK_WAIT)
|
||||
|
@ -159,10 +154,10 @@ static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||
raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK");
|
||||
|
||||
if(RnW) {
|
||||
if(swdptap_seq_in_parity(&response, 32)) /* Give up on parity error */
|
||||
if(swd_proc.swdptap_seq_in_parity(&response, 32)) /* Give up on parity error */
|
||||
raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
|
||||
} else {
|
||||
swdptap_seq_out_parity(value, 32);
|
||||
swd_proc.swdptap_seq_out_parity(value, 32);
|
||||
/* RM0377 Rev. 8 Chapter 27.5.4 for STM32L0x1 states:
|
||||
* Because of the asynchronous clock domains SWCLK and HCLK,
|
||||
* two extra SWCLK cycles are needed after a write transaction
|
||||
|
@ -173,13 +168,13 @@ static uint32_t adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
|
|||
* for a power-up request. If the next transaction (requiring
|
||||
* a power-up) occurs immediately, it will fail.
|
||||
*/
|
||||
swdptap_seq_out(0, 2);
|
||||
swd_proc.swdptap_seq_out(0, 2);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
void firmware_swdp_abort(ADIv5_DP_t *dp, uint32_t abort)
|
||||
{
|
||||
adiv5_dp_write(dp, ADIV5_DP_ABORT, abort);
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ static uint32_t va_to_pa(target *t, uint32_t va)
|
|||
if (par & 1)
|
||||
priv->mmu_fault = true;
|
||||
uint32_t pa = (par & ~0xfff) | (va & 0xfff);
|
||||
DEBUG("%s: VA = 0x%08"PRIx32", PAR = 0x%08"PRIx32", PA = 0x%08"PRIX32"\n",
|
||||
DEBUG_INFO("%s: VA = 0x%08"PRIx32", PAR = 0x%08"PRIx32", PA = 0x%08"PRIX32"\n",
|
||||
__func__, va, par, pa);
|
||||
return pa;
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
|
|||
adiv5_ap_ref(apb);
|
||||
struct cortexa_priv *priv = calloc(1, sizeof(*priv));
|
||||
if (!priv) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ bool cortexa_attach(target *t)
|
|||
dbgdscr |= DBGDSCR_HDBGEN | DBGDSCR_ITREN;
|
||||
dbgdscr = (dbgdscr & ~DBGDSCR_EXTDCCMODE_MASK) | DBGDSCR_EXTDCCMODE_STALL;
|
||||
apb_write(t, DBGDSCR, dbgdscr);
|
||||
DEBUG("DBGDSCR = 0x%08"PRIx32"\n", dbgdscr);
|
||||
DEBUG_INFO("DBGDSCR = 0x%08"PRIx32"\n", dbgdscr);
|
||||
|
||||
target_halt_request(t);
|
||||
tries = 10;
|
||||
|
@ -630,7 +630,7 @@ static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch)
|
|||
if (!(dbgdscr & DBGDSCR_HALTED)) /* Not halted */
|
||||
return TARGET_HALT_RUNNING;
|
||||
|
||||
DEBUG("%s: DBGDSCR = 0x%08"PRIx32"\n", __func__, dbgdscr);
|
||||
DEBUG_INFO("%s: DBGDSCR = 0x%08"PRIx32"\n", __func__, dbgdscr);
|
||||
/* Reenable DBGITR */
|
||||
dbgdscr |= DBGDSCR_ITREN;
|
||||
apb_write(t, DBGDSCR, dbgdscr);
|
||||
|
@ -657,7 +657,7 @@ void cortexa_halt_resume(target *t, bool step)
|
|||
if (step) {
|
||||
uint32_t addr = priv->reg_cache.r[15];
|
||||
uint32_t bas = bp_bas(addr, (priv->reg_cache.cpsr & CPSR_THUMB) ? 2 : 4);
|
||||
DEBUG("step 0x%08"PRIx32" %"PRIx32"\n", addr, bas);
|
||||
DEBUG_INFO("step 0x%08"PRIx32" %"PRIx32"\n", addr, bas);
|
||||
/* Set match any breakpoint */
|
||||
apb_write(t, DBGBVR(0), priv->reg_cache.r[15] & ~3);
|
||||
apb_write(t, DBGBCR(0), DBGBCR_INST_MISMATCH | bas |
|
||||
|
@ -693,7 +693,7 @@ void cortexa_halt_resume(target *t, bool step)
|
|||
do {
|
||||
apb_write(t, DBGDRCR, DBGDRCR_CSE | DBGDRCR_RRQ);
|
||||
dbgdscr = apb_read(t, DBGDSCR);
|
||||
DEBUG("%s: DBGDSCR = 0x%08"PRIx32"\n", __func__, dbgdscr);
|
||||
DEBUG_INFO("%s: DBGDSCR = 0x%08"PRIx32"\n", __func__, dbgdscr);
|
||||
} while (!(dbgdscr & DBGDSCR_RESTARTED) &&
|
||||
!platform_timeout_is_expired(&to));
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2012 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* and Koen De Vleeschauwer.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>,
|
||||
* Koen De Vleeschauwer and Uwe Bonne
|
||||
*
|
||||
* 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
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef PC_HOSTED
|
||||
#if PC_HOSTED == 1
|
||||
|
||||
/*
|
||||
* pc-hosted semihosting does keyboard, file and screen i/o on the system
|
||||
|
@ -296,7 +296,7 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
|
|||
uint32_t identity = ap->idr & 0xff;
|
||||
struct cortexm_priv *priv = calloc(1, sizeof(*priv));
|
||||
if (!priv) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -478,88 +478,98 @@ static void cortexm_regs_read(target *t, void *data)
|
|||
uint32_t *regs = data;
|
||||
ADIv5_AP_t *ap = cortexm_ap(t);
|
||||
unsigned i;
|
||||
#if defined(STLINKV2)
|
||||
uint32_t base_regs[21];
|
||||
extern void stlink_regs_read(ADIv5_AP_t *ap, void *data);
|
||||
extern uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx);
|
||||
stlink_regs_read(ap, base_regs);
|
||||
for(i = 0; i < sizeof(regnum_cortex_m) / 4; i++)
|
||||
*regs++ = base_regs[regnum_cortex_m[i]];
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(size_t t = 0; t < sizeof(regnum_cortex_mf) / 4; t++)
|
||||
*regs++ = stlink_reg_read(ap, regnum_cortex_mf[t]);
|
||||
#else
|
||||
/* FIXME: Describe what's really going on here */
|
||||
adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
|
||||
|
||||
/* Map the banked data registers (0x10-0x1c) to the
|
||||
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR);
|
||||
|
||||
/* Walk the regnum_cortex_m array, reading the registers it
|
||||
* calls out. */
|
||||
adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRSR), regnum_cortex_m[0]); /* Required to switch banks */
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
regnum_cortex_m[i]);
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
#if PC_HOSTED == 1
|
||||
if ((ap->dp->ap_reg_read) && (ap->dp->ap_regs_read)) {
|
||||
uint32_t base_regs[21];
|
||||
ap->dp->ap_regs_read(ap, base_regs);
|
||||
for(i = 0; i < sizeof(regnum_cortex_m) / 4; i++)
|
||||
*regs++ = base_regs[regnum_cortex_m[i]];
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(size_t t = 0; t < sizeof(regnum_cortex_mf) / 4; t++)
|
||||
*regs++ = ap->dp->ap_reg_read(ap, regnum_cortex_mf[t]);
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRSR),
|
||||
regnum_cortex_mf[i]);
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
}
|
||||
#else
|
||||
if (0) {}
|
||||
#endif
|
||||
else {
|
||||
/* FIXME: Describe what's really going on here */
|
||||
adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
|
||||
|
||||
/* Map the banked data registers (0x10-0x1c) to the
|
||||
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR,
|
||||
CORTEXM_DHCSR);
|
||||
|
||||
/* Walk the regnum_cortex_m array, reading the registers it
|
||||
* calls out. */
|
||||
adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRSR), regnum_cortex_m[0]);
|
||||
/* Required to switch banks */
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
regnum_cortex_m[i]);
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRSR),
|
||||
regnum_cortex_mf[i]);
|
||||
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cortexm_regs_write(target *t, const void *data)
|
||||
{
|
||||
const uint32_t *regs = data;
|
||||
ADIv5_AP_t *ap = cortexm_ap(t);
|
||||
#if defined(STLINKV2)
|
||||
extern void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val);
|
||||
for(size_t z = 0; z < sizeof(regnum_cortex_m) / 4; z++) {
|
||||
stlink_reg_write(ap, regnum_cortex_m[z], *regs);
|
||||
regs++;
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(size_t z = 0; z < sizeof(regnum_cortex_mf) / 4; z++) {
|
||||
stlink_reg_write(ap, regnum_cortex_mf[z], *regs);
|
||||
#if PC_HOSTED == 1
|
||||
if (ap->dp->ap_reg_write) {
|
||||
for (size_t z = 0; z < sizeof(regnum_cortex_m) / 4; z++) {
|
||||
ap->dp->ap_reg_write(ap, regnum_cortex_m[z], *regs);
|
||||
regs++;
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(size_t z = 0; z < sizeof(regnum_cortex_mf) / 4; z++) {
|
||||
ap->dp->ap_reg_write(ap, regnum_cortex_mf[z], *regs);
|
||||
regs++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
unsigned i;
|
||||
|
||||
/* FIXME: Describe what's really going on here */
|
||||
adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
|
||||
|
||||
/* Map the banked data registers (0x10-0x1c) to the
|
||||
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR);
|
||||
|
||||
/* Walk the regnum_cortex_m array, writing the registers it
|
||||
* calls out. */
|
||||
adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRDR), *regs++); /* Required to switch banks */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_m[0]);
|
||||
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRDR), *regs++);
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_m[i]);
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRDR), *regs++);
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_mf[i]);
|
||||
}
|
||||
if (0) {}
|
||||
#endif
|
||||
else {
|
||||
unsigned i;
|
||||
|
||||
/* FIXME: Describe what's really going on here */
|
||||
adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD);
|
||||
|
||||
/* Map the banked data registers (0x10-0x1c) to the
|
||||
* debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR,
|
||||
CORTEXM_DHCSR);
|
||||
/* Walk the regnum_cortex_m array, writing the registers it
|
||||
* calls out. */
|
||||
adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRDR), *regs++);
|
||||
/* Required to switch banks */
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_m[0]);
|
||||
for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRDR), *regs++);
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_m[i]);
|
||||
}
|
||||
if (t->target_options & TOPT_FLAVOUR_V7MF)
|
||||
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) {
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRDR), *regs++);
|
||||
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE,
|
||||
ADIV5_AP_DB(DB_DCRSR),
|
||||
0x10000 | regnum_cortex_mf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cortexm_mem_write_sized(
|
||||
|
@ -647,7 +657,7 @@ static void cortexm_reset(target *t)
|
|||
!platform_timeout_is_expired(&to));
|
||||
#if defined(PLATFORM_HAS_DEBUG)
|
||||
if (platform_timeout_is_expired(&to))
|
||||
DEBUG("Reset seem to be stuck low!\n");
|
||||
DEBUG_WARN("Reset seem to be stuck low!\n");
|
||||
#endif
|
||||
/* 10 ms delay to ensure that things such as the STM32 HSI clock
|
||||
* have started up fully. */
|
||||
|
@ -1067,14 +1077,14 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[])
|
|||
#define SYS_WRITEC 0x03
|
||||
#define SYS_WRITE0 0x04
|
||||
|
||||
#if !defined(PC_HOSTED)
|
||||
#if PC_HOSTED == 0
|
||||
/* probe memory access functions */
|
||||
static void probe_mem_read(target *t __attribute__((unused)), void *probe_dest, target_addr target_src, size_t len)
|
||||
{
|
||||
uint8_t *dst = (uint8_t *)probe_dest;
|
||||
uint8_t *src = (uint8_t *)target_src;
|
||||
|
||||
DEBUG("probe_mem_read\n");
|
||||
DEBUG_INFO("probe_mem_read\n");
|
||||
while (len--) *dst++=*src++;
|
||||
return;
|
||||
}
|
||||
|
@ -1084,7 +1094,7 @@ static void probe_mem_write(target *t __attribute__((unused)), target_addr targe
|
|||
uint8_t *dst = (uint8_t *)target_dest;
|
||||
uint8_t *src = (uint8_t *)probe_src;
|
||||
|
||||
DEBUG("probe_mem_write\n");
|
||||
DEBUG_INFO("probe_mem_write\n");
|
||||
while (len--) *dst++=*src++;
|
||||
return;
|
||||
}
|
||||
|
@ -1101,10 +1111,10 @@ static int cortexm_hostio_request(target *t)
|
|||
uint32_t syscall = arm_regs[0];
|
||||
int32_t ret = 0;
|
||||
|
||||
DEBUG("syscall 0"PRIx32"%"PRIx32" (%"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32")\n",
|
||||
DEBUG_INFO("syscall 0"PRIx32"%"PRIx32" (%"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32")\n",
|
||||
syscall, params[0], params[1], params[2], params[3]);
|
||||
switch (syscall) {
|
||||
#if defined(PC_HOSTED)
|
||||
#if PC_HOSTED == 1
|
||||
|
||||
/* code that runs in pc-hosted process. use linux system calls. */
|
||||
|
||||
|
|
|
@ -543,7 +543,7 @@ static void efm32_add_flash(target *t, target_addr addr, size_t length,
|
|||
{
|
||||
struct target_flash *f = calloc(1, sizeof(*f));
|
||||
if (!f) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -720,11 +720,11 @@ static int efm32_flash_write(struct target_flash *f,
|
|||
int ret = cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len,
|
||||
device->msc_addr);
|
||||
|
||||
#ifdef PLATFORM_HAS_DEBUG
|
||||
#ifdef ENABLE_DEBUG
|
||||
/* Check the MSC_IF */
|
||||
uint32_t msc = device->msc_addr;
|
||||
uint32_t msc_if = target_mem_read32(t, EFM32_MSC_IF(msc));
|
||||
DEBUG("EFM32: Flash write done MSC_IF=%08"PRIx32"\n", msc_if);
|
||||
DEBUG_INFO("EFM32: Flash write done MSC_IF=%08"PRIx32"\n", msc_if);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
@ -985,7 +985,7 @@ void efm32_aap_probe(ADIv5_AP_t *ap)
|
|||
{
|
||||
if ((ap->idr & EFM32_APP_IDR_MASK) == EFM32_AAP_IDR) {
|
||||
/* It's an EFM32 AAP! */
|
||||
DEBUG("EFM32: Found EFM32 AAP\n");
|
||||
DEBUG_INFO("EFM32: Found EFM32 AAP\n");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -1002,7 +1002,7 @@ void efm32_aap_probe(ADIv5_AP_t *ap)
|
|||
//efm32_aap_cmd_device_erase(t);
|
||||
|
||||
/* Read status */
|
||||
DEBUG("EFM32: AAP STATUS=%08"PRIx32"\n", adiv5_ap_read(ap, AAP_STATUS));
|
||||
DEBUG_INFO("EFM32: AAP STATUS=%08"PRIx32"\n", adiv5_ap_read(ap, AAP_STATUS));
|
||||
|
||||
sprintf(aap_driver_string,
|
||||
"EFM32 Authentication Access Port rev.%d",
|
||||
|
@ -1032,15 +1032,15 @@ static bool efm32_aap_cmd_device_erase(target *t, int argc, const char **argv)
|
|||
|
||||
/* Read status */
|
||||
status = adiv5_ap_read(ap, AAP_STATUS);
|
||||
DEBUG("EFM32: AAP STATUS=%08"PRIx32"\n", status);
|
||||
DEBUG_INFO("EFM32: AAP STATUS=%08"PRIx32"\n", status);
|
||||
|
||||
if (status & AAP_STATUS_ERASEBUSY) {
|
||||
DEBUG("EFM32: AAP Erase in progress\n");
|
||||
DEBUG("EFM32: -> ABORT\n");
|
||||
DEBUG_WARN("EFM32: AAP Erase in progress\n");
|
||||
DEBUG_WARN("EFM32: -> ABORT\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG("EFM32: Issuing DEVICEERASE...\n");
|
||||
DEBUG_INFO("EFM32: Issuing DEVICEERASE...\n");
|
||||
adiv5_ap_write(ap, AAP_CMDKEY, CMDKEY);
|
||||
adiv5_ap_write(ap, AAP_CMD, 1);
|
||||
|
||||
|
@ -1051,7 +1051,7 @@ static bool efm32_aap_cmd_device_erase(target *t, int argc, const char **argv)
|
|||
|
||||
/* Read status */
|
||||
status = adiv5_ap_read(ap, AAP_STATUS);
|
||||
DEBUG("EFM32: AAP STATUS=%08"PRIx32"\n", status);
|
||||
DEBUG_INFO("EFM32: AAP STATUS=%08"PRIx32"\n", status);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -66,13 +66,20 @@ int jtag_scan(const uint8_t *irlens)
|
|||
/* Run throught the SWD to JTAG sequence for the case where an attached SWJ-DP is
|
||||
* in SW-DP mode.
|
||||
*/
|
||||
DEBUG("Resetting TAP\n");
|
||||
DEBUG_INFO("Resetting TAP\n");
|
||||
#if PC_HOSTED == 1
|
||||
if (platform_jtagtap_init()) {
|
||||
DEBUG_WARN("JTAG not available\n");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
jtagtap_init();
|
||||
jtagtap_reset();
|
||||
#endif
|
||||
jtag_proc.jtagtap_reset();
|
||||
|
||||
if (irlens) {
|
||||
DEBUG("Given list of IR lengths, skipping probe\n");
|
||||
DEBUG("Change state to Shift-IR\n");
|
||||
DEBUG_WARN("Given list of IR lengths, skipping probe\n");
|
||||
DEBUG_INFO("Change state to Shift-IR\n");
|
||||
jtagtap_shift_ir();
|
||||
j = 0;
|
||||
while((jtag_dev_count <= JTAG_MAX_DEVS) &&
|
||||
|
@ -80,9 +87,9 @@ int jtag_scan(const uint8_t *irlens)
|
|||
uint32_t irout;
|
||||
if(*irlens == 0)
|
||||
break;
|
||||
jtagtap_tdi_tdo_seq((uint8_t*)&irout, 0, ones, *irlens);
|
||||
jtag_proc.jtagtap_tdi_tdo_seq((uint8_t*)&irout, 0, ones, *irlens);
|
||||
if (!(irout & 1)) {
|
||||
DEBUG("check failed: IR[0] != 1\n");
|
||||
DEBUG_WARN("check failed: IR[0] != 1\n");
|
||||
return -1;
|
||||
}
|
||||
jtag_devs[jtag_dev_count].ir_len = *irlens;
|
||||
|
@ -93,19 +100,20 @@ int jtag_scan(const uint8_t *irlens)
|
|||
jtag_dev_count++;
|
||||
}
|
||||
} else {
|
||||
DEBUG("Change state to Shift-IR\n");
|
||||
DEBUG_INFO("Change state to Shift-IR\n");
|
||||
jtagtap_shift_ir();
|
||||
|
||||
DEBUG("Scanning out IRs\n");
|
||||
if(!jtagtap_next(0, 1)) {
|
||||
DEBUG("jtag_scan: Sanity check failed: IR[0] shifted out as 0\n");
|
||||
DEBUG_INFO("Scanning out IRs\n");
|
||||
if(!jtag_proc.jtagtap_next(0, 1)) {
|
||||
DEBUG_WARN("jtag_scan: Sanity check failed: IR[0] shifted out "
|
||||
"as 0\n");
|
||||
jtag_dev_count = -1;
|
||||
return -1; /* must be 1 */
|
||||
}
|
||||
jtag_devs[0].ir_len = 1; j = 1;
|
||||
while((jtag_dev_count <= JTAG_MAX_DEVS) &&
|
||||
(jtag_devs[jtag_dev_count].ir_len <= JTAG_MAX_IR_LEN)) {
|
||||
if(jtagtap_next(0, 1)) {
|
||||
if(jtag_proc.jtagtap_next(0, 1)) {
|
||||
if(jtag_devs[jtag_dev_count].ir_len == 1) break;
|
||||
jtag_devs[++jtag_dev_count].ir_len = 1;
|
||||
jtag_devs[jtag_dev_count].ir_prescan = j;
|
||||
|
@ -114,38 +122,38 @@ int jtag_scan(const uint8_t *irlens)
|
|||
j++;
|
||||
}
|
||||
if(jtag_dev_count > JTAG_MAX_DEVS) {
|
||||
DEBUG("jtag_scan: Maximum device count exceeded\n");
|
||||
DEBUG_WARN("jtag_scan: Maximum device count exceeded\n");
|
||||
jtag_dev_count = -1;
|
||||
return -1;
|
||||
}
|
||||
if(jtag_devs[jtag_dev_count].ir_len > JTAG_MAX_IR_LEN) {
|
||||
DEBUG("jtag_scan: Maximum IR length exceeded\n");
|
||||
DEBUG_WARN("jtag_scan: Maximum IR length exceeded\n");
|
||||
jtag_dev_count = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("Return to Run-Test/Idle\n");
|
||||
jtagtap_next(1, 1);
|
||||
DEBUG_INFO("Return to Run-Test/Idle\n");
|
||||
jtag_proc.jtagtap_next(1, 1);
|
||||
jtagtap_return_idle();
|
||||
|
||||
/* All devices should be in BYPASS now */
|
||||
|
||||
/* Count device on chain */
|
||||
DEBUG("Change state to Shift-DR\n");
|
||||
DEBUG_INFO("Change state to Shift-DR\n");
|
||||
jtagtap_shift_dr();
|
||||
for(i = 0; (jtagtap_next(0, 1) == 0) && (i <= jtag_dev_count); i++)
|
||||
for(i = 0; (jtag_proc.jtagtap_next(0, 1) == 0) && (i <= jtag_dev_count); i++)
|
||||
jtag_devs[i].dr_postscan = jtag_dev_count - i - 1;
|
||||
|
||||
if(i != jtag_dev_count) {
|
||||
DEBUG("jtag_scan: Sanity check failed: "
|
||||
DEBUG_WARN("jtag_scan: Sanity check failed: "
|
||||
"BYPASS dev count doesn't match IR scan\n");
|
||||
jtag_dev_count = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("Return to Run-Test/Idle\n");
|
||||
jtagtap_next(1, 1);
|
||||
DEBUG_INFO("Return to Run-Test/Idle\n");
|
||||
jtag_proc.jtagtap_next(1, 1);
|
||||
jtagtap_return_idle();
|
||||
if(!jtag_dev_count) {
|
||||
return 0;
|
||||
|
@ -157,17 +165,17 @@ int jtag_scan(const uint8_t *irlens)
|
|||
jtag_devs[i].ir_len;
|
||||
|
||||
/* Reset jtagtap: should take all devs to IDCODE */
|
||||
jtagtap_reset();
|
||||
jtag_proc.jtagtap_reset();
|
||||
jtagtap_shift_dr();
|
||||
for(i = 0; i < jtag_dev_count; i++) {
|
||||
if(!jtagtap_next(0, 1)) continue;
|
||||
if(!jtag_proc.jtagtap_next(0, 1)) continue;
|
||||
jtag_devs[i].idcode = 1;
|
||||
for(j = 2; j; j <<= 1)
|
||||
if(jtagtap_next(0, 1)) jtag_devs[i].idcode |= j;
|
||||
if(jtag_proc.jtagtap_next(0, 1)) jtag_devs[i].idcode |= j;
|
||||
|
||||
}
|
||||
DEBUG("Return to Run-Test/Idle\n");
|
||||
jtagtap_next(1, 1);
|
||||
DEBUG_INFO("Return to Run-Test/Idle\n");
|
||||
jtag_proc.jtagtap_next(1, 1);
|
||||
jtagtap_return_idle();
|
||||
|
||||
/* Check for known devices and handle accordingly */
|
||||
|
@ -187,7 +195,7 @@ int jtag_scan(const uint8_t *irlens)
|
|||
return jtag_dev_count;
|
||||
}
|
||||
|
||||
void jtag_dev_write_ir(jtag_dev_t *d, uint32_t ir)
|
||||
void jtag_dev_write_ir(jtag_proc_t *jp, jtag_dev_t *d, uint32_t ir)
|
||||
{
|
||||
if(ir == d->current_ir) return;
|
||||
for(int i = 0; i < jtag_dev_count; i++)
|
||||
|
@ -195,21 +203,21 @@ void jtag_dev_write_ir(jtag_dev_t *d, uint32_t ir)
|
|||
d->current_ir = ir;
|
||||
|
||||
jtagtap_shift_ir();
|
||||
jtagtap_tdi_seq(0, ones, d->ir_prescan);
|
||||
jtagtap_tdi_seq(d->ir_postscan?0:1, (void*)&ir, d->ir_len);
|
||||
jtagtap_tdi_seq(1, ones, d->ir_postscan);
|
||||
jp->jtagtap_tdi_seq(0, ones, d->ir_prescan);
|
||||
jp->jtagtap_tdi_seq(d->ir_postscan?0:1, (void*)&ir, d->ir_len);
|
||||
jp->jtagtap_tdi_seq(1, ones, d->ir_postscan);
|
||||
jtagtap_return_idle();
|
||||
}
|
||||
|
||||
void jtag_dev_shift_dr(jtag_dev_t *d, uint8_t *dout, const uint8_t *din, int ticks)
|
||||
void jtag_dev_shift_dr(jtag_proc_t *jp, jtag_dev_t *d, uint8_t *dout, const uint8_t *din, int ticks)
|
||||
{
|
||||
jtagtap_shift_dr();
|
||||
jtagtap_tdi_seq(0, ones, d->dr_prescan);
|
||||
jp->jtagtap_tdi_seq(0, ones, d->dr_prescan);
|
||||
if(dout)
|
||||
jtagtap_tdi_tdo_seq((void*)dout, d->dr_postscan?0:1, (void*)din, ticks);
|
||||
jp->jtagtap_tdi_tdo_seq((void*)dout, d->dr_postscan?0:1, (void*)din, ticks);
|
||||
else
|
||||
jtagtap_tdi_seq(d->dr_postscan?0:1, (void*)din, ticks);
|
||||
jtagtap_tdi_seq(1, ones, d->dr_postscan);
|
||||
jp->jtagtap_tdi_seq(d->dr_postscan?0:1, (void*)din, ticks);
|
||||
jp->jtagtap_tdi_seq(1, ones, d->dr_postscan);
|
||||
jtagtap_return_idle();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <jtagtap.h>
|
||||
|
||||
#ifndef __JTAG_SCAN_H
|
||||
#define __JTAG_SCAN_H
|
||||
|
@ -25,7 +26,6 @@
|
|||
#define JTAG_MAX_IR_LEN 16
|
||||
|
||||
typedef struct jtag_dev_s {
|
||||
#if !defined(JTAG_HL)
|
||||
union {
|
||||
uint8_t dev;
|
||||
uint8_t dr_prescan;
|
||||
|
@ -35,20 +35,16 @@ typedef struct jtag_dev_s {
|
|||
uint8_t ir_len;
|
||||
uint8_t ir_prescan;
|
||||
uint8_t ir_postscan;
|
||||
#endif
|
||||
uint32_t idcode;
|
||||
const char *descr;
|
||||
#if !defined(JTAG_HL)
|
||||
uint32_t current_ir;
|
||||
#endif
|
||||
|
||||
} jtag_dev_t;
|
||||
|
||||
extern struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1];
|
||||
extern int jtag_dev_count;
|
||||
|
||||
void jtag_dev_write_ir(jtag_dev_t *dev, uint32_t ir);
|
||||
void jtag_dev_shift_dr(jtag_dev_t *dev, uint8_t *dout, const uint8_t *din, int ticks);
|
||||
void jtag_dev_write_ir(jtag_proc_t *jp, jtag_dev_t *dev, uint32_t ir);
|
||||
void jtag_dev_shift_dr(jtag_proc_t *jp, jtag_dev_t *dev, uint8_t *dout, const uint8_t *din, int ticks);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
|
|||
struct target_flash *f;
|
||||
|
||||
if (!kf) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ static void lmi_add_flash(target *t, size_t length)
|
|||
{
|
||||
struct target_flash *f = calloc(1, sizeof(*f));
|
||||
if (!f) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ lpc11xx_probe(target *t)
|
|||
return true;
|
||||
}
|
||||
if (idcode) {
|
||||
DEBUG("LPC11xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
|
||||
DEBUG_INFO("LPC11xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
|
||||
}
|
||||
idcode = target_mem_read32(t, LPC8XX_DEVICE_ID);
|
||||
switch (idcode) {
|
||||
|
@ -196,7 +196,7 @@ lpc11xx_probe(target *t)
|
|||
return true;
|
||||
}
|
||||
if (idcode) {
|
||||
DEBUG("LPC8xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
|
||||
DEBUG_INFO("LPC8xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -138,17 +138,20 @@ lpc17xx_cmd_erase(target *t, int argc, const char *argv[])
|
|||
struct flash_param param;
|
||||
|
||||
if (lpc17xx_iap_call(t, ¶m, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR-1)) {
|
||||
DEBUG("lpc17xx_cmd_erase: prepare failed %d\n", (unsigned int)param.result[0]);
|
||||
DEBUG_WARN("lpc17xx_cmd_erase: prepare failed %d\n",
|
||||
(unsigned int)param.result[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lpc17xx_iap_call(t, ¶m, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR-1, CPU_CLK_KHZ)) {
|
||||
DEBUG("lpc17xx_cmd_erase: erase failed %d\n", (unsigned int)param.result[0]);
|
||||
DEBUG_WARN("lpc17xx_cmd_erase: erase failed %d\n",
|
||||
(unsigned int)param.result[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lpc17xx_iap_call(t, ¶m, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR-1)) {
|
||||
DEBUG("lpc17xx_cmd_erase: blankcheck failed %d\n", (unsigned int)param.result[0]);
|
||||
DEBUG_WARN("lpc17xx_cmd_erase: blankcheck failed %d\n",
|
||||
(unsigned int)param.result[0]);
|
||||
return false;
|
||||
}
|
||||
tc_printf(t, "Erase OK.\n");
|
||||
|
@ -198,4 +201,4 @@ lpc17xx_iap_call(target *t, struct flash_param *param, enum iap_cmd cmd, ...) {
|
|||
/* copy back just the parameters structure */
|
||||
target_mem_read(t, (void *)param, IAP_RAM_BASE, sizeof(struct flash_param));
|
||||
return param->result[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length)
|
|||
struct target_flash *f;
|
||||
|
||||
if (!lf) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ static void msp432_add_flash(target *t, uint32_t addr, size_t length, target_add
|
|||
struct msp432_flash *mf = calloc(1, sizeof(*mf));
|
||||
struct target_flash *f;
|
||||
if (!mf) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -184,8 +184,10 @@ bool msp432_probe(target *t)
|
|||
return false;
|
||||
|
||||
/* Check for the right HW revision: at least C, as no flash support for B */
|
||||
if (target_mem_read32(t, HWREV_ADDR) < HWREV_MIN_VALUE)
|
||||
if (target_mem_read32(t, HWREV_ADDR) < HWREV_MIN_VALUE) {
|
||||
DEBUG_INFO("MSP432 Version not handled\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If we got till this point, we are most probably looking at a real TLV */
|
||||
/* Device Information structure. Now check for the correct device */
|
||||
|
@ -237,20 +239,21 @@ static bool msp432_sector_erase(struct target_flash *f, target_addr addr)
|
|||
|
||||
/* Unprotect sector */
|
||||
uint32_t old_prot = msp432_sector_unprotect(mf, addr);
|
||||
DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register));
|
||||
DEBUG_WARN("Flash protect: 0x%08"PRIX32"\n",
|
||||
target_mem_read32(t, mf->flash_protect_register));
|
||||
|
||||
/* Prepare input data */
|
||||
uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA
|
||||
target_regs_read(t, regs);
|
||||
regs[0] = addr; // Address of sector to erase in R0
|
||||
|
||||
DEBUG("Erasing sector at 0x%08"PRIX32"\n", addr);
|
||||
DEBUG_INFO("Erasing sector at 0x%08"PRIX32"\n", addr);
|
||||
|
||||
/* Call ROM */
|
||||
msp432_call_ROM(t, mf->FlashCtl_eraseSector, regs);
|
||||
|
||||
// Result value in R0 is true for success
|
||||
DEBUG("ROM return value: %"PRIu32"\n", regs[0]);
|
||||
DEBUG_INFO("ROM return value: %"PRIu32"\n", regs[0]);
|
||||
|
||||
/* Restore original protection */
|
||||
target_mem_write32(t, mf->flash_protect_register, old_prot);
|
||||
|
@ -289,7 +292,8 @@ static int msp432_flash_write(struct target_flash *f, target_addr dest,
|
|||
/* Unprotect sector, len is always < SECTOR_SIZE */
|
||||
uint32_t old_prot = msp432_sector_unprotect(mf, dest);
|
||||
|
||||
DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register));
|
||||
DEBUG_WARN("Flash protect: 0x%08"PRIX32"\n",
|
||||
target_mem_read32(t, mf->flash_protect_register));
|
||||
|
||||
/* Prepare input data */
|
||||
uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA
|
||||
|
@ -298,14 +302,14 @@ static int msp432_flash_write(struct target_flash *f, target_addr dest,
|
|||
regs[1] = dest; // Flash address to be write to in R1
|
||||
regs[2] = len; // Size of buffer to be flashed in R2
|
||||
|
||||
DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08zu\n", dest, len);
|
||||
DEBUG_INFO("Writing 0x%04" PRIX32 " bytes at 0x%08zu\n", dest, len);
|
||||
/* Call ROM */
|
||||
msp432_call_ROM(t, mf->FlashCtl_programMemory, regs);
|
||||
|
||||
/* Restore original protection */
|
||||
target_mem_write32(t, mf->flash_protect_register, old_prot);
|
||||
|
||||
DEBUG("ROM return value: %"PRIu32"\n", regs[0]);
|
||||
DEBUG_INFO("ROM return value: %"PRIu32"\n", regs[0]);
|
||||
// Result value in R0 is true for success
|
||||
return !regs[0];
|
||||
}
|
||||
|
@ -319,7 +323,7 @@ static bool msp432_cmd_erase_main(target *t, int argc, const char **argv)
|
|||
/* Usually, this is not wanted, so go sector by sector... */
|
||||
|
||||
uint32_t banksize = target_mem_read32(t, SYS_FLASH_SIZE) / 2;
|
||||
DEBUG("Bank Size: 0x%08"PRIX32"\n", banksize);
|
||||
DEBUG_INFO("Bank Size: 0x%08"PRIX32"\n", banksize);
|
||||
|
||||
/* Erase first bank */
|
||||
struct target_flash *f = get_target_flash(t, MAIN_FLASH_BASE);
|
||||
|
|
|
@ -99,7 +99,7 @@ static void nrf51_add_flash(target *t,
|
|||
{
|
||||
struct target_flash *f = calloc(1, sizeof(*f));
|
||||
if (!f) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ bool ke04_probe(target *t)
|
|||
/* Add flash, all KE04 have same write and erase size */
|
||||
struct target_flash *f = calloc(1, sizeof(*f));
|
||||
if (!f) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ static void sam3_add_flash(target *t,
|
|||
struct target_flash *f;
|
||||
|
||||
if (!sf) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ static void sam4_add_flash(target *t,
|
|||
struct target_flash *f;
|
||||
|
||||
if (!sf) { /* calloc failed: heap exhaustion */
|
||||
DEBUG("calloc: failed in %s\n", __func__);
|
||||
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,7 @@ bool sam3x_probe(target *t)
|
|||
static int
|
||||
sam3x_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg)
|
||||
{
|
||||
DEBUG("%s: base = 0x%08"PRIx32" cmd = 0x%02X, arg = 0x%06X\n",
|
||||
DEBUG_INFO("%s: base = 0x%08"PRIx32" cmd = 0x%02X, arg = 0x%06X\n",
|
||||
__func__, base, cmd, arg);
|
||||
target_mem_write32(t, EEFC_FCR(base),
|
||||
EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue