Merge commit 'e6a9a1a3665e83e25d5d4077a33aa5b0110646b8' into sam-update
# Conflicts: # .gitignore
This commit is contained in:
commit
78837173a4
40
.gitattributes
vendored
Normal file
40
.gitattributes
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Text for humans
|
||||||
|
LICENSE text eol=lf
|
||||||
|
HACKING text eol=lf
|
||||||
|
COPYING text eol=lf
|
||||||
|
UsingSWO text eol=lf
|
||||||
|
README.* text eol=lf
|
||||||
|
|
||||||
|
# Source code
|
||||||
|
Makefile text eol=lf
|
||||||
|
*.mk text eol=lf
|
||||||
|
*.mak text eol=lf
|
||||||
|
*.inc text eol=lf
|
||||||
|
*.py text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.c text eol=lf
|
||||||
|
*.S text eol=lf
|
||||||
|
*.s text eol=lf
|
||||||
|
*.h text eol=lf
|
||||||
|
*.ld text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.rules text eol=lf
|
||||||
|
|
||||||
|
# Git control files
|
||||||
|
.gitattributes eol=lf
|
||||||
|
.gitignore eol=lf
|
||||||
|
.gitmodules eol=lf
|
||||||
|
|
||||||
|
# Windows source code uses CRLF
|
||||||
|
*.vcxproj text eol=crlf
|
||||||
|
*.props text eol=crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
*.inf text eol=crlf
|
||||||
|
|
||||||
|
# Other binary files
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.bin binary
|
||||||
|
*.elf binary
|
||||||
|
*.bin binary
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -21,3 +21,5 @@ blackmagic_upgrade
|
|||||||
.vscode
|
.vscode
|
||||||
cscope.out
|
cscope.out
|
||||||
cscope.files
|
cscope.files
|
||||||
|
.gdb_history
|
||||||
|
src/artifacts/
|
28
UsingSWO
28
UsingSWO
@ -14,24 +14,28 @@ monitor traceswo 115200
|
|||||||
|
|
||||||
We are constrained on maximum input speed by both the capabilities of the
|
We are constrained on maximum input speed by both the capabilities of the
|
||||||
BMP STM32F103 USART and the ability to get the packets back out over the USB
|
BMP STM32F103 USART and the ability to get the packets back out over the USB
|
||||||
link. The UART baudrate is set by b=(72x10^6)/(16*d)...so for d=1 that means
|
link. The UART baudrate is set by b=(72x10^6)/d...with d >= 16 or
|
||||||
a maximum speed of 4.5Mbps. For continious streaming that turns out to be
|
a maximum speed of 4.5Mbps UART1 and 2.25 Mbps on UART2.
|
||||||
_too_ fast for the USB link, so the next available option is the 2.25Mbps
|
For continious streaming that turns out to be_too_ fast for the USB
|
||||||
that we use. ....you can safely use the 4.5Mbps setting if your debug data
|
link, so the next available option is the 2.25Mbps that we use. ....
|
||||||
|
You can safely use the 4.5Mbps setting if your debug data
|
||||||
is bursty, or if you're using a different CPU to the STM32F103 as your BMP
|
is bursty, or if you're using a different CPU to the STM32F103 as your BMP
|
||||||
host, but you potentially run the risk of losing packets if you have long
|
host, but you potentially run the risk of losing packets if you have long
|
||||||
runs of sending which the usb cannot flush in time (there's a 12K buffer, so
|
runs of sending which the usb cannot flush in time (there's a 12K buffer, so
|
||||||
the it is a pretty long run before it becomes a problem).
|
the it is a pretty long run before it becomes a problem).
|
||||||
|
|
||||||
Note that the baudrate equation means there are only certain speeds
|
Note that the baudrate equation means there are only certain speeds
|
||||||
available. The highest half dozen are;
|
available. The highest:
|
||||||
SWO uses USART1(stlink) USART2(swlink)
|
BRR USART1(stlink) USART2(swlink)
|
||||||
1 4.50 Mbps 2.25 Mbps
|
16 4.50 Mbps 2.25 Mbps
|
||||||
2 2.25 Mbps 1.125 Mbps
|
17 4.235 Mbps 2.118 Mbps
|
||||||
3 1.50 Mbps 0.75 Mbps
|
18 4.000 Mbps 2.0 Mbps
|
||||||
4 1.125 Mbps 0.5635 Mbps
|
19 3.789 Mbps 1.895 Mbps
|
||||||
5 0.900 Mbps 0.45 Mbps
|
20 3.600 Mbps 1.8 Mbps
|
||||||
6 0.750 Mbps 0.375 Mbps
|
...
|
||||||
|
24 3.0 Mbps 1.5 Mbps
|
||||||
|
...
|
||||||
|
36 2.0 Mbps 1.0 Mbps
|
||||||
|
|
||||||
...the USART will cope with some timing slip, but it's advisible to stay as
|
...the USART will cope with some timing slip, but it's advisible to stay as
|
||||||
close to these values as you can. As the speed comes down the spread between
|
close to these values as you can. As the speed comes down the spread between
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
* Copyright (C) 2021 Uwe Bonnes
|
||||||
|
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -27,6 +29,7 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "gdb_packet.h"
|
#include "gdb_packet.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "target_internal.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "serialno.h"
|
#include "serialno.h"
|
||||||
@ -37,13 +40,6 @@
|
|||||||
|
|
||||||
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
|
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
|
||||||
|
|
||||||
struct command_s {
|
|
||||||
const char *cmd;
|
|
||||||
cmd_handler handler;
|
|
||||||
|
|
||||||
const char *help;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool cmd_version(target *t, int argc, char **argv);
|
static bool cmd_version(target *t, int argc, char **argv);
|
||||||
static bool cmd_serial(target *t, int argc, char **argv);
|
static bool cmd_serial(target *t, int argc, char **argv);
|
||||||
static bool cmd_help(target *t, int argc, char **argv);
|
static bool cmd_help(target *t, int argc, char **argv);
|
||||||
@ -179,10 +175,11 @@ bool cmd_help(target *t, int argc, char **argv)
|
|||||||
(void)argv;
|
(void)argv;
|
||||||
const struct command_s *c;
|
const struct command_s *c;
|
||||||
|
|
||||||
gdb_out("General commands:\n");
|
if (!t || t->tc->destroy_callback) {
|
||||||
for(c = cmd_list; c->cmd; c++)
|
gdb_out("General commands:\n");
|
||||||
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
|
for(c = cmd_list; c->cmd; c++)
|
||||||
|
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
|
||||||
|
}
|
||||||
if (!t)
|
if (!t)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -240,8 +237,9 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
|
|||||||
bool cmd_swdp_scan(target *t, int argc, char **argv)
|
bool cmd_swdp_scan(target *t, int argc, char **argv)
|
||||||
{
|
{
|
||||||
(void)t;
|
(void)t;
|
||||||
(void)argc;
|
volatile uint32_t targetid = 0;
|
||||||
(void)argv;
|
if (argc > 1)
|
||||||
|
targetid = strtol(argv[1], NULL, 0);
|
||||||
if (platform_target_voltage())
|
if (platform_target_voltage())
|
||||||
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
gdb_outf("Target voltage: %s\n", platform_target_voltage());
|
||||||
|
|
||||||
@ -252,9 +250,9 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
|
|||||||
volatile struct exception e;
|
volatile struct exception e;
|
||||||
TRY_CATCH (e, EXCEPTION_ALL) {
|
TRY_CATCH (e, EXCEPTION_ALL) {
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
devs = platform_adiv5_swdp_scan();
|
devs = platform_adiv5_swdp_scan(targetid);
|
||||||
#else
|
#else
|
||||||
devs = adiv5_swdp_scan();
|
devs = adiv5_swdp_scan(targetid);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
|
@ -35,13 +35,13 @@ typedef uint32_t target_addr;
|
|||||||
struct target_controller;
|
struct target_controller;
|
||||||
|
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
int platform_adiv5_swdp_scan(void);
|
int platform_adiv5_swdp_scan(uint32_t targetid);
|
||||||
int platform_jtag_scan(const uint8_t *lrlens);
|
int platform_jtag_scan(const uint8_t *lrlens);
|
||||||
#endif
|
#endif
|
||||||
int adiv5_swdp_scan(void);
|
int adiv5_swdp_scan(uint32_t targetid);
|
||||||
int jtag_scan(const uint8_t *lrlens);
|
int jtag_scan(const uint8_t *lrlens);
|
||||||
|
|
||||||
bool target_foreach(void (*cb)(int i, target *t, void *context), void *context);
|
int target_foreach(void (*cb)(int i, target *t, void *context), void *context);
|
||||||
void target_list_free(void);
|
void target_list_free(void);
|
||||||
|
|
||||||
/* Attach/detach functions */
|
/* Attach/detach functions */
|
||||||
|
@ -144,7 +144,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
|
|||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
.bInterfaceClass = USB_CLASS_CDC,
|
.bInterfaceClass = USB_CLASS_CDC,
|
||||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iInterface = 4,
|
.iInterface = 4,
|
||||||
|
|
||||||
.endpoint = gdb_comm_endp,
|
.endpoint = gdb_comm_endp,
|
||||||
@ -174,7 +174,7 @@ static const struct usb_iface_assoc_descriptor gdb_assoc = {
|
|||||||
.bInterfaceCount = 2,
|
.bInterfaceCount = 2,
|
||||||
.bFunctionClass = USB_CLASS_CDC,
|
.bFunctionClass = USB_CLASS_CDC,
|
||||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bFunctionProtocol = USB_CDC_PROTOCOL_AT,
|
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iFunction = 0,
|
.iFunction = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ static const struct usb_interface_descriptor uart_comm_iface[] = {{
|
|||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
.bInterfaceClass = USB_CLASS_CDC,
|
.bInterfaceClass = USB_CLASS_CDC,
|
||||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
|
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iInterface = 5,
|
.iInterface = 5,
|
||||||
|
|
||||||
.endpoint = uart_comm_endp,
|
.endpoint = uart_comm_endp,
|
||||||
@ -277,7 +277,7 @@ static const struct usb_iface_assoc_descriptor uart_assoc = {
|
|||||||
.bInterfaceCount = 2,
|
.bInterfaceCount = 2,
|
||||||
.bFunctionClass = USB_CLASS_CDC,
|
.bFunctionClass = USB_CLASS_CDC,
|
||||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
.bFunctionProtocol = USB_CDC_PROTOCOL_AT,
|
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE,
|
||||||
.iFunction = 0,
|
.iFunction = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -401,8 +401,8 @@ char serial_no[13];
|
|||||||
static char serial_no[9];
|
static char serial_no[9];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BOARD_IDENT "Black Magic Probe" PLATFORM_IDENT FIRMWARE_VERSION
|
#define BOARD_IDENT "Black Magic Probe " PLATFORM_IDENT FIRMWARE_VERSION
|
||||||
#define DFU_IDENT "Black Magic Firmware Upgrade" PLATFORM_IDENT FIRMWARE_VERSION
|
#define DFU_IDENT "Black Magic Firmware Upgrade " PLATFORM_IDENT FIRMWARE_VERSION
|
||||||
|
|
||||||
static const char *usb_strings[] = {
|
static const char *usb_strings[] = {
|
||||||
"Black Sphere Technologies",
|
"Black Sphere Technologies",
|
||||||
|
@ -36,7 +36,19 @@ blackmagic -V <file>.bin
|
|||||||
```
|
```
|
||||||
### Show more options
|
### Show more options
|
||||||
```
|
```
|
||||||
blackmagic -h"
|
blackmagic -h
|
||||||
|
```
|
||||||
|
### Show available monitor commands
|
||||||
|
```
|
||||||
|
blackmagic -M help
|
||||||
|
```
|
||||||
|
### Show available monitor commands on second target
|
||||||
|
```
|
||||||
|
blackmagic -n 2 -M help
|
||||||
|
```
|
||||||
|
### Monitor commands with multiple arguments, e.g.Stm32F1:
|
||||||
|
```
|
||||||
|
blackmagic -M "option help"
|
||||||
```
|
```
|
||||||
## Used shared libraries:
|
## Used shared libraries:
|
||||||
### libusb
|
### libusb
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Copyright(C) 2020 - 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -36,13 +36,15 @@
|
|||||||
|
|
||||||
#define VENDOR_ID_SEGGER 0x1366
|
#define VENDOR_ID_SEGGER 0x1366
|
||||||
|
|
||||||
|
#define NO_SERIAL_NUMBER "<no serial number>"
|
||||||
|
|
||||||
void bmp_ident(bmp_info_t *info)
|
void bmp_ident(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
DEBUG_INFO("BMP hosted %s\n for ST-Link V2/3, CMSIS_DAP, JLINK and "
|
DEBUG_INFO("BMP hosted %s\n for ST-Link V2/3, CMSIS_DAP, JLINK and "
|
||||||
"LIBFTDI/MPSSE\n", FIRMWARE_VERSION);
|
"LIBFTDI/MPSSE\n", FIRMWARE_VERSION);
|
||||||
if (info && info->vid && info->pid)
|
if (info && info->vid && info->pid)
|
||||||
DEBUG_INFO("Using %04x:%04x %s %s\n %s\n", info->vid, info->pid,
|
DEBUG_INFO("Using %04x:%04x %s %s\n %s\n", info->vid, info->pid,
|
||||||
info->serial,
|
(info->serial[0]) ? info->serial : NO_SERIAL_NUMBER,
|
||||||
info->manufacturer,
|
info->manufacturer,
|
||||||
info->product);
|
info->product);
|
||||||
}
|
}
|
||||||
@ -147,22 +149,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
|||||||
res = libusb_get_string_descriptor_ascii(
|
res = libusb_get_string_descriptor_ascii(
|
||||||
handle, desc.iManufacturer, (uint8_t*)manufacturer,
|
handle, desc.iManufacturer, (uint8_t*)manufacturer,
|
||||||
sizeof(manufacturer));
|
sizeof(manufacturer));
|
||||||
if (res > 0) {
|
res = libusb_get_string_descriptor_ascii(
|
||||||
res = libusb_get_string_descriptor_ascii(
|
handle, desc.iProduct, (uint8_t*)product,
|
||||||
handle, desc.iProduct, (uint8_t*)product,
|
sizeof(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;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
libusb_close(handle);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
libusb_close(handle);
|
libusb_close(handle);
|
||||||
if (cl_opts->opt_ident_string) {
|
if (cl_opts->opt_ident_string) {
|
||||||
char *match_manu = NULL;
|
char *match_manu = NULL;
|
||||||
@ -233,11 +222,9 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
|
|||||||
if (!cable->name)
|
if (!cable->name)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!serial[0])
|
|
||||||
strcpy(serial, "<no serial number>");
|
|
||||||
if (report) {
|
if (report) {
|
||||||
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
|
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
|
||||||
serial,
|
(serial[0]) ? serial : NO_SERIAL_NUMBER,
|
||||||
manufacturer,product);
|
manufacturer,product);
|
||||||
}
|
}
|
||||||
info->vid = desc.idVendor;
|
info->vid = desc.idVendor;
|
||||||
|
@ -73,7 +73,7 @@ bool remote_target_get_power(void)
|
|||||||
return (construct[1] == '1');
|
return (construct[1] == '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_target_set_power(bool power)
|
bool remote_target_set_power(bool power)
|
||||||
{
|
{
|
||||||
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
uint8_t construct[REMOTE_MAX_MSG_SIZE];
|
||||||
int s;
|
int s;
|
||||||
@ -87,8 +87,9 @@ void remote_target_set_power(bool power)
|
|||||||
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
|
||||||
DEBUG_WARN("platform_target_set_power failed, error %s\n",
|
DEBUG_WARN("platform_target_set_power failed, error %s\n",
|
||||||
s ? (char *)&(construct[1]) : "unknown");
|
s ? (char *)&(construct[1]) : "unknown");
|
||||||
exit(-1);
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remote_srst_set_val(bool assert)
|
void remote_srst_set_val(bool assert)
|
||||||
|
@ -34,7 +34,7 @@ int remote_swdptap_init(swd_proc_t *swd_proc);
|
|||||||
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
|
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
bool remote_target_get_power(void);
|
bool remote_target_get_power(void);
|
||||||
const char *remote_target_voltage(void);
|
const char *remote_target_voltage(void);
|
||||||
void remote_target_set_power(bool power);
|
bool remote_target_set_power(bool power);
|
||||||
void remote_srst_set_val(bool assert);
|
void remote_srst_set_val(bool assert);
|
||||||
bool remote_srst_get_val(void);
|
bool remote_srst_get_val(void);
|
||||||
void remote_max_frequency_set(uint32_t freq);
|
void remote_max_frequency_set(uint32_t freq);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019-20 Uwe Bonnes <bon@elektron,ikp.physik.tu-darmstadt.de>
|
* Copyright (C) 2019-2021 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -49,10 +49,11 @@ uint8_t mode;
|
|||||||
static hid_device *handle = NULL;
|
static hid_device *handle = NULL;
|
||||||
static uint8_t hid_buffer[1024 + 1];
|
static uint8_t hid_buffer[1024 + 1];
|
||||||
static int report_size = 64 + 1; // TODO: read actual report size
|
static int report_size = 64 + 1; // TODO: read actual report size
|
||||||
|
static bool has_swd_sequence = false;
|
||||||
|
|
||||||
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
|
||||||
int dap_init(bmp_info_t *info)
|
int dap_init(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
DEBUG_INFO("dap_init\n");
|
|
||||||
if (hid_init())
|
if (hid_init())
|
||||||
return -1;
|
return -1;
|
||||||
int size = strlen(info->serial);
|
int size = strlen(info->serial);
|
||||||
@ -71,17 +72,32 @@ int dap_init(bmp_info_t *info)
|
|||||||
if (!handle)
|
if (!handle)
|
||||||
return -1;
|
return -1;
|
||||||
dap_disconnect();
|
dap_disconnect();
|
||||||
|
size = dap_info(DAP_INFO_FW_VER, hid_buffer, sizeof(hid_buffer));
|
||||||
|
if (size) {
|
||||||
|
DEBUG_INFO("Ver %s, ", hid_buffer);
|
||||||
|
int major = -1, minor = -1, sub = -1;
|
||||||
|
if (sscanf((const char *)hid_buffer, "%d.%d.%d",
|
||||||
|
&major, &minor, &sub)) {
|
||||||
|
if (sub == -1) {
|
||||||
|
if (minor > 10) {
|
||||||
|
minor /= 10;
|
||||||
|
sub = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has_swd_sequence = ((major > 0 ) && (minor > 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
|
||||||
dap_caps = hid_buffer[0];
|
dap_caps = hid_buffer[0];
|
||||||
DEBUG_INFO(" Cap (0x%2x): %s%s%s", hid_buffer[0],
|
DEBUG_INFO("Cap (0x%2x): %s%s%s", dap_caps,
|
||||||
(hid_buffer[0] & 1)? "SWD" : "",
|
(dap_caps & 1)? "SWD" : "",
|
||||||
((hid_buffer[0] & 3) == 3) ? "/" : "",
|
((dap_caps & 3) == 3) ? "/" : "",
|
||||||
(hid_buffer[0] & 2)? "JTAG" : "");
|
(dap_caps & 2)? "JTAG" : "");
|
||||||
if (hid_buffer[0] & 4)
|
if (dap_caps & 4)
|
||||||
DEBUG_INFO(", SWO_UART");
|
DEBUG_INFO(", SWO_UART");
|
||||||
if (hid_buffer[0] & 8)
|
if (dap_caps & 8)
|
||||||
DEBUG_INFO(", SWO_MANCHESTER");
|
DEBUG_INFO(", SWO_MANCHESTER");
|
||||||
if (hid_buffer[0] & 0x10)
|
if (dap_caps & 0x10)
|
||||||
DEBUG_INFO(", Atomic Cmds");
|
DEBUG_INFO(", Atomic Cmds");
|
||||||
DEBUG_INFO("\n");
|
DEBUG_INFO("\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include "jtagtap.h"
|
#include "jtagtap.h"
|
||||||
|
|
||||||
#include "bmp_hosted.h"
|
#include "bmp_hosted.h"
|
||||||
#include <libftdi1/ftdi.h>
|
|
||||||
|
|
||||||
typedef struct data_desc_s {
|
typedef struct data_desc_s {
|
||||||
int16_t data_low;
|
int16_t data_low;
|
||||||
@ -101,11 +100,6 @@ typedef struct cable_desc_s {
|
|||||||
char * name;
|
char * name;
|
||||||
}cable_desc_t;
|
}cable_desc_t;
|
||||||
|
|
||||||
extern cable_desc_t cable_desc[];
|
|
||||||
extern cable_desc_t *active_cable;
|
|
||||||
extern struct ftdi_context *ftdic;
|
|
||||||
extern data_desc_t active_state;
|
|
||||||
|
|
||||||
#if HOSTED_BMP_ONLY == 1
|
#if HOSTED_BMP_ONLY == 1
|
||||||
# pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
@ -123,6 +117,12 @@ void libftdi_max_frequency_set(uint32_t freq) {};
|
|||||||
uint32_t libftdi_max_frequency_get(void) {return 0;};
|
uint32_t libftdi_max_frequency_get(void) {return 0;};
|
||||||
# pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#else
|
#else
|
||||||
|
#include <libftdi1/ftdi.h>
|
||||||
|
extern cable_desc_t cable_desc[];
|
||||||
|
extern cable_desc_t *active_cable;
|
||||||
|
extern struct ftdi_context *ftdic;
|
||||||
|
extern data_desc_t active_state;
|
||||||
|
|
||||||
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
|
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_swdptap_init(swd_proc_t *swd_proc);
|
||||||
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
|
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Copyright (C) 2020- 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -119,14 +119,16 @@ void platform_init(int argc, char **argv)
|
|||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_adiv5_swdp_scan(void)
|
int platform_adiv5_swdp_scan(uint32_t targetid)
|
||||||
{
|
{
|
||||||
info.is_jtag = false;
|
info.is_jtag = false;
|
||||||
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
||||||
|
if (targetid && (info.bmp_type != BMP_TYPE_BMP))
|
||||||
|
DEBUG_WARN("Ignoring TARGETID for now!\n");
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
return adiv5_swdp_scan();
|
return adiv5_swdp_scan(targetid);
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_STLINKV2:
|
case BMP_TYPE_STLINKV2:
|
||||||
{
|
{
|
||||||
@ -377,6 +379,20 @@ uint32_t platform_max_frequency_get(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_target_set_power(bool power)
|
||||||
|
{
|
||||||
|
switch (info.bmp_type) {
|
||||||
|
case BMP_TYPE_BMP:
|
||||||
|
if (remote_target_set_power(power))
|
||||||
|
DEBUG_INFO("Powering up device!\n");
|
||||||
|
else
|
||||||
|
DEBUG_WARN("Powering up device unimplemented or failed\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void platform_buffer_flush(void)
|
void platform_buffer_flush(void)
|
||||||
{
|
{
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
|
@ -131,10 +131,6 @@ void platform_init(void)
|
|||||||
GPIO_CNF_OUTPUT_PUSHPULL,
|
GPIO_CNF_OUTPUT_PUSHPULL,
|
||||||
LED_UART | LED_IDLE_RUN | LED_ERROR);
|
LED_UART | LED_IDLE_RUN | LED_ERROR);
|
||||||
|
|
||||||
/* FIXME: This pin in intended to be input, but the TXS0108 fails
|
|
||||||
* to release the device from reset if this floats. */
|
|
||||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
|
|
||||||
GPIO_CNF_OUTPUT_PUSHPULL, GPIO7);
|
|
||||||
/* Enable SRST output. Original uses a NPN to pull down, so setting the
|
/* Enable SRST output. Original uses a NPN to pull down, so setting the
|
||||||
* output HIGH asserts. Mini is directly connected so use open drain output
|
* output HIGH asserts. Mini is directly connected so use open drain output
|
||||||
* and set LOW to assert.
|
* and set LOW to assert.
|
||||||
@ -146,7 +142,17 @@ void platform_init(void)
|
|||||||
? GPIO_CNF_OUTPUT_PUSHPULL
|
? GPIO_CNF_OUTPUT_PUSHPULL
|
||||||
: GPIO_CNF_OUTPUT_OPENDRAIN),
|
: GPIO_CNF_OUTPUT_OPENDRAIN),
|
||||||
SRST_PIN);
|
SRST_PIN);
|
||||||
|
/* FIXME: Gareth, Esden, what versions need this fix? */
|
||||||
|
if (platform_hwversion() < 3) {
|
||||||
|
/* FIXME: This pin in intended to be input, but the TXS0108 fails
|
||||||
|
* to release the device from reset if this floats. */
|
||||||
|
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_OUTPUT_2_MHZ,
|
||||||
|
GPIO_CNF_OUTPUT_PUSHPULL, SRST_SENSE_PIN);
|
||||||
|
} else {
|
||||||
|
gpio_set(SRST_SENSE_PORT, SRST_SENSE_PIN);
|
||||||
|
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_INPUT,
|
||||||
|
GPIO_CNF_INPUT_PULL_UPDOWN, SRST_SENSE_PIN);
|
||||||
|
}
|
||||||
/* Enable internal pull-up on PWR_BR so that we don't drive
|
/* Enable internal pull-up on PWR_BR so that we don't drive
|
||||||
TPWR locally or inadvertently supply power to the target. */
|
TPWR locally or inadvertently supply power to the target. */
|
||||||
if (platform_hwversion () == 1) {
|
if (platform_hwversion () == 1) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes
|
||||||
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -32,6 +32,7 @@
|
|||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "target_internal.h"
|
#include "target_internal.h"
|
||||||
#include "cortexm.h"
|
#include "cortexm.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
#include "cl_utils.h"
|
#include "cl_utils.h"
|
||||||
#include "bmp_hosted.h"
|
#include "bmp_hosted.h"
|
||||||
@ -45,6 +46,18 @@
|
|||||||
# include <sys/mman.h>
|
# include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void cl_target_printf(struct target_controller *tc,
|
||||||
|
const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
(void)tc;
|
||||||
|
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct target_controller cl_controller = {
|
||||||
|
.printf = cl_target_printf,
|
||||||
|
};
|
||||||
|
|
||||||
struct mmap_data {
|
struct mmap_data {
|
||||||
void *data;
|
void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -152,6 +165,9 @@ static void cl_help(char **argv)
|
|||||||
DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\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("\t-R\t\t: Reset device\n");
|
||||||
DEBUG_WARN("\t-H\t\t: Do not use high level commands (BMP-Remote)\n");
|
DEBUG_WARN("\t-H\t\t: Do not use high level commands (BMP-Remote)\n");
|
||||||
|
DEBUG_WARN("\t-m <target>\t: Use (target)id for SWD multi-drop.\n");
|
||||||
|
DEBUG_WARN("\t-M <string>\t: Run target specific monitor commands. Quote multi\n");
|
||||||
|
DEBUG_WARN("\t\t\t word strings. Run \"-M help\" for help.\n");
|
||||||
DEBUG_WARN("Flash operation modifiers options:\n");
|
DEBUG_WARN("Flash operation modifiers options:\n");
|
||||||
DEBUG_WARN("\tDefault action with given file is to write to flash\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"
|
DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n"
|
||||||
@ -168,7 +184,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
opt->opt_flash_size = 16 * 1024 *1024;
|
opt->opt_flash_size = 16 * 1024 *1024;
|
||||||
opt->opt_flash_start = 0xffffffff;
|
opt->opt_flash_start = 0xffffffff;
|
||||||
opt->opt_max_swj_frequency = 4000000;
|
opt->opt_max_swj_frequency = 4000000;
|
||||||
while((c = getopt(argc, argv, "eEhHv:d:f:s:I:c:CnltVtTa:S:jpP:rR")) != -1) {
|
while((c = getopt(argc, argv, "eEhHv:d:f:s:I:c:Cln:m:M:tVtTa:S:jpP:rR")) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
@ -255,6 +271,15 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
|
|||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
opt->opt_target_dev = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (optarg)
|
||||||
|
opt->opt_targetid = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
opt->opt_mode = BMP_MODE_MONITOR;
|
||||||
|
if (optarg)
|
||||||
|
opt->opt_monitor = optarg;
|
||||||
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if (optarg)
|
if (optarg)
|
||||||
opt->opt_position = atoi(optarg);
|
opt->opt_position = atoi(optarg);
|
||||||
@ -313,13 +338,10 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
int num_targets;
|
int num_targets;
|
||||||
#if defined(PLATFORM_HAS_POWER_SWITCH)
|
|
||||||
if (opt->opt_tpwr) {
|
if (opt->opt_tpwr) {
|
||||||
DEBUG_INFO("Powering up device");
|
|
||||||
platform_target_set_power(true);
|
platform_target_set_power(true);
|
||||||
platform_delay(500);
|
platform_delay(500);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (opt->opt_connect_under_reset)
|
if (opt->opt_connect_under_reset)
|
||||||
DEBUG_INFO("Connecting under reset\n");
|
DEBUG_INFO("Connecting under reset\n");
|
||||||
connect_assert_srst = opt->opt_connect_under_reset;
|
connect_assert_srst = opt->opt_connect_under_reset;
|
||||||
@ -330,66 +352,52 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
if (opt->opt_usejtag) {
|
if (opt->opt_usejtag) {
|
||||||
num_targets = platform_jtag_scan(NULL);
|
num_targets = platform_jtag_scan(NULL);
|
||||||
} else {
|
} else {
|
||||||
num_targets = platform_adiv5_swdp_scan();
|
num_targets = platform_adiv5_swdp_scan(opt->opt_targetid);
|
||||||
}
|
}
|
||||||
if (!num_targets) {
|
if (!num_targets) {
|
||||||
DEBUG_WARN("No target found\n");
|
DEBUG_WARN("No target found\n");
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
target_foreach(display_target, NULL);
|
num_targets = target_foreach(display_target, &num_targets);
|
||||||
}
|
}
|
||||||
if (opt->opt_target_dev > num_targets) {
|
if (opt->opt_target_dev > num_targets) {
|
||||||
DEBUG_WARN("Given target nummer %d not available\n",
|
DEBUG_WARN("Given target nummer %d not available max %d\n",
|
||||||
opt->opt_target_dev);
|
opt->opt_target_dev, num_targets);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
target *t = target_attach_n(opt->opt_target_dev, NULL);
|
target *t = target_attach_n(opt->opt_target_dev, &cl_controller);
|
||||||
|
|
||||||
if (!t) {
|
if (!t) {
|
||||||
DEBUG_WARN("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;
|
goto target_detach;
|
||||||
}
|
}
|
||||||
|
/* List each defined RAM */
|
||||||
|
int n_ram = 0;
|
||||||
|
for (struct target_ram *r = t->ram; r; r = r->next)
|
||||||
|
n_ram++;
|
||||||
|
for (int n = n_ram; n >= 0; n --) {
|
||||||
|
struct target_ram *r = t->ram;
|
||||||
|
for (int i = 1; r; r = r->next, i++)
|
||||||
|
if (i == n)
|
||||||
|
DEBUG_INFO("RAM Start: 0x%08" PRIx32 " length = 0x%" PRIx32 "\n",
|
||||||
|
r->start, (uint32_t)r->length);
|
||||||
|
}
|
||||||
/* Always scan memory map to find lowest flash */
|
/* Always scan memory map to find lowest flash */
|
||||||
char memory_map [1024], *p = memory_map;
|
/* List each defined Flash */
|
||||||
uint32_t flash_start = 0xffffffff;
|
uint32_t flash_start = 0xffffffff;
|
||||||
if (target_mem_map(t, memory_map, sizeof(memory_map))) {
|
int n_flash = 0;
|
||||||
while (*p && (*p == '<')) {
|
for (struct target_flash *f = t->flash; f; f = f->next)
|
||||||
unsigned int start, size;
|
n_flash++;
|
||||||
char *res;
|
for (int n = n_flash; n >= 0; n --) {
|
||||||
int match;
|
struct target_flash *f = t->flash;
|
||||||
match = strncmp(p, "<memory-map>", strlen("<memory-map>"));
|
for (int i = 1; f; f = f->next, i++)
|
||||||
if (!match) {
|
if (i == n) {
|
||||||
p += strlen("<memory-map>");
|
DEBUG_INFO("Flash Start: 0x%08" PRIx32 " length = 0x%" PRIx32
|
||||||
continue;
|
" blocksize 0x%" PRIx32 "\n",
|
||||||
|
f->start, (uint32_t)f->length, (uint32_t)f->blocksize);
|
||||||
|
if (f->start < flash_start)
|
||||||
|
flash_start = f->start;
|
||||||
}
|
}
|
||||||
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 == 0xffffffff)
|
if (opt->opt_flash_start == 0xffffffff)
|
||||||
opt->opt_flash_start = flash_start;
|
opt->opt_flash_start = flash_start;
|
||||||
@ -406,6 +414,8 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
default:
|
default:
|
||||||
DEBUG_WARN("No test for this core type yet\n");
|
DEBUG_WARN("No test for this core type yet\n");
|
||||||
}
|
}
|
||||||
|
} else if (opt->opt_mode == BMP_MODE_MONITOR) {
|
||||||
|
command_process(t, opt->opt_monitor);
|
||||||
}
|
}
|
||||||
if ((opt->opt_mode == BMP_MODE_TEST) ||
|
if ((opt->opt_mode == BMP_MODE_TEST) ||
|
||||||
(opt->opt_mode == BMP_MODE_SWJ_TEST))
|
(opt->opt_mode == BMP_MODE_SWJ_TEST))
|
||||||
@ -528,8 +538,11 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
|
|||||||
uint32_t end_time = platform_time_ms();
|
uint32_t end_time = platform_time_ms();
|
||||||
if (read_file != -1)
|
if (read_file != -1)
|
||||||
close(read_file);
|
close(read_file);
|
||||||
DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n",
|
if ((opt->opt_mode == BMP_MODE_FLASH_VERIFY) ||
|
||||||
bytes_read, (((bytes_read * 1.0)/(end_time - start_time))));
|
(opt->opt_mode == BMP_MODE_FLASH_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:
|
free_map:
|
||||||
if (map.size)
|
if (map.size)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 - 2020 Uwe Bonnes
|
* Copyright (C) 2019 - 2021 Uwe Bonnes
|
||||||
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -35,6 +35,7 @@ enum bmp_cl_mode {
|
|||||||
BMP_MODE_FLASH_READ,
|
BMP_MODE_FLASH_READ,
|
||||||
BMP_MODE_FLASH_VERIFY,
|
BMP_MODE_FLASH_VERIFY,
|
||||||
BMP_MODE_SWJ_TEST,
|
BMP_MODE_SWJ_TEST,
|
||||||
|
BMP_MODE_MONITOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BMP_CL_OPTIONS_s {
|
typedef struct BMP_CL_OPTIONS_s {
|
||||||
@ -48,9 +49,11 @@ typedef struct BMP_CL_OPTIONS_s {
|
|||||||
char *opt_flash_file;
|
char *opt_flash_file;
|
||||||
char *opt_device;
|
char *opt_device;
|
||||||
char *opt_serial;
|
char *opt_serial;
|
||||||
|
uint32_t opt_targetid;
|
||||||
char *opt_ident_string;
|
char *opt_ident_string;
|
||||||
int opt_position;
|
int opt_position;
|
||||||
char *opt_cable;
|
char *opt_cable;
|
||||||
|
char *opt_monitor;
|
||||||
int opt_debuglevel;
|
int opt_debuglevel;
|
||||||
int opt_target_dev;
|
int opt_target_dev;
|
||||||
uint32_t opt_flash_start;
|
uint32_t opt_flash_start;
|
||||||
|
@ -190,7 +190,8 @@ int platform_buffer_read(uint8_t *data, int maxsize)
|
|||||||
c = data;
|
c = data;
|
||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
|
|
||||||
tv.tv_usec = 1000 * cortexm_wait_timeout;
|
tv.tv_sec = cortexm_wait_timeout / 1000 ;
|
||||||
|
tv.tv_usec = 1000 * (cortexm_wait_timeout % 1000);
|
||||||
|
|
||||||
/* Look for start of response */
|
/* Look for start of response */
|
||||||
do {
|
do {
|
||||||
|
@ -322,7 +322,7 @@ uint64_t adiv5_ap_read_pidr(ADIv5_AP_t *ap, uint32_t addr)
|
|||||||
* DBGMCU_CR not set.
|
* DBGMCU_CR not set.
|
||||||
*
|
*
|
||||||
* Keep a copy of DEMCR at startup to restore with exit, to
|
* Keep a copy of DEMCR at startup to restore with exit, to
|
||||||
* not interrupt tracing initialed by the CPU.
|
* not interrupt tracing initiated by the CPU.
|
||||||
*/
|
*/
|
||||||
static bool cortexm_prepare(ADIv5_AP_t *ap)
|
static bool cortexm_prepare(ADIv5_AP_t *ap)
|
||||||
{
|
{
|
||||||
@ -339,6 +339,8 @@ static bool cortexm_prepare(ADIv5_AP_t *ap)
|
|||||||
while (true) {
|
while (true) {
|
||||||
adiv5_mem_write(ap, CORTEXM_DHCSR, &dhcsr_ctl, sizeof(dhcsr_ctl));
|
adiv5_mem_write(ap, CORTEXM_DHCSR, &dhcsr_ctl, sizeof(dhcsr_ctl));
|
||||||
dhcsr = adiv5_mem_read32(ap, CORTEXM_DHCSR);
|
dhcsr = adiv5_mem_read32(ap, CORTEXM_DHCSR);
|
||||||
|
/* ADIV5_DP_CTRLSTAT_READOK is always set e.g. on STM32F7 even so
|
||||||
|
CORTEXM_DHCS reads nonsense*/
|
||||||
/* On a sleeping STM32F7, invalid DHCSR reads with e.g. 0xffffffff and
|
/* On a sleeping STM32F7, invalid DHCSR reads with e.g. 0xffffffff and
|
||||||
* 0x0xA05F0000 may happen.
|
* 0x0xA05F0000 may happen.
|
||||||
* M23/33 will have S_SDE set when debug is allowed
|
* M23/33 will have S_SDE set when debug is allowed
|
||||||
@ -416,6 +418,8 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
|
|||||||
return; /* Halting failed! */
|
return; /* Halting failed! */
|
||||||
/* CPU now halted, read cidr again. */
|
/* CPU now halted, read cidr again. */
|
||||||
cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET);
|
cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET);
|
||||||
|
if ((cidr & ~CID_CLASS_MASK) != CID_PREAMBLE)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(ENABLE_DEBUG)
|
#if defined(ENABLE_DEBUG)
|
||||||
@ -604,9 +608,9 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel)
|
|||||||
#if defined(ENABLE_DEBUG)
|
#if defined(ENABLE_DEBUG)
|
||||||
uint32_t cfg = adiv5_ap_read(ap, ADIV5_AP_CFG);
|
uint32_t cfg = adiv5_ap_read(ap, ADIV5_AP_CFG);
|
||||||
DEBUG_INFO("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08" PRIx32
|
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);
|
" CSW=%08"PRIx32, apsel, ap->idr, cfg, ap->base, ap->csw);
|
||||||
DEBUG_INFO("AP#0 IDR = 0x%08" PRIx32 " (AHB-AP var%x rev%x)\n",
|
DEBUG_INFO(" (AHB-AP var%x rev%x)\n",
|
||||||
ap->idr, (ap->idr >> 4) & 0xf, ap->idr >> 28);
|
(ap->idr >> 4) & 0xf, ap->idr >> 28);
|
||||||
#endif
|
#endif
|
||||||
adiv5_ap_ref(ap);
|
adiv5_ap_ref(ap);
|
||||||
return ap;
|
return ap;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
* Copyright (C) 2011 Black Sphere Technologies Ltd.
|
||||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
* Copyright (C) 2020- 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -33,10 +34,25 @@
|
|||||||
#define SWDP_ACK_WAIT 0x02
|
#define SWDP_ACK_WAIT 0x02
|
||||||
#define SWDP_ACK_FAULT 0x04
|
#define SWDP_ACK_FAULT 0x04
|
||||||
|
|
||||||
int adiv5_swdp_scan(void)
|
static unsigned int make_packet_request(uint8_t RnW, uint16_t addr)
|
||||||
|
{
|
||||||
|
bool APnDP = addr & ADIV5_APnDP;
|
||||||
|
addr &= 0xff;
|
||||||
|
unsigned int request = 0x81; /* Park and Startbit */
|
||||||
|
if(APnDP) request ^= 0x22;
|
||||||
|
if(RnW) request ^= 0x24;
|
||||||
|
|
||||||
|
addr &= 0xC;
|
||||||
|
request |= (addr << 1) & 0x18;
|
||||||
|
if((addr == 4) || (addr == 8))
|
||||||
|
request ^= 0x20;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
int adiv5_swdp_scan(uint32_t targetid)
|
||||||
{
|
{
|
||||||
uint32_t ack;
|
uint32_t ack;
|
||||||
|
(void) targetid;
|
||||||
target_list_free();
|
target_list_free();
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
if (platform_swdptap_init()) {
|
if (platform_swdptap_init()) {
|
||||||
@ -60,7 +76,8 @@ int adiv5_swdp_scan(void)
|
|||||||
/* Read the SW-DP IDCODE register to syncronise */
|
/* Read the SW-DP IDCODE register to syncronise */
|
||||||
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
||||||
* allow the ack to be checked here. */
|
* allow the ack to be checked here. */
|
||||||
swd_proc.swdptap_seq_out(0xA5, 8);
|
uint32_t request = make_packet_request(ADIV5_LOW_READ, ADIV5_DP_IDCODE);
|
||||||
|
swd_proc.swdptap_seq_out(request, 8);
|
||||||
ack = swd_proc.swdptap_seq_in(3);
|
ack = swd_proc.swdptap_seq_in(3);
|
||||||
uint32_t idcode;
|
uint32_t idcode;
|
||||||
if((ack != SWDP_ACK_OK) || swd_proc.swdptap_seq_in_parity(&idcode, 32)) {
|
if((ack != SWDP_ACK_OK) || swd_proc.swdptap_seq_in_parity(&idcode, 32)) {
|
||||||
@ -122,22 +139,12 @@ uint32_t firmware_swdp_read(ADIv5_DP_t *dp, uint16_t addr)
|
|||||||
uint32_t firmware_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)
|
uint16_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
bool APnDP = addr & ADIV5_APnDP;
|
uint32_t request = make_packet_request(RnW, addr);
|
||||||
addr &= 0xff;
|
|
||||||
uint32_t request = 0x81;
|
|
||||||
uint32_t response = 0;
|
uint32_t response = 0;
|
||||||
uint32_t ack;
|
uint32_t ack;
|
||||||
platform_timeout timeout;
|
platform_timeout timeout;
|
||||||
|
|
||||||
if(APnDP && dp->fault) return 0;
|
if((addr & ADIV5_APnDP) && dp->fault) return 0;
|
||||||
|
|
||||||
if(APnDP) request ^= 0x22;
|
|
||||||
if(RnW) request ^= 0x24;
|
|
||||||
|
|
||||||
addr &= 0xC;
|
|
||||||
request |= (addr << 1) & 0x18;
|
|
||||||
if((addr == 4) || (addr == 8))
|
|
||||||
request ^= 0x20;
|
|
||||||
|
|
||||||
platform_timeout_set(&timeout, 2000);
|
platform_timeout_set(&timeout, 2000);
|
||||||
do {
|
do {
|
||||||
|
@ -458,6 +458,8 @@ bool cortexm_probe(ADIv5_AP_t *ap)
|
|||||||
PROBE(kinetis_probe); /* Older K-series */
|
PROBE(kinetis_probe); /* Older K-series */
|
||||||
} else if (ap->ap_partno == 0x4cb) { /* Cortex-M23 ROM */
|
} else if (ap->ap_partno == 0x4cb) { /* Cortex-M23 ROM */
|
||||||
PROBE(gd32f1_probe); /* GD32E23x uses GD32F1 peripherals */
|
PROBE(gd32f1_probe); /* GD32E23x uses GD32F1 peripherals */
|
||||||
|
} else if (ap->ap_partno == 0x4c0) { /* Cortex-M0+ ROM */
|
||||||
|
PROBE(lpc11xx_probe); /* some of the LPC8xx series, like LPC802 */
|
||||||
}
|
}
|
||||||
/* Info on PIDR of these parts wanted! */
|
/* Info on PIDR of these parts wanted! */
|
||||||
PROBE(sam3x_probe);
|
PROBE(sam3x_probe);
|
||||||
|
@ -326,6 +326,13 @@ bool kinetis_probe(target *t)
|
|||||||
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
|
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
|
||||||
kl_gen_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
|
kl_gen_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
|
||||||
break;
|
break;
|
||||||
|
case 0x148: /* S32K148 */
|
||||||
|
t->driver = "S32K148";
|
||||||
|
target_add_ram(t, 0x1FFE0000, 0x20000); /* SRAM_L, 128 KB */
|
||||||
|
target_add_ram(t, 0x20000000, 0x1f000); /* SRAM_H, 124 KB */
|
||||||
|
kl_gen_add_flash(t, 0x00000000, 0x00180000, 0x1000, K64_WRITE_LEN); /* P-Flash, 1536 KB, 4 KB Sectors */
|
||||||
|
kl_gen_add_flash(t, 0x10000000, 0x80000, 0x1000, K64_WRITE_LEN); /* FlexNVM, 512 KB, 4 KB Sectors */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
#define MIN_RAM_SIZE 1024
|
#define MIN_RAM_SIZE 1024
|
||||||
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
|
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
|
||||||
|
|
||||||
#define IAP_ENTRY_MOST 0x1fff1ff1 /* all except LPC84x */
|
#define IAP_ENTRY_MOST 0x1fff1ff1 /* all except LPC802, LPC804 & LPC84x */
|
||||||
#define IAP_ENTRY_84x 0x0f001ff1
|
#define IAP_ENTRY_84x 0x0f001ff1 /* LPC802, LPC804 & LPC84x */
|
||||||
#define IAP_RAM_BASE 0x10000000
|
#define IAP_RAM_BASE 0x10000000
|
||||||
|
|
||||||
#define LPC11XX_DEVICE_ID 0x400483F4
|
#define LPC11XX_DEVICE_ID 0x400483F4
|
||||||
@ -142,6 +142,25 @@ lpc11xx_probe(target *t)
|
|||||||
}
|
}
|
||||||
idcode = target_mem_read32(t, LPC8XX_DEVICE_ID);
|
idcode = target_mem_read32(t, LPC8XX_DEVICE_ID);
|
||||||
switch (idcode) {
|
switch (idcode) {
|
||||||
|
case 0x00008021: /* 802M001JDH20 */
|
||||||
|
case 0x00008022: /* 802M011JDH20 */
|
||||||
|
case 0x00008023: /* 802M001JDH16 */
|
||||||
|
case 0x00008024: /* 802M001JHI33 */
|
||||||
|
t->driver = "LPC802";
|
||||||
|
target_add_ram(t, 0x10000000, 0x800);
|
||||||
|
lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_84x);
|
||||||
|
target_add_commands(t, lpc11xx_cmd_list, "LPC802");
|
||||||
|
return true;
|
||||||
|
case 0x00008040: /* 804M101JBD64 */
|
||||||
|
case 0x00008041: /* 804M101JDH20 */
|
||||||
|
case 0x00008042: /* 804M101JDH24 */
|
||||||
|
case 0x00008043: /* 804M111JDH24 */
|
||||||
|
case 0x00008044: /* 804M101JHI33 */
|
||||||
|
t->driver = "LPC804";
|
||||||
|
target_add_ram(t, 0x10000000, 0x1000);
|
||||||
|
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_84x);
|
||||||
|
target_add_commands(t, lpc11xx_cmd_list, "LPC804");
|
||||||
|
return true;
|
||||||
case 0x00008100: /* LPC810M021FN8 */
|
case 0x00008100: /* LPC810M021FN8 */
|
||||||
case 0x00008110: /* LPC811M001JDH16 */
|
case 0x00008110: /* LPC811M001JDH16 */
|
||||||
case 0x00008120: /* LPC812M101JDH16 */
|
case 0x00008120: /* LPC812M101JDH16 */
|
||||||
@ -161,6 +180,18 @@ lpc11xx_probe(target *t)
|
|||||||
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
|
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
|
||||||
target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
|
target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
|
||||||
return true;
|
return true;
|
||||||
|
case 0x00008322: /* LPC832M101FDH20 */
|
||||||
|
t->driver = "LPC832";
|
||||||
|
target_add_ram(t, 0x10000000, 0x1000);
|
||||||
|
lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST);
|
||||||
|
target_add_commands(t, lpc11xx_cmd_list, "LPC832");
|
||||||
|
return true;
|
||||||
|
case 0x00008341: /* LPC8341201FHI33 */
|
||||||
|
t->driver = "LPC834";
|
||||||
|
target_add_ram(t, 0x10000000, 0x1000);
|
||||||
|
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
|
||||||
|
target_add_commands(t, lpc11xx_cmd_list, "LPC834");
|
||||||
|
return true;
|
||||||
case 0x00008441:
|
case 0x00008441:
|
||||||
case 0x00008442:
|
case 0x00008442:
|
||||||
case 0x00008443: /* UM11029 Rev.1.4 list 8442 */
|
case 0x00008443: /* UM11029 Rev.1.4 list 8442 */
|
||||||
|
@ -25,6 +25,13 @@
|
|||||||
* Reference manual - STM32H7x3 advanced ARM®-based 32-bit MCUs Rev.3
|
* Reference manual - STM32H7x3 advanced ARM®-based 32-bit MCUs Rev.3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While the ST document (RM 0433) claims that the stm32h750 only has 1 bank
|
||||||
|
* with 1 sector (128k) of user main memory flash (pages 151-152), we were able
|
||||||
|
* to write and successfully verify into other regions in bank 1 and also into
|
||||||
|
* bank 2 (0x0810 0000 as indicated for the other chips).
|
||||||
|
*/
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "target_internal.h"
|
#include "target_internal.h"
|
||||||
@ -199,13 +206,14 @@ static bool stm32h7_attach(target *t)
|
|||||||
target_mem_map_free(t);
|
target_mem_map_free(t);
|
||||||
|
|
||||||
/* Add RAM to memory map */
|
/* Add RAM to memory map */
|
||||||
|
/* Table 7. Memory map and default device memory area attributes RM 0433, pg 130 */
|
||||||
target_add_ram(t, 0x00000000, 0x10000); /* ITCM Ram, 64 k */
|
target_add_ram(t, 0x00000000, 0x10000); /* ITCM Ram, 64 k */
|
||||||
target_add_ram(t, 0x20000000, 0x20000); /* DTCM Ram, 128 k */
|
target_add_ram(t, 0x20000000, 0x20000); /* DTCM Ram, 128 k */
|
||||||
target_add_ram(t, 0x24000000, 0x80000); /* AXI Ram, 512 k */
|
target_add_ram(t, 0x24000000, 0x80000); /* AXI Ram, 512 k */
|
||||||
target_add_ram(t, 0x30000000, 0x20000); /* AHB SRAM1, 128 k */
|
target_add_ram(t, 0x30000000, 0x20000); /* AHB SRAM1, 128 k */
|
||||||
target_add_ram(t, 0x32000000, 0x20000); /* AHB SRAM2, 128 k */
|
target_add_ram(t, 0x30020000, 0x20000); /* AHB SRAM2, 128 k */
|
||||||
target_add_ram(t, 0x34000000, 0x08000); /* AHB SRAM3, 32 k */
|
target_add_ram(t, 0x30040000, 0x08000); /* AHB SRAM3, 32 k */
|
||||||
target_add_ram(t, 0x38000000, 0x01000); /* AHB SRAM4, 32 k */
|
target_add_ram(t, 0x38000000, 0x10000); /* AHB SRAM4, 64 k */
|
||||||
|
|
||||||
/* Add the flash to memory map. */
|
/* Add the flash to memory map. */
|
||||||
stm32h7_add_flash(t, 0x8000000, 0x100000, FLASH_SECTOR_SIZE);
|
stm32h7_add_flash(t, 0x8000000, 0x100000, FLASH_SECTOR_SIZE);
|
||||||
|
@ -69,13 +69,13 @@ target *target_new(void)
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool target_foreach(void (*cb)(int, target *t, void *context), void *context)
|
int target_foreach(void (*cb)(int, target *t, void *context), void *context)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
target *t = target_list;
|
target *t = target_list;
|
||||||
for (; t; t = t->next, i++)
|
for (; t; t = t->next, i++)
|
||||||
cb(i, t, context);
|
cb(i, t, context);
|
||||||
return target_list != NULL;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void target_mem_map_free(target *t)
|
void target_mem_map_free(target *t)
|
||||||
@ -100,7 +100,7 @@ void target_list_free(void)
|
|||||||
|
|
||||||
while(target_list) {
|
while(target_list) {
|
||||||
target *t = target_list->next;
|
target *t = target_list->next;
|
||||||
if (target_list->tc)
|
if (target_list->tc && target_list->tc->destroy_callback)
|
||||||
target_list->tc->destroy_callback(target_list->tc, target_list);
|
target_list->tc->destroy_callback(target_list->tc, target_list);
|
||||||
if (target_list->priv)
|
if (target_list->priv)
|
||||||
target_list->priv_free(target_list->priv);
|
target_list->priv_free(target_list->priv);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user