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:
UweBonnes 2020-06-05 15:57:25 +02:00 committed by GitHub
commit f5e305e237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 5399 additions and 2442 deletions

1
.gitignore vendored
View File

@ -16,4 +16,5 @@ tags
*.b#*
blackmagic_upgrade
*.exe
*.elf
.vscode

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

@ -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));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,4 +27,3 @@ struct platform_timeout {
uint32_t platform_time_ms(void);
#endif /* __TIMING_H */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)); \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

750
src/platforms/hosted/dap.c Normal file
View File

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

View File

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

View File

@ -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";
}

View File

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

View File

@ -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]);
}

View File

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

View File

@ -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);
}

View File

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

View File

View File

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

View File

@ -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);
}

View File

@ -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);
}

View File

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

View File

@ -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]);
}

View File

@ -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);
}
}

View File

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

View File

View File

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

View File

@ -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)); \

View File

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

View File

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

View File

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

View File

@ -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)".

View File

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

View File

@ -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);}

View File

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

View File

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

View File

@ -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]);
}

View File

@ -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];
}

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 '+';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&param, ticks);
badParity = swd_proc.swdptap_seq_in_parity(&param, 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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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. */

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -138,17 +138,20 @@ lpc17xx_cmd_erase(target *t, int argc, const char *argv[])
struct flash_param param;
if (lpc17xx_iap_call(t, &param, 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, &param, 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, &param, 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];
}
}

View File

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

View File

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

View File

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

View File

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

View File

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