Compare commits

..

3 Commits

Author SHA1 Message Date
Jason Kotzin
2de5e2117e Force USB to connect after init 2018-07-07 08:34:39 -07:00
Jason Kotzin
3a7a59ab74 Support debugging on SAMD platforms 2018-07-07 08:34:18 -07:00
Jason Kotzin
f67c070b9f Use macro for reset so we can support ARMv6 2018-07-07 08:33:23 -07:00
208 changed files with 4516 additions and 27749 deletions

40
.gitattributes vendored
View File

@ -1,40 +0,0 @@
# 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
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: [esden, dragonmux]
patreon: 1bitsquared

View File

@ -1,36 +0,0 @@
name: build and upload
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Use embedded toolchain
- uses: numworks/setup-arm-toolchain@2020-q4
# Runs a single command using the runners shell
- name: Build
run: make
- name: Archive firmware build artifacts as a zip
uses: actions/upload-artifact@v2.2.4
with:
name: blackmagic-firmware.zip
path: src/blackmagic*
if-no-files-found: error

View File

@ -1,38 +0,0 @@
name: build PR
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Use embedded toolchain
- uses: numworks/setup-arm-toolchain@2020-q4
# Run some of the most common build types
- name: Build native fw
run: make
- name: Clean
run: make clean
- name: Install BMP PC hosted dependencies
run: sudo apt-get -y install libftdi1-dev libhidapi-dev
- name: Build PC hosted binary
run: make PROBE_HOST=hosted

8
.gitignore vendored
View File

@ -16,10 +16,4 @@ tags
*.b#* *.b#*
blackmagic_upgrade blackmagic_upgrade
*.exe *.exe
.DS_Store
*.elf
.vscode
cscope.out
cscope.files
.gdb_history
src/artifacts/

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "libopencm3"] [submodule "libopencm3"]
path = libopencm3 path = libopencm3
url = https://github.com/flirc/libopencm3.git url = https://github.com/libopencm3/libopencm3.git

View File

@ -1,11 +1,13 @@
dist: bionic dist: trusty
sudo: required sudo: required
before_install: before_install:
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -y build-essential libftdi-dev gcc-arm-embedded
- pip install --user intelhex - pip install --user intelhex
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev libftdi1 libftdi1-dev
install: true
script: script:
- make -C libopencm3 lib - make -C libopencm3 lib

View File

@ -1 +1 @@
See https://github.com/blackmagic-debug/blackmagic/wiki/Hacking See https://github.com/blacksphere/blackmagic/wiki/Hacking

View File

@ -3,37 +3,16 @@ MFLAGS += --no-print-dir
Q := @ Q := @
endif endif
PC_HOSTED =
NO_LIBOPENCM3 =
ifeq ($(PROBE_HOST), hosted)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
all: all:
ifndef NO_LIBOPENCM3
$(Q)if [ ! -f libopencm3/Makefile ]; then \ $(Q)if [ ! -f libopencm3/Makefile ]; then \
echo "Initialising git submodules..." ;\ echo "Initialising git submodules..." ;\
git submodule init ;\ git submodule init ;\
git submodule update ;\ git submodule update ;\
fi fi
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d $(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib
endif
$(Q)$(MAKE) $(MFLAGS) -C src $(Q)$(MAKE) $(MFLAGS) -C src
all_platforms:
$(Q)$(MAKE) $(MFLAGS) -C src $@
clean: clean:
ifndef NO_LIBOPENCM3
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@ $(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
endif
$(Q)$(MAKE) $(MFLAGS) -C src $@ $(Q)$(MAKE) $(MFLAGS) -C src $@
clang-tidy:
$(Q)scripts/run-clang-tidy.py -s "$(PWD)"
clang-format:
$(Q)$(MAKE) $(MFLAGS) -C src $@
.PHONY: clean all_platforms clang-tidy clang-format

View File

@ -1,54 +1,22 @@
Jeff Probe Black Magic Probe
========== =================
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic). [![Build Status](https://travis-ci.org/blacksphere/blackmagic.svg?branch=master)](https://travis-ci.org/blacksphere/blackmagic)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/blacksphere/blackmagic?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Donate](https://img.shields.io/badge/paypal-donate-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N84QYNAM2JJQG)
[![Kickstarter](https://img.shields.io/badge/kickstarter-back%20us-14e16e.svg)](https://www.kickstarter.com/projects/esden/1bitsy-and-black-magic-probe-demystifying-arm-prog)
The original is arguably better, faster and wider supported. However, this Firmware for the Black Magic Debug Probe.
project was a way to offer an affordable version and I'll rely on community
support and pull requests.
One urguably better funncton is the ability to do DEBUG and Serial communication The Black Magic Probe is a modern, in-application debugging tool for
over a single JTAG cable when paired with a device that uses single wire JTAG. embedded microprocessors. It allows you see what is going on 'inside' an
application running on an embedded microprocessor while it executes. It is
Normally, the serial header can be used on a target for the serial port, and able to control and examine the state of the target microprocessor using a
shows up as the second serial device on the system, however, we can dynamically JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
change the pins to use the ones on the JTAG cable with the following command: by the microprocessor. The probe connects to a host computer using a
standard USB interface. The user is able to control exactly what happens
``` bash using the GNU source level debugging software, GDB.
$ mon convert_tdio enable
```
Compilation
---
Newer toolchains can cause issues. I usually work 4_9-2014q4-20141203 found [here.](https://launchpad.net/gcc-arm-embedded/4.9/4.9-2014-q4-major/+download/gcc-arm-none-eabi-4_9-2014q4-20141203-mac.tar.bz2)
the versionfollowing version
```bash
$ make clean
$ make PROBE_HOST=jeff CUSTOM_SER=1
$ dfu-util --device ,1d50:6017 -s 0x00002000:leave -D src/blackmagic.bin
```
CUSTOM OPTIONS
---
On mac, our device shows up with a serial number /dev/tty.cuJEFF123HDC
This can be annoy if we want to autocnnect with a gith script. We can override
the use of a serial number by doing a custom compliation such that our device
shows up with the following: /dev/cu.usbmodemJEFF1 and /dev/cu.usbmodemJEFF3
```bash
$ make PROBE_HOST=jeff CUSTOM_SER=1
```
More
---
More helpful information can be found on the black magic probe [readme](https://github.com/blacksphere/blackmagic/blob/master/README.md#black-magic-probe), which is relevant.
See online documentation at https://github.com/blacksphere/blackmagic/wiki See online documentation at https://github.com/blacksphere/blackmagic/wiki
Binaries from the latest automated build can be found on the release page. Binaries from the latest automated build are at http://builds.blacksphere.co.nz/blackmagic

View File

@ -1,271 +0,0 @@
# Using RTT
When debugging arm processors, there are three ways for the target to print debug messages on the host: Semihosting, Serial Wire Output SWO, and Real-Time Transfer RTT.
[Black Magic Probe](https://github.com/blacksphere/blackmagic) (BMP) is an open source debugger probe that already implements Semihosting and Single Wire Output. This patch adds Real-Time Transfer RTT output to usb serial port.
- RTT is implemented, not as a user program, but as a serial port device. To read RTT output, use a terminal emulator and connect to the serial port.
- A novel way to detect RTT automatically, fast and convenient.
## Use
This example uses linux as operating system. For Windows and MacOS see the *Operating Systems* section.
In one window open a terminal emulator (minicom, putty) and connect to the usb uart:
```
$ minicom -c on -D /dev/ttyBmpTarg
```
In another window open a debugger:
```
$ gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
^C
(gdb) monitor rtt status
rtt: on found: yes ident: off halt: off channels: auto 0 1 3
max poll ms: 256 min poll ms: 8 max errs: 10
```
The terminal emulator displays RTT output from the target,
and characters typed in the terminal emulator are sent via RTT to the target.
## gdb commands
The following new gdb commands are available:
- ``monitor rtt``
switch rtt on
- ``monitor rtt enable``
switch rtt on
- ``monitor rtt disable``
switch rtt off
- ``monitor rtt poll `` max_poll_ms min_poll_ms max_errs
sets maximum time between polls, minimum time between polls, and the maximum number of errors before RTT disconnects from the target. Times in milliseconds. It is best if max_poll_ms/min_poll_ms is a power of two. As an example, if you wish to check for RTT output between once per second to eight times per second: ``monitor rtt poll 1000 125 10``.
- ``monitor rtt status``
show status.
rtt|found|state
---|---|---
rtt: off|found: no|rtt inactive
rtt: on|found: no|searching for rtt control block
rtt: on|found: yes|rtt active
rtt: off|found: yes|corrupt rtt control block, or target memory access error
A status of `rtt: on found: no` indicates bmp is still searching for the rtt control block in target ram, but has not found anything yet. A status of `rtt: on found: yes` indicates the control block has been found and rtt is active.
- ``monitor rtt channel``
enables the first two output channels, and the first input channel. (default)
- ``monitor rtt channel number...``
enables the given RTT channel numbers. Channels are numbers from 0 to 15, inclusive. Eg. ``monitor rtt channel 0 1 4`` to enable channels 0, 1, and 4.
- ``monitor rtt ident string``
sets RTT ident to *string*. If *string* contains a space, replace the space with an underscore _. Setting ident string is optional, RTT works fine without.
- ``monitor rtt ident``
clears ident string. (default)
- ``monitor rtt cblock``
shows rtt control block data, and which channels are enabled. This is an example control block:
```
(gdb) mon rtt cb
cbaddr: 0x200000a0
ch ena cfg i/o buf@ size head@ tail@ flg
0 y y out 0x20000148 1024 0x200000c4 0x200000c8 2
1 y n out 0x00000000 0 0x200000dc 0x200000e0 0
2 n n out 0x00000000 0 0x200000f4 0x200000f8 0
3 y y in 0x20000548 16 0x2000010c 0x20000110 0
4 n n in 0x00000000 0 0x20000124 0x20000128 0
5 n n in 0x00000000 0 0x2000013c 0x20000140 0
6 n n in 0x00000000 0 0x00000000 0x00000000 0
7 n n in 0x00000000 0 0x00000000 0x00000000 0
8 n n in 0x00000000 0 0x00000000 0x00000000 0
9 n n in 0x00000000 0 0x00000000 0x00000000 0
10 n n in 0x00000000 0 0x00000000 0x00000000 0
11 n n in 0x00000000 0 0x00000000 0x00000000 0
12 n n in 0x00000000 0 0x00000000 0x00000000 0
13 n n in 0x00000000 0 0x00000000 0x00000000 0
14 n n in 0x00000000 0 0x00000000 0x00000000 0
15 n n in 0x00000000 0 0x00000000 0x00000000 0
```
Channels are listed, one channel per line. The columns are: channel, enabled, configured, input/output, buffer address, buffer size, address of head pointer, address of tail pointer, flag. Each channel is a circular buffer with head and tail pointer.
Note the columns `ena` for enabled, `cfg` for configured.
Configured channels have a non-zero buffer address and non-zero size. Configured channels are marked yes `y` in the column `cfg` . What channels are configured depends upon target software.
Channels the user wants to see are marked yes `y` in the column enabled `ena`. The user can change which channels are shown with the `monitor rtt channel` command.
Output channels are displayed, and Input channels receive keyboard input, if they are marked yes in both *enabled* and *configured*.
The control block is cached for speed. In an interrupted program, `monitor rtt` will force a reload of the control block when the program continues.
## Identifier string
It is possible to set an RTT identifier string.
As an example, if the RTT identifier is "IDENT STR":
```
$ gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt ident IDENT_STR
(gdb) monitor rtt
(gdb) run
^C
(gdb) monitor rtt status
rtt: on found: yes ident: "IDENT STR" halt: off channels: auto 0 1 3
max poll ms: 256 min poll ms: 8 max errs: 10
```
Note replacing space with underscore _ in *monitor rtt ident*.
Setting an identifier string is optional. RTT gives the same output at the same speed, with or without specifying identifier string.
## Operating systems
[Configuration](https://github.com/blacksphere/blackmagic/wiki/Getting-Started) instructions for windows, linux and macos.
### Windows
After configuration, Black Magic Probe shows up in Windows as two _USB Serial (CDC)_ ports.
Connect arm-none-eabi-gdb, the gnu debugger for arm processors, to the lower numbered of the two COM ports. Connect an ansi terminal emulator to the higher numbered of the two COM ports.
Sample gdb session:
```
(gdb) target extended-remote COM3
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
For COM port COM10 and higher, add the prefix `\\.\`, e.g.
```
target extended-remote \\.\COM10
```
Target RTT output will appear in the terminal, and what you type in the terminal will be sent to the RTT input of the target.
### linux
On linux, install [udev rules](https://github.com/blacksphere/blackmagic/blob/master/driver/99-blackmagic.rules). Disconnect and re-connect the BMP. Check the device shows up in /dev/ :
```
$ ls -l /dev/ttyBmp*
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpGdb -> ttyACM0
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpTarg -> ttyACM2
```
Connect terminal emulator to /dev/ttyBmpTarg and gdb to /dev/ttyBmpGdb .
In one window:
```
minicom -c on -D /dev/ttyBmpTarg
```
In another window :
```
gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
### MacOS
On MacOS the tty devices have different names than on linux. On connecting blackmagic to the computer 4 devices are created, 2 'tty' and 2 'cu' devices. Gdb connects to the first cu device (e.g.: `target extended-remote /dev/cu.usbmodemDDCEC9EC1`), while RTT is connected to the second tty device (`minicom -c on -D /dev/tty.usbmodemDDCEC9EC3`). In full:
In one Terminal window, connect a terminal emulator to /dev/tty.usbmodemDDCEC9EC3 :
```
minicom -c on -D /dev/tty.usbmodemDDCEC9EC3
```
In another Terminal window, connect gdb to /dev/cu.usbmodemDDCEC9EC1 :
```
gdb
(gdb) target extended-remote /dev/cu.usbmodemDDCEC9EC1
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
RTT input/output is in the window running _minicom_.
## Notes
- Design goal was smallest, simplest implementation that has good practical use.
- RTT code size is 3.5 kbyte - the whole debugger 110 kbyte.
- Because RTT is implemented as a serial port device, there is no need to write and maintain software for different host operating systems. A serial port works everywhere - linux, windows and mac. You can even use an Android mobile phone as RTT terminal.
- Because polling occurs between debugger probe and target, the load on the host is small. There is no constant usb traffic, there are no real-time requirements on the host.
- RTT polling frequency is adaptive and goes up and down with RTT activity. Use *monitor rtt poll* to balance response speed and target load for your use.
- Detects RTT automatically, very convenient.
- When using RTT as a terminal, sending data from host to target, you may need to change local echo, carriage return and/or line feed settings in your terminal emulator.
- Architectures such as risc-v may not allow the debugger access to target memory while the target is running. As a workaround, on these architectures RTT briefly halts the target during polling. If the target is halted during polling, `monitor rtt status` shows `halt: on`.
- Measured RTT speed.
| debugger | char/s |
| ------------------------- | ------ |
| bmp stm32f723 stlinkv3 | 49811 |
| bmp stm32f411 black pill | 50073 |
| bmp stm32f103 blue pill | 50142 |
This is the speed at which characters can be sent from target to debugger probe, in reasonable circumstances. Test target is an stm32f103 blue pill running an [Arduino sketch](https://github.com/koendv/Arduino-RTTStream/blob/main/examples/SpeedTest/SpeedTest.ino). Default *monitor rtt poll* settings on debugger. Default RTT buffer size in target and debugger. Overhead for printf() calls included.
## Compiling firmware
To compile with RTT support, add *ENABLE_RTT=1*.
Eg. for STM32F103 blue pill:
```
make clean
make PROBE_HOST=stlink ENABLE_RTT=1
```
or for the STM32F411 *[Black Pill](https://www.aliexpress.com/item/1005001456186625.html)*:
```
make clean
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1
```
Setting an ident string is optional. But if you wish, you can set the default RTT ident at compile time.
For STM32F103 *Blue Pill*:
```
make clean
make PROBE_HOST=stlink ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
```
or for STM32F411 *Black Pill*:
```
make clean
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
```
Note the backslash \\ before the space.
## Links
- [OpenOCD](https://openocd.org/doc/html/General-Commands.html#Real-Time-Transfer-_0028RTT_0029)
- [probe-rs](https://probe.rs/) and [rtt-target](https://github.com/mvirkkunen/rtt-target) for the _rust_ programming language.
- [RTT Stream](https://github.com/koendv/Arduino-RTTStream) for Arduino on arm processors
- [\[WIP\] RTT support - PR from katyo](https://github.com/blacksphere/blackmagic/pull/833)

View File

@ -14,28 +14,24 @@ 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)/d...with d >= 16 or link. The UART baudrate is set by b=(72x10^6)/(16*d)...so for d=1 that means
a maximum speed of 4.5Mbps UART1 and 2.25 Mbps on UART2. a maximum speed of 4.5Mbps. For continious streaming that turns out to be
For continious streaming that turns out to be_too_ fast for the USB _too_ fast for the USB link, so the next available option is the 2.25Mbps
link, so the next available option is the 2.25Mbps that we use. .... that we use. ....you can safely use the 4.5Mbps setting if your debug data
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: available. The highest half dozen are;
BRR USART1(stlink) USART2(swlink)
16 4.50 Mbps 2.25 Mbps 1 4.50 Mbps
17 4.235 Mbps 2.118 Mbps 2 2.25 Mbps
18 4.000 Mbps 2.0 Mbps 3 1.50 Mbps
19 3.789 Mbps 1.895 Mbps 4 1.125 Mbps
20 3.600 Mbps 1.8 Mbps 5 0.900 Mbps
... 6 0.750 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
@ -54,14 +50,13 @@ An example for a STM32F103 for the UART (NRZ) data format that we use;
AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO
DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; // Enable IO trace pins DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; // Enable IO trace pins
TPI->ACPR = 31; // Output bits at 72000000/(31+1)=2.25MHz. *((volatile unsigned *)(0xE0040010)) = 31; // Output bits at 72000000/(31+1)=2.25MHz.
TPI->SPPR = 2; // Use Async mode (1 for RZ/Manchester) *((volatile unsigned *)(0xE00400F0)) = 2; // Use Async mode (1 for RZ/Manchester)
TPI-FFCR = 0; // Disable formatter *((volatile unsigned *)(0xE0040304)) = 0; // Disable formatter
/* Configure instrumentation trace macroblock */ /* Configure instrumentation trace macroblock */
ITM->LAR = 0xC5ACCE55; ITM->LAR = 0xC5ACCE55;
ITM->TCR = 1 << ITM_TCR_TraceBusID_Pos | ITM_TCR_SYNCENA_Msk | ITM->TCR = 0x00010005;
ITM_TCR_ITMENA_Msk;
ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports
Code for the STM32L476 might look like: Code for the STM32L476 might look like:
@ -113,13 +108,12 @@ Note that swolisten can be used with either BMP firmware, or with a
conventional TTL serial dongle. See at the bottom of this file for conventional TTL serial dongle. See at the bottom of this file for
information on how to use a dongle. information on how to use a dongle.
The command line to build the swolisten tool may look like: The command line to build the swolisten tool is;
E.g. for Ubuntu gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib -lusb-1.0 swolisten.c -o swolisten
gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib swolisten.c -o swolisten -lusb-1.0
E.g. For Opensuse: For Opensuse:
gcc -I /usr/include/libusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og -lusb-1.0 gcc -I /usr/include/libusb-1.0 -lusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og
...you will obviously need to change the paths to your libusb files. ...you will obviously need to change the paths to your libusb files.
@ -240,7 +234,7 @@ can pick this up. Success has been had with CP2102 dongles at up to 921600
baud. baud.
To use this mode just connect SWO to the RX pin of your dongle, and start To use this mode just connect SWO to the RX pin of your dongle, and start
swolisten with parameters representing the speed and port. An example; swolisten with parmeters representing the speed and port. An example;
>./swolisten -p /dev/cu.SLAB_USBtoUART -v -b swo/ -s 921600 >./swolisten -p /dev/cu.SLAB_USBtoUART -v -b swo/ -s 921600

View File

@ -1,8 +0,0 @@
# Black Magic Probe
# there are two connections, one for GDB and one for UART debugging
# copy this to /etc/udev/rules.d/99-blackmagic.rules
# and run /usr/sbin/udevadm control --reload-rules
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6018", MODE="0666"

View File

@ -13,17 +13,17 @@
Signature="$Windows NT$" Signature="$Windows NT$"
Class=Ports Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%BLACKMAGIC% Provider=%BLACKSPHERE%
DriverVer=28/12/2011,0.0.1.1 DriverVer=28/12/2011,0.0.1.1
[Manufacturer] [Manufacturer]
%VendorName%=DeviceList, NTamd64 %VendorName%=DeviceList, NTamd64
[Strings] [Strings]
VendorName = "Black Magic Debug" VendorName = "Black Sphere Technologies"
BLACKMAGICGDB = "Black Magic GDB Server" BLACKMAGICGDB = "Black Magic GDB Server"
BLACKMAGICUART = "Black Magic UART Port" BLACKMAGICUART = "Black Magic UART Port"
BLACKMAGIC_DISPLAY_NAME = "Black Magic Probe Driver" BLACKSPHERE_DISPLAY_NAME = "Black Magic Probe Driver"
[DeviceList] [DeviceList]
%BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00 %BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00
@ -55,7 +55,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
AddService = usbser,0x0002,DriverService.nt AddService = usbser,0x0002,DriverService.nt
[DriverService.nt] [DriverService.nt]
DisplayName = %BLACKMAGIC_DISPLAY_NAME% DisplayName = %BLACKSPHERE_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL ErrorControl = 1 ; SERVICE_ERROR_NORMAL
@ -80,7 +80,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
AddService = usbser,0x0002,DriverService.NTamd64 AddService = usbser,0x0002,DriverService.NTamd64
[DriverService.NTamd64] [DriverService.NTamd64]
DisplayName = %BLACKMAGIC_DISPLAY_NAME% DisplayName = %BLACKSPHERE_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL ErrorControl = 1 ; SERVICE_ERROR_NORMAL

View File

@ -4,7 +4,7 @@
DeviceName = "Black Magic Firmware Upgrade" DeviceName = "Black Magic Firmware Upgrade"
DeviceNameDFU = "Black Magic Probe (Upgrade)" DeviceNameDFU = "Black Magic Probe (Upgrade)"
DeviceNameTPA = "Black Magic Trace Capture" DeviceNameTPA = "Black Magic Trace Capture"
VendorName = "Black Magic Debug" VendorName = "Black Sphere Technologies"
SourceName = "Black Magic Firmware Upgrade Install Disk" SourceName = "Black Magic Firmware Upgrade Install Disk"
DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04" DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04"
DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100" DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100"

@ -1 +1 @@
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8 Subproject commit db7a8d71ca30dd9ce7947aa036897b910bdc4ad2

Binary file not shown.

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1 # bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
@ -28,100 +28,102 @@ class stm32_boot:
# Turn on target device in SystemMemory boot mode # Turn on target device in SystemMemory boot mode
self.serial.setDTR(1) self.serial.setDTR(1)
sleep(0.1) sleep(0.1);
self._sync() self._sync()
def _sync(self): def _sync(self):
# Send sync byte # Send sync byte
#print("sending sync byte") #print "sending sync byte"
self.serial.write(b"\x7f") self.serial.write("\x7F")
self._checkack() self._checkack()
def _sendcmd(self, cmd): def _sendcmd(self, cmd):
cmd = ord(cmd) if type(cmd) == int:
cmd = bytes((cmd, cmd ^ 0xff)) cmd = chr(cmd)
#print("sendcmd:", repr(cmd)) cmd += chr(ord(cmd) ^ 0xff)
#print "sendcmd:", repr(cmd)
self.serial.write(cmd) self.serial.write(cmd)
def _send(self, data): def _send(self, data):
csum = 0 csum = 0
for c in data: csum ^= c for c in data: csum ^= ord(c)
data = data + bytes((csum,)) data = data + chr(csum)
#print("sending:", repr(data)) #print "sending:", repr(data)
self.serial.write(data) self.serial.write(data)
def _checkack(self): def _checkack(self):
ACK = b"\x79" ACK = "\x79"
b = self.serial.read(1) b = self.serial.read(1)
if b != ACK: raise Exception("Invalid ack: %r" % b) if b != ACK: raise Exception("Invalid ack: %r" % b)
#print("got ack!") #print "got ack!"
def get(self): def get(self):
self._sendcmd(b"\x00") self._sendcmd("\x00")
self._checkack() self._checkack()
num = self.serial.read(1)[0] num = ord(self.serial.read(1))
data = self.serial.read(num+1) data = self.serial.read(num+1)
self._checkack() self._checkack()
return data return data
def eraseall(self): def eraseall(self):
# Send erase cmd # Send erase cmd
self._sendcmd(b"\x43") self._sendcmd("\x43")
self._checkack() self._checkack()
# Global erase # Global erase
self._sendcmd(b"\xff") self._sendcmd("\xff")
self._checkack() self._checkack()
def read(self, addr, len): def read(self, addr, len):
# Send read cmd # Send read cmd
self._sendcmd(b"\x11") self._sendcmd("\x11")
self._checkack() self._checkack()
# Send address # Send address
self._send(struct.pack(">L", addr)) self._send(struct.pack(">L", addr))
self._checkack() self._checkack()
# Send length # Send length
self._sendcmd(bytes((len-1,))) self._sendcmd(chr(len-1))
self._checkack() self._checkack()
return self.serial.read(len) return self.serial.read(len)
def write(self, addr, data): def write(self, addr, data):
# Send write cmd # Send write cmd
self._sendcmd(b"\x31") self._sendcmd("\x31")
self._checkack() self._checkack()
# Send address # Send address
self._send(struct.pack(">L", addr)) self._send(struct.pack(">L", addr))
self._checkack() self._checkack()
# Send data # Send data
self._send(bytes((len(data)-1,)) + data) self._send(chr(len(data)-1) + data)
self._checkack() self._checkack()
def write_protect(self, sectors): def write_protect(self, sectors):
# Send WP cmd # Send WP cmd
self._sendcmd(b"\x63") self._sendcmd("\x63")
self._checkack() self._checkack()
# Send sector list # Send sector list
self._send(bytes((len(sectors)-1,)) + bytes(sectors)) self._send(chr(len(sectors)-1) + "".join(chr(i) for i in sectors))
self._checkack() self._checkack()
# Resync after system reset # Resync after system reset
self._sync() self._sync()
def write_unprotect(self): def write_unprotect(self):
self._sendcmd(b"\x73") self._sendcmd("\x73")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
def read_protect(self): def read_protect(self):
self._sendcmd(b"\x82") self._sendcmd("\x82")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
def read_unprotect(self): def read_unprotect(self):
self._sendcmd(b"\x92") self._sendcmd("\x92")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
@ -131,12 +133,12 @@ if __name__ == "__main__":
from sys import stdout, argv, platform from sys import stdout, argv, platform
from getopt import getopt from getopt import getopt
if platform == "linux": if platform == "linux2":
print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print "\x1b\x5b\x48\x1b\x5b\x32\x4a" # clear terminal screen
print("STM32 SystemMemory Production Programmer -- version 1.1") print "STM32 SystemMemory Production Programmer -- version 1.1"
print("Copyright (C) 2011 Black Sphere Technologies") print "Copyright (C) 2011 Black Sphere Technologies"
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>") print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print() print
dev = "COM1" if platform == "win32" else "/dev/ttyUSB0" dev = "COM1" if platform == "win32" else "/dev/ttyUSB0"
baud = 115200 baud = 115200
@ -150,38 +152,38 @@ if __name__ == "__main__":
progfile = args[0] progfile = args[0]
except: except:
print("Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0]) print "Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0]
print("\t-d : Use target on interface <dev> (default: %s)" % dev) print "\t-d : Use target on interface <dev> (default: %s)" % dev
print("\t-b : Set device baudrate (default: %d)" % baud) print "\t-b : Set device baudrate (default: %d)" % baud
print("\t-a : Set programming address (default: 0x%X)" % addr) print "\t-a : Set programming address (default: 0x%X)" % addr
print() print
exit(-1) exit(-1)
prog = open(progfile, "rb").read() prog = open(progfile, "rb").read()
boot = stm32_boot(dev, baud) boot = stm32_boot(dev, baud)
cmds = boot.get() cmds = boot.get()
print("Target bootloader version: %d.%d\n" % (cmds[0] >> 4, cmds[0] % 0xf)) print "Target bootloader version: %d.%d\n" % (ord(cmds[0]) >> 4, ord(cmds[0]) % 0xf)
print("Removing device protection...") print "Removing device protection..."
boot.read_unprotect() boot.read_unprotect()
boot.write_unprotect() boot.write_unprotect()
print("Erasing target device...") print "Erasing target device..."
boot.eraseall() boot.eraseall()
addr = 0x8000000 addr = 0x8000000
while prog: while prog:
print("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255)), end=' ') print ("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255))),
stdout.flush() stdout.flush();
boot.write(addr, prog[:256]) boot.write(addr, prog[:256])
addr += 256 addr += 256
prog = prog[256:] prog = prog[256:]
print print
print("Enabling device protection...") print "Enabling device protection..."
boot.write_protect(range(0,2)) boot.write_protect(range(0,2))
#boot.read_protect() #boot.read_protect()
print("All operations completed.") print "All operations completed."
print print

53
scripts/dfu-convert.py Executable file → Normal file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/python2
# Written by Antonio Galea - 2010/11/18 # Written by Antonio Galea - 2010/11/18
# Distributed under Gnu LGPL 3.0 # Distributed under Gnu LGPL 3.0
@ -16,64 +16,57 @@ def consume(fmt,data,names):
n = struct.calcsize(fmt) n = struct.calcsize(fmt)
return named(struct.unpack(fmt,data[:n]),names),data[n:] return named(struct.unpack(fmt,data[:n]),names),data[n:]
def cstring(string): def cstring(string):
return string.split(b'\0',1)[0] return string.split('\0',1)[0]
def compute_crc(data): def compute_crc(data):
return 0xFFFFFFFF & -zlib.crc32(data) -1 return 0xFFFFFFFF & -zlib.crc32(data) -1
def parse(file,dump_images=False): def parse(file,dump_images=False):
print('File: "%s"' % file) print 'File: "%s"' % file
data = open(file,'rb').read() data = open(file,'rb').read()
crc = compute_crc(data[:-4]) crc = compute_crc(data[:-4])
prefix, data = consume('<5sBIB',data,'signature version size targets') prefix, data = consume('<5sBIB',data,'signature version size targets')
print('%(signature)r v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix
for t in range(prefix['targets']): for t in range(prefix['targets']):
tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements')
tprefix['num'] = t tprefix['num'] = t
if tprefix['named']: if tprefix['named']:
tprefix['name'] = cstring(tprefix['name']) tprefix['name'] = cstring(tprefix['name'])
else: else:
tprefix['name'] = b'' tprefix['name'] = ''
print('%(signature)r %(num)d, alt setting: %(altsetting)r, name: %(name)r, size: %(size)d, elements: %(elements)d' % tprefix) print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix
tsize = tprefix['size'] tsize = tprefix['size']
target, data = data[:tsize], data[tsize:] target, data = data[:tsize], data[tsize:]
for e in range(tprefix['elements']): for e in range(tprefix['elements']):
eprefix, target = consume('<2I',target,'address size') eprefix, target = consume('<2I',target,'address size')
eprefix['num'] = e eprefix['num'] = e
print(' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix) print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix
esize = eprefix['size'] esize = eprefix['size']
image, target = target[:esize], target[esize:] image, target = target[:esize], target[esize:]
if dump_images: if dump_images:
out = '%s.target%d.image%d.bin' % (file,t,e) out = '%s.target%d.image%d.bin' % (file,t,e)
open(out,'wb').write(image) open(out,'wb').write(image)
print(' DUMPED IMAGE TO "%s"' % out) print ' DUMPED IMAGE TO "%s"' % out
if len(target): if len(target):
print("target %d: PARSE ERROR" % t) print "target %d: PARSE ERROR" % t
suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)r, %(len)d, 0x%(crc)08x' % suffix) print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix
if crc != suffix['crc']: if crc != suffix['crc']:
print("CRC ERROR: computed crc32 is 0x%08x" % crc) print "CRC ERROR: computed crc32 is 0x%08x" % crc
data = data[16:] data = data[16:]
if data: if data:
print("PARSE ERROR") print "PARSE ERROR"
def build(file,targets,device=DEFAULT_DEVICE): def build(file,targets,device=DEFAULT_DEVICE):
data = b'' data = ''
for t,target in enumerate(targets): for t,target in enumerate(targets):
tdata = b'' tdata = ''
for image in target: for image in target:
tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata
trgt = b'Target'
st = b'ST...'
tdata = struct.pack('<6sBI255s2I',trgt,0,1,st,len(tdata),len(target)) + tdata
data += tdata data += tdata
data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data
dfu_se = b'DfuSe'
ufd = b'UFD'
data = struct.pack('<5sBIB',dfu_se,1,len(data)+11,len(targets)) + data
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
data += struct.pack('<4H3sB',0,d,v,0x011a,ufd,16) data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16)
crc = compute_crc(data) crc = compute_crc(data)
data += struct.pack('<I',crc) data += struct.pack('<I',crc)
open(file,'wb').write(data) open(file,'wb').write(data)
@ -103,15 +96,15 @@ if __name__=="__main__":
try: try:
address,binfile = arg.split(':',1) address,binfile = arg.split(':',1)
except ValueError: except ValueError:
print("Address:file couple '%s' invalid." % arg) print "Address:file couple '%s' invalid." % arg
sys.exit(1) sys.exit(1)
try: try:
address = int(address,0) & 0xFFFFFFFF address = int(address,0) & 0xFFFFFFFF
except ValueError: except ValueError:
print("Address %s invalid." % address) print "Address %s invalid." % address
sys.exit(1) sys.exit(1)
if not os.path.isfile(binfile): if not os.path.isfile(binfile):
print("Unreadable file '%s'." % binfile) print "Unreadable file '%s'." % binfile
sys.exit(1) sys.exit(1)
target.append({ 'address': address, 'data': open(binfile,'rb').read() }) target.append({ 'address': address, 'data': open(binfile,'rb').read() })
@ -123,7 +116,7 @@ if __name__=="__main__":
try: try:
address = address & 0xFFFFFFFF address = address & 0xFFFFFFFF
except ValueError: except ValueError:
print("Address %s invalid." % address) print "Address %s invalid." % address
sys.exit(1) sys.exit(1)
target.append({ 'address': address, 'data': data }) target.append({ 'address': address, 'data': data })
@ -134,13 +127,13 @@ if __name__=="__main__":
try: try:
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
except: except:
print("Invalid device '%s'." % device) print "Invalid device '%s'." % device
sys.exit(1) sys.exit(1)
build(outfile,[target],device) build(outfile,[target],device)
elif len(args)==1: elif len(args)==1:
infile = args[0] infile = args[0]
if not os.path.isfile(infile): if not os.path.isfile(infile):
print("Unreadable file '%s'." % infile) print "Unreadable file '%s'." % infile
sys.exit(1) sys.exit(1)
parse(infile, dump_images=options.dump_images) parse(infile, dump_images=options.dump_images)
else: else:

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# dfu.py: Access USB DFU class devices # dfu.py: Access USB DFU class devices
# Copyright (C) 2009 Black Sphere Technologies # Copyright (C) 2009 Black Sphere Technologies
@ -62,7 +62,7 @@ DFU_STATUS_ERROR_POR = 0x0d
DFU_STATUS_ERROR_UNKNOWN = 0x0e DFU_STATUS_ERROR_UNKNOWN = 0x0e
DFU_STATUS_ERROR_STALLEDPKT = 0x0f DFU_STATUS_ERROR_STALLEDPKT = 0x0f
class dfu_status: class dfu_status(object):
def __init__(self, buf): def __init__(self, buf):
self.bStatus = buf[0] self.bStatus = buf[0]
self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16) self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16)
@ -70,7 +70,7 @@ class dfu_status:
self.iString = buf[5] self.iString = buf[5]
class dfu_device: class dfu_device(object):
def __init__(self, dev, conf, iface): def __init__(self, dev, conf, iface):
self.dev = dev self.dev = dev
self.conf = conf self.conf = conf
@ -157,7 +157,7 @@ class dfu_device:
if ((status.bState == STATE_APP_DETACH) or if ((status.bState == STATE_APP_DETACH) or
(status.bState == STATE_DFU_MANIFEST_WAIT_RESET)): (status.bState == STATE_DFU_MANIFEST_WAIT_RESET)):
usb.reset(self.handle) usb.reset(self.handle)
return False return False
raise Exception raise Exception
@ -178,16 +178,16 @@ def finddevs():
if __name__ == "__main__": if __name__ == "__main__":
devs = finddevs() devs = finddevs()
if not devs: if not devs:
print("No devices found!") print "No devices found!"
exit(-1) exit(-1)
for dfu in devs: for dfu in devs:
handle = dfu[0].open() handle = dfu[0].open()
man = handle.getString(dfu[0].iManufacturer, 30) man = handle.getString(dfu[0].iManufacturer, 30)
product = handle.getString(dfu[0].iProduct, 30) product = handle.getString(dfu[0].iProduct, 30)
print("Device %s: ID %04x:%04x %s - %s" % (dfu[0].filename, print "Device %s: ID %04x:%04x %s - %s" % (dfu[0].filename,
dfu[0].idVendor, dfu[0].idProduct, man, product)) dfu[0].idVendor, dfu[0].idProduct, man, product)
print("%r, %r" % (dfu[1], dfu[2])) print "%r, %r" % (dfu[1], dfu[2])

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# gdb.py: Python module for low level GDB protocol implementation # gdb.py: Python module for low level GDB protocol implementation
# Copyright (C) 2009 Black Sphere Technologies # Copyright (C) 2009 Black Sphere Technologies
@ -24,12 +24,18 @@ import struct
import time import time
def hexify(s): def hexify(s):
"""Convert a bytes object into hex bytes representation""" """Convert a binary string into hex representation"""
return s.hex().encode() ret = ''
for c in s:
ret += "%02X" % ord(c)
return ret
def unhexify(s): def unhexify(s):
"""Convert a hex-encoded bytes into bytes object""" """Convert a hex string into binary representation"""
return bytes.fromhex(s.decode()) ret = ''
for i in range(0, len(s), 2):
ret += chr(int(s[i:i+2], 16))
return ret
class FakeSocket: class FakeSocket:
"""Emulate socket functions send and recv on a file object""" """Emulate socket functions send and recv on a file object"""
@ -49,183 +55,145 @@ class Target:
else: else:
self.sock = FakeSocket(sock) self.sock = FakeSocket(sock)
self.PacketSize=0x100 # default
def getpacket(self): def getpacket(self):
"""Return the first correctly received packet from GDB target""" """Return the first correctly received packet from GDB target"""
while True: while True:
while self.sock.recv(1) != b'$': while self.sock.recv(1) != '$': pass
pass
csum = 0 csum = 0
packet = [] # list-of-small-int packet = ''
while True: while True:
c, = self.sock.recv(1) c = self.sock.recv(1)
if c == ord('#'): if c == '#': break
break
if c == ord('$'): if c == '$':
packet = [] packet = ''
csum = 0 csum = 0
continue continue
if c == ord('}'): if c == '}':
c, = self.sock.recv(1) c = self.sock.recv(1)
csum += c + ord('}') csum += ord(c) + ord('}')
packet.append(c ^ 0x20) packet += chr(ord(c) ^ 0x20)
continue continue
packet.append(c) packet += c
csum += c csum += ord(c)
if (csum & 0xFF) == int(self.sock.recv(2),16): if (csum & 0xFF) == int(self.sock.recv(2),16): break
break
self.sock.send(b'-') self.sock.send('-')
self.sock.send('+')
return packet
self.sock.send(b'+')
return bytes(packet)
def putpacket(self, packet): def putpacket(self, packet):
"""Send packet to GDB target and wait for acknowledge """Send packet to GDB target and wait for acknowledge"""
packet is bytes or string"""
if type(packet) == str:
packet = packet.encode()
while True: while True:
out = [] self.sock.send('$')
csum = 0
for c in packet: for c in packet:
if (c in b'$#}'): if (c == '$') or (c == '#') or (c == '}'):
out.append(ord('}')) self.sock.send('}')
out.append(c ^ 0x20) self.sock.send(chr(ord(c) ^ 0x20))
csum += (ord(c) ^ 0x20) + ord('}')
else: else:
out.append(c) self.sock.send(c)
csum += ord(c)
csum = sum(out) self.sock.send('#')
outb = b'$'+bytes(out)+b'#%02X' % (csum & 0xff) self.sock.send("%02X" % (csum & 0xFF))
if self.sock.recv(1) == '+': break
self.sock.send(outb)
if self.sock.recv(1) == b'+':
break
def monitor(self, cmd): def monitor(self, cmd):
"""Send gdb "monitor" command to target""" """Send gdb "monitor" command to target"""
if type(cmd) == str:
cmd = cmd.encode()
ret = [] ret = []
self.putpacket(b"qRcmd," + hexify(cmd)) self.putpacket("qRcmd," + hexify(cmd))
while True: while True:
s = self.getpacket() s = self.getpacket()
if s == '': return None
if s == b'': if s == 'OK': return ret
return None if s.startswith('O'): ret.append(unhexify(s[1:]))
if s == b'OK':
return ret
if s.startswith(b'O'):
ret.append(unhexify(s[1:]))
else: else:
raise Exception('Invalid GDB stub response %r'%s.decode()) raise Exception('Invalid GDB stub response')
def attach(self, pid): def attach(self, pid):
"""Attach to target process (gdb "attach" command)""" """Attach to target process (gdb "attach" command)"""
self.putpacket(b"vAttach;%08X" % pid) self.putpacket("vAttach;%08X" % pid)
reply = self.getpacket() reply = self.getpacket()
if (reply == b'') or (reply[:1] == b'E'): if (len(reply) == 0) or (reply[0] == 'E'):
raise Exception('Failed to attach to remote pid %d' % pid) raise Exception('Failed to attach to remote pid %d' % pid)
def detach(self): def detach(self):
"""Detach from target process (gdb "detach" command)""" """Detach from target process (gdb "detach" command)"""
self.putpacket(b"D") self.putpacket("D")
if self.getpacket() != b'OK': if self.getpacket() != 'OK':
raise Exception("Failed to detach from remote process") raise Exception("Failed to detach from remote process")
def reset(self): def reset(self):
"""Reset the target system""" """Reset the target system"""
self.putpacket(b"r") self.putpacket("r")
def read_mem(self, addr, length): def read_mem(self, addr, length):
"""Read length bytes from target at address addr""" """Read length bytes from target at address addr"""
ret = b'' self.putpacket("m%08X,%08X" % (addr, length))
while length: reply = self.getpacket()
# print("Read") if (len(reply) == 0) or (reply[0] == 'E'):
packlen = min(length,self.PacketSize//2) raise Exception('Error reading memory at 0x%08X' % addr)
self.putpacket(b"m%08X,%08X" % (addr, packlen)) try:
reply = self.getpacket() data = unhexify(reply)
if (reply == b'') or (reply[:1] == b'E'): except Excpetion:
raise Exception('Error reading memory at 0x%08X' % addr) raise Exception('Invalid response to memory read packet: %r' % reply)
try: return data
data = unhexify(reply)
except Exception:
raise Exception('Invalid response to memory read packet: %r' % reply)
ret += data
length -= packlen
addr += packlen
return ret
def write_mem(self, addr, data): def write_mem(self, addr, data):
"""Write data to target at address addr""" """Write data to target at address addr"""
data = bytes(data) self.putpacket("X%08X,%08X:%s" % (addr, len(data), data))
if self.getpacket() != 'OK':
while data: raise Exception('Error writing to memory at 0x%08X' % addr)
d = data[:self.PacketSize-44]
data = data[len(d):]
#print("Writing %d bytes at 0x%X" % (len(d), addr))
pack = b"X%08X,%08X:%s" % (addr, len(d), d)
self.putpacket(pack)
if self.getpacket() != b'OK':
raise Exception('Error writing to memory at 0x%08X' % addr)
addr += len(d)
def read_regs(self): def read_regs(self):
"""Read target core registers""" """Read target core registers"""
self.putpacket(b"g") self.putpacket("g")
reply = self.getpacket() reply = self.getpacket()
if (reply == b'') or (reply[:1] == b'E'): if (len(reply) == 0) or (reply[0] == 'E'):
raise Exception('Error reading target core registers') raise Exception('Error reading memory at 0x%08X' % addr)
try: try:
data = unhexify(reply) data = unhexify(reply)
except Exception: except Excpetion:
raise Exception('Invalid response to registers read packet: %r' % reply) raise Exception('Invalid response to memory read packet: %r' % reply)
ret = array.array('I',data) return struct.unpack("=20L", data)
return ret
def write_regs(self, *regs): def write_regs(self, *regs):
"""Write target core registers""" """Write target core registers"""
data = struct.pack("=%dL" % len(regs), *regs) data = struct.pack("=%dL" % len(regs), *regs)
self.putpacket(b"G" + hexify(data)) self.putpacket("G" + hexify(data))
if self.getpacket() != b'OK': if self.getpacket() != 'OK':
raise Exception('Error writing to target core registers') raise Exception('Error writing to target core registers')
def memmap_read(self): def memmap_read(self):
"""Read the XML memory map from target""" """Read the XML memory map from target"""
offset = 0 offset = 0
ret = b'' ret = ''
while True: while True:
self.putpacket(b"qXfer:memory-map:read::%08X,%08X" % (offset, 512)) self.putpacket("qXfer:memory-map:read::%08X,%08X" % (offset, 512))
reply = self.getpacket() reply = self.getpacket()
if (reply[0] in b'ml'): if (reply[0] == 'm') or (reply[0] == 'l'):
offset += len(reply) - 1 offset += len(reply) - 1
ret += reply[1:] ret += reply[1:]
else: else:
raise Exception('Invalid GDB stub response %r'%reply) raise Exception("Invalid GDB stub response")
if reply[:1] == b'l': if reply[0] == 'l': return ret
return ret
def resume(self): def resume(self):
"""Resume target execution""" """Resume target execution"""
self.putpacket(b'c') self.putpacket("c")
def interrupt(self): def interrupt(self):
"""Interrupt target execution""" """Interrupt target execution"""
self.sock.send(b'\x03') self.sock.send("\x03")
def run_stub(self, stub, address, *args): def run_stub(self, stub, address, *args):
"""Execute a binary stub at address, passing args in core registers.""" """Execute a binary stub at address, passing args in core registers."""
@ -237,19 +205,11 @@ class Target:
regs[15] = address regs[15] = address
self.write_regs(*regs) self.write_regs(*regs)
self.resume() self.resume()
reply = None reply = self.getpacket()
while not reply: while not reply:
reply = self.getpacket() reply = self.getpacket()
if not reply.startswith(b"T05"): if not reply.startswith("T05"):
message = "Invalid stop response: %r" % reply raise Exception("Invalid stop response: %r" % reply)
try:
message += {'T02':' (SIGINT)',
'T05':' (SIGTRAP)',
'T0B':' (SIGSEGV)',
'T1D':' (SIGLOST)'}[reply]
except KeyError:
pass
raise Exception(message)
class FlashMemory: class FlashMemory:
def __init__(self, target, offset, length, blocksize): def __init__(self, target, offset, length, blocksize):
@ -257,29 +217,26 @@ class Target:
self.offset = offset self.offset = offset
self.length = length self.length = length
self.blocksize = blocksize self.blocksize = blocksize
self.blocks = list(None for i in range(length // blocksize)) self.blocks = list(None for i in range(length / blocksize))
def prog(self, offset, data): def prog(self, offset, data):
assert type(data)==bytes
assert ((offset >= self.offset) and assert ((offset >= self.offset) and
(offset + len(data) <= self.offset + self.length)) (offset + len(data) <= self.offset + self.length))
while data: while data:
index = (offset - self.offset) // self.blocksize index = (offset - self.offset) / self.blocksize
bloffset = (offset - self.offset) % self.blocksize bloffset = (offset - self.offset) % self.blocksize
bldata = data[:self.blocksize-bloffset] bldata = data[:self.blocksize-bloffset]
data = data[len(bldata):]; offset += len(bldata) data = data[len(bldata):]; offset += len(bldata)
if self.blocks[index] is None: # Initialize a clear block if self.blocks[index] is None: # Initialize a clear block
self.blocks[index] = bytes(0xff for i in range(self.blocksize)) self.blocks[index] = "".join(chr(0xff) for i in range(self.blocksize))
self.blocks[index] = (self.blocks[index][:bloffset] + bldata + self.blocks[index] = (self.blocks[index][:bloffset] + bldata +
self.blocks[index][bloffset+len(bldata):]) self.blocks[index][bloffset+len(bldata):])
def commit(self, progress_cb=None): def commit(self, progress_cb=None):
totalblocks = 0 totalblocks = 0
for b in self.blocks: for b in self.blocks:
if b is not None: if b is not None: totalblocks += 1
totalblocks += 1
block = 0 block = 0
for i in range(len(self.blocks)): for i in range(len(self.blocks)):
@ -290,28 +247,27 @@ class Target:
# Erase the block # Erase the block
data = self.blocks[i] data = self.blocks[i]
addr = self.offset + self.blocksize * i addr = self.offset + self.blocksize * i
if data is None: if data is None: continue
continue #print "Erasing flash at 0x%X" % (self.offset + self.blocksize*i)
#print("Erasing flash at 0x%X" % (self.offset + self.blocksize*i)) self.target.putpacket("vFlashErase:%08X,%08X" %
self.target.putpacket(b"vFlashErase:%08X,%08X" %
(self.offset + self.blocksize*i, self.blocksize)) (self.offset + self.blocksize*i, self.blocksize))
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to erase flash") raise Exception("Failed to erase flash")
while data: while data:
d = data[0:980] d = data[0:980]
data = data[len(d):] data = data[len(d):]
#print("Writing %d bytes at 0x%X" % (len(d), addr)) #print "Writing %d bytes at 0x%X" % (len(d), addr)
self.target.putpacket(b"vFlashWrite:%08X:%s" % (addr, d)) self.target.putpacket("vFlashWrite:%08X:%s" % (addr, d))
addr += len(d) addr += len(d)
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to write flash") raise Exception("Failed to write flash")
self.target.putpacket(b"vFlashDone") self.target.putpacket("vFlashDone")
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to commit") raise Exception("Failed to commit")
self.blocks = list(None for i in range(self.length // self.blocksize)) self.blocks = list(None for i in range(self.length / self.blocksize))
def flash_probe(self): def flash_probe(self):
@ -319,8 +275,7 @@ class Target:
xmldom = parseString(self.memmap_read()) xmldom = parseString(self.memmap_read())
for memrange in xmldom.getElementsByTagName("memory"): for memrange in xmldom.getElementsByTagName("memory"):
if memrange.getAttribute("type") != "flash": if memrange.getAttribute("type") != "flash": continue
continue
offset = eval(memrange.getAttribute("start")) offset = eval(memrange.getAttribute("start"))
length = eval(memrange.getAttribute("length")) length = eval(memrange.getAttribute("length"))
for property in memrange.getElementsByTagName("property"): for property in memrange.getElementsByTagName("property"):
@ -342,3 +297,5 @@ class Target:
def flash_commit(self, progress_cb=None): def flash_commit(self, progress_cb=None):
for m in self.mem: for m in self.mem:
m.commit(progress_cb) m.commit(progress_cb)

View File

@ -1,56 +1,60 @@
#!/usr/bin/env python3 #!/usr/bin/python
"""Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for """Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for
pasting into blackmagic's nrf51.c pasting into blackmagic's nrf51.c
""" """
import subprocess import subprocess,re
import re
import io
cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf5.c | tar -xO' cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf51.c | tar -xO'
class Spec(): class Spec():
def __repr__(self): def __repr__(self):
return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code) return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code)
proc = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) fd = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE).stdout
specdict = {} specdict={}
specs = [] specs=[]
spec = Spec() spec=Spec()
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): for line in fd.read().split('\n'):
m = re.search(r'/\*(.*)\*/',line) m=re.search('/\*(.*)\*/',line)
if m: if m:
lastcomment=m.group(1) lastcomment=m.group(1)
m = re.search(r'NRF51_DEVICE_DEF\((0x[0-9A-F]*),\s*"(.*)",\s*"(.*)",\s*"(.*)",\s*([0-9]*)\s*\),', line) m=re.search('.hwid.*=\s*(0x[0-9A-F]*),',line)
if m: if m:
spec.hwid = int(m.group(1), base=0) spec.hwid=int(m.group(1),base=0)
spec.variant = m.group(3) m=re.search('.variant.*=\s*"(.*)",',line)
spec.build_code = m.group(4) if m:
spec.flash_size_kb = int(m.group(5), base=0) spec.variant=m.group(1)
ram, flash = {'AA':(16,256), m=re.search('.build_code.*=\s*"(.*)",',line)
'AB':(16,128), if m:
'AC':(32,256)}[spec.variant[-2:]] spec.build_code=m.group(1)
assert flash == spec.flash_size_kb m=re.search('.flash_size_kb.*=\s*([0-9]*),',line)
if m:
spec.flash_size_kb=int(m.group(1),base=0)
ram,flash = {'AA':(16,256),
'AB':(16,128),
'AC':(32,256)}[spec.variant[-2:]]
assert flash==spec.flash_size_kb
spec.ram_size_kb = ram spec.ram_size_kb = ram
nicecomment = lastcomment.strip().replace('IC ','').replace('Devices ','').replace('.','') nicecomment =lastcomment.strip().replace('IC ','').replace('Devices ','').replace('.','')
spec.comment = nicecomment spec.comment=nicecomment
specdict.setdefault((ram,flash),[]).append(spec) specdict.setdefault((ram,flash),[]).append(spec)
specs.append(spec) specs.append(spec)
spec=Spec() spec=Spec()
for (ram,flash),specs in specdict.items(): for (ram,flash),specs in specdict.iteritems():
specs.sort(key=lambda x:x.hwid) specs.sort(key=lambda x:x.hwid)
for spec in specs: for spec in specs:
print("\tcase",spec) print "\tcase",spec
print('\t\tt->driver = "Nordic nRF51";') print '\t\tt->driver = "Nordic nRF51";'
print('\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram)) print '\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram)
print('\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash)) print '\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash)
print('\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);') print '\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);'
print('\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");') print '\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");'
print('\t\treturn true;') print '\t\treturn true;'

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# hexprog.py: Python application to flash a target with an Intel hex file # hexprog.py: Python application to flash a target with an Intel hex file
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import gdb import gdb
import struct
import time import time
# Microcode sequence to erase option bytes # Microcode sequence to erase option bytes
@ -30,16 +31,15 @@ def flash_write_hex(target, hexfile, progress_cb=None):
f = open(hexfile) f = open(hexfile)
addrhi = 0 addrhi = 0
for line in f: for line in f:
if line[0] != ':': if line[0] != ':': raise Exception("Error in hex file")
raise Exception("Error in hex file")
reclen = int(line[1:3], 16) reclen = int(line[1:3], 16)
addrlo = int(line[3:7], 16) addrlo = int(line[3:7], 16)
rectype = int(line[7:9], 16) rectype = int(line[7:9], 16);
if sum(x for x in bytes.fromhex(line[1:11+reclen*2])) & 0xff != 0: if sum(ord(x) for x in gdb.unhexify(line[1:11+reclen*2])) & 0xff != 0:
raise Exception("Checksum error in hex file") raise Exception("Checksum error in hex file")
if rectype == 0: # Data record if rectype == 0: # Data record
addr = (addrhi << 16) + addrlo addr = (addrhi << 16) + addrlo
data = bytes.fromhex(line[9:9+reclen*2]) data = gdb.unhexify(line[9:9+reclen*2])
target.flash_write_prepare(addr, data) target.flash_write_prepare(addr, data)
pass pass
elif rectype == 4: # High address record elif rectype == 4: # High address record
@ -55,7 +55,7 @@ def flash_write_hex(target, hexfile, progress_cb=None):
try: try:
target.flash_commit(progress_cb) target.flash_commit(progress_cb)
except: except:
print("Flash write failed! Is device protected?\n") print "Flash write failed! Is device protected?\n"
exit(-1) exit(-1)
@ -64,11 +64,11 @@ if __name__ == "__main__":
from sys import argv, platform, stdout from sys import argv, platform, stdout
from getopt import getopt from getopt import getopt
if platform == "linux": if platform == "linux2":
print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print ("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen
print("Black Magic Probe -- Target Production Programming Tool -- version 1.0") print("Black Magic Probe -- Target Production Programming Tool -- version 1.0")
print("Copyright (C) 2011 Black Sphere Technologies") print "Copyright (C) 2011 Black Sphere Technologies"
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>") print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print("") print("")
dev = "COM1" if platform == "win32" else "/dev/ttyACM0" dev = "COM1" if platform == "win32" else "/dev/ttyACM0"
@ -80,20 +80,13 @@ if __name__ == "__main__":
try: try:
opts, args = getopt(argv[1:], "sd:b:t:rR") opts, args = getopt(argv[1:], "sd:b:t:rR")
for opt in opts: for opt in opts:
if opt[0] == "-s": if opt[0] == "-s": scan = "swdp_scan"
scan = "swdp_scan" elif opt[0] == "-b": baud = int(opt[1])
elif opt[0] == "-b": elif opt[0] == "-d": dev = opt[1]
baud = int(opt[1]) elif opt[0] == "-t": targetno = int(opt[1])
elif opt[0] == "-d": elif opt[0] == "-r": unprot = True
dev = opt[1] elif opt[0] == "-R": prot = True
elif opt[0] == "-t": else: raise Exception()
targetno = int(opt[1])
elif opt[0] == "-r":
unprot = True
elif opt[0] == "-R":
prot = True
else:
raise Exception()
hexfile = args[0] hexfile = args[0]
except: except:
@ -108,44 +101,39 @@ if __name__ == "__main__":
exit(-1) exit(-1)
try: try:
s = Serial(dev) #, baud, timeout=0.1) s = Serial(dev, baud, timeout=3)
#s.setDTR(1) s.setDTR(1)
#s.flushInput() while s.read(1024):
pass
#while s.read(1024):
# pass
target = gdb.Target(s) target = gdb.Target(s)
except SerialException as e: except SerialException, e:
print("FATAL: Failed to open serial device!\n%s\n" % e[0]) print("FATAL: Failed to open serial device!\n%s\n" % e[0])
exit(-1) exit(-1)
try: try:
r = target.monitor("version") r = target.monitor("version")
for s in r: for s in r: print s,
print(s.decode(), end=' ') except SerialException, e:
except SerialException as e:
print("FATAL: Serial communication failure!\n%s\n" % e[0]) print("FATAL: Serial communication failure!\n%s\n" % e[0])
exit(-1) exit(-1)
#except: pass except: pass
print("Target device scan:") print "Target device scan:"
targetlist = None targetlist = None
r = target.monitor(scan) r = target.monitor(scan)
for s in r: for s in r:
print(s.decode(), end=' ') print s,
print() print
r = target.monitor("targets") r = target.monitor("targets")
for s in r: for s in r:
if s.startswith(b"No. Att Driver"): if s.startswith("No. Att Driver"): targetlist = []
targetlist = []
try: try:
if type(targetlist) is list: if type(targetlist) is list:
targetlist.append(int(s[:2])) targetlist.append(int(s[:2]))
except: except: pass
pass
#if not targetlist: #if not targetlist:
# print("FATAL: No usable targets found!\n") # print("FATAL: No usable targets found!\n")
@ -173,7 +161,7 @@ if __name__ == "__main__":
print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize)) print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize))
def progress(percent): def progress(percent):
print("Progress: %d%%\r" % percent, end=' ') print ("Progress: %d%%\r" % percent),
stdout.flush() stdout.flush()
print("Programming target") print("Programming target")
@ -191,3 +179,4 @@ if __name__ == "__main__":
target.detach() target.detach()
print("\nAll operations complete!\n") print("\nAll operations complete!\n")

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# stm32_mem.py: STM32 memory access using USB DFU class # stm32_mem.py: STM32 memory access using USB DFU class
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
# Copyright (C) 2017, 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) # Copyright (C) 2017 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
# Written by Gareth McMullin <gareth@blacksphere.co.nz> # Written by Gareth McMullin <gareth@blacksphere.co.nz>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -20,15 +20,15 @@
from time import sleep from time import sleep
import struct import struct
import os from sys import stdout, argv
from sys import stdout
import argparse import argparse
import usb
import dfu import dfu
CMD_GETCOMMANDS = 0x00 CMD_GETCOMMANDS = 0x00
CMD_SETADDRESSPOINTER = 0x21 CMD_SETADDRESSPOINTER = 0x21
CMD_ERASE = 0x41 CMD_ERASE = 0x41
def stm32_erase(dev, addr): def stm32_erase(dev, addr):
erase_cmd = struct.pack("<BL", CMD_ERASE, addr) erase_cmd = struct.pack("<BL", CMD_ERASE, addr)
@ -70,7 +70,7 @@ def stm32_read(dev):
return data return data
def stm32_manifest(dev): def stm32_manifest(dev):
dev.download(0, b"") dev.download(0, "")
while True: while True:
try: try:
status = dev.get_status() status = dev.get_status()
@ -79,86 +79,64 @@ def stm32_manifest(dev):
sleep(status.bwPollTimeout / 1000.0) sleep(status.bwPollTimeout / 1000.0)
if status.bState == dfu.STATE_DFU_MANIFEST: if status.bState == dfu.STATE_DFU_MANIFEST:
break break
def stm32_scan(args, test): def stm32_scan(args, test):
devs = dfu.finddevs() devs = dfu.finddevs()
bmp_devs = []
bmp = 0 bmp = 0
if not devs: if not devs:
if test: if test == True:
return return
print "No DFU devices found!"
print("No DFU devices found!")
exit(-1) exit(-1)
for dev in devs: for dev in devs:
try:
dfudev = dfu.dfu_device(*dev)
except:
# Exceptions are raised when current user doesn't have permissions
# for the specified USB device, but the device scan needs to
# continue
continue
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
if man == b"Black Sphere Technologies":
bmp = bmp + 1
bmp_devs.append(dev)
if bmp == 0:
if test:
return
print("No compatible device found\n")
exit(-1)
if bmp > 1 and not args.serial_target:
if test:
return
print("Found multiple devices:\n")
for dev in bmp_devs:
dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8')
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8')
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8')
print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct))
print("Manufacturer:\t %s" % man)
print("Product:\t %s" % product)
print("Serial:\t\t %s\n" % serial_no)
print("Select device with serial number!")
exit(-1)
for dev in bmp_devs:
dfudev = dfu.dfu_device(*dev) dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8') man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8') if man == "Black Sphere Technologies": bmp = bmp + 1
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8') if bmp == 0 :
if test == True:
return
print "No compatible device found\n"
exit(-1)
if bmp > 1 and not args.serial_target :
if test == True:
return
print "Found multiple devices:\n"
for dev in devs:
dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
print "Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)
print "Manufacturer:\t %s" % man
print "Product:\t %s" % product
print "Serial:\t\t %s\n" % serial_no
print "Select device with serial number!"
exit (-1)
for dev in devs:
dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
if args.serial_target: if args.serial_target:
if man == "Black Sphere Technologies" and serial_no == args.serial_target: if man == "Black Sphere Technologies" and serial_no == args.serial_target: break
break
else: else:
if man == "Black Sphere Technologies": if man == "Black Sphere Technologies": break
break print "Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)
print "Manufacturer:\t %s" % man
print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)) print "Product:\t %s" % product
print("Manufacturer:\t %s" % man) print "Serial:\t\t %s" % serial_no
print("Product:\t %s" % product) if args.serial_target and serial_no != args.serial_target:
print("Serial:\t\t %s" % serial_no) print "Serial number doesn't match!\n"
if args.serial_target and serial_no != args.serial_target:
print("Serial number doesn't match %s vs %s!\n" % (serial_no, args.serial_target))
exit(-2) exit(-2)
return dfudev return dfudev
if __name__ == "__main__": if __name__ == "__main__":
print("-") print
print("USB Device Firmware Upgrade - Host Utility -- version 1.2") print "USB Device Firmware Upgrade - Host Utility -- version 1.2"
print("Copyright (C) 2011 Black Sphere Technologies") print "Copyright (C) 2011 Black Sphere Technologies"
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>") print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print("-") print
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("progfile", help="Binary file to program") parser.add_argument("progfile", help="Binary file to program")
@ -170,48 +148,41 @@ if __name__ == "__main__":
try: try:
state = dfudev.get_state() state = dfudev.get_state()
except: except:
if args.manifest: exit(0) if args.manifest : exit(0)
print("Failed to read device state! Assuming APP_IDLE") print "Failed to read device state! Assuming APP_IDLE"
state = dfu.STATE_APP_IDLE state = dfu.STATE_APP_IDLE
if state == dfu.STATE_APP_IDLE: if state == dfu.STATE_APP_IDLE:
try: dfudev.detach()
dfudev.detach()
except:
pass
dfudev.release() dfudev.release()
print("Invoking DFU Device") print "Invoking DFU Device"
timeout = 0 timeout = 0
while True: while True :
sleep(1) sleep(0.5)
timeout = timeout + 0.5 timeout = timeout + 0.5
dfudev = stm32_scan(args, True) dfudev = stm32_scan(args, True)
if dfudev: break if dfudev: break
if timeout > 5: if timeout > 5 :
print("Error: DFU device did not appear") print "Error: DFU device did not appear"
exit(-1) exit(-1)
if args.manifest: if args.manifest :
stm32_manifest(dfudev) stm32_manifest(dfudev)
print("Invoking Application Device") print "Invoking Application Device"
exit(0) exit(0)
dfudev.make_idle() dfudev.make_idle()
file = open(args.progfile, "rb") file = open(args.progfile, "rb")
if (os.path.getsize(args.progfile) > 0x1f800):
print("File too large")
exit(0)
bin = file.read() bin = file.read()
product = dfudev.handle.getString(dfudev.dev.iProduct, 64).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 64)
if args.address: if args.address :
start = int(args.address, 0) start = int(args.address, 0)
else: else :
if "F4" in product or "STLINK-V3" in product: if "F4" in product:
start = 0x8004000 start = 0x8004000
else: else:
start = 0x8002000 start = 0x8002000
addr = start addr = start
while bin: while bin:
print("Programming memory at 0x%08X" % addr, end="\r") print ("Programming memory at 0x%08X\r" % addr),
stdout.flush() stdout.flush()
try: try:
# STM DFU bootloader erases always. # STM DFU bootloader erases always.
@ -220,12 +191,12 @@ if __name__ == "__main__":
# get evaluated and erase called only once per sector! # get evaluated and erase called only once per sector!
stm32_erase(dfudev, addr) stm32_erase(dfudev, addr)
except: except:
print("\nErase Timed out\n") print "\nErase Timed out\n"
break break
try: try:
stm32_set_address(dfudev, addr) stm32_set_address(dfudev, addr)
except: except:
print("\nSet Address Timed out\n") print "\nSet Address Timed out\n"
break break
stm32_write(dfudev, bin[:1024]) stm32_write(dfudev, bin[:1024])
bin = bin[1024:] bin = bin[1024:]
@ -234,28 +205,28 @@ if __name__ == "__main__":
bin = file.read() bin = file.read()
len = len(bin) len = len(bin)
addr = start addr = start
print("\n-") print
while bin: while bin:
try: try:
stm32_set_address(dfudev, addr) stm32_set_address(dfudev, addr)
data = stm32_read(dfudev) data = stm32_read(dfudev)
except: except:
# Abort silent if bootloader does not support upload # Abort silent if bootloader does not support upload
break break
print("Verifying memory at 0x%08X" % addr, end="\r") print ("Verifying memory at 0x%08X\r" % addr),
stdout.flush() stdout.flush()
if len > 1024: if len > 1024 :
size = 1024 size = 1024
else: else :
size = len size = len
if bin[:size] != bytearray(data[:size]): if bin[:size] != bytearray(data[:size]) :
print("\nMismatch in block at 0x%08X" % addr) print ("\nMitmatch in block at 0x%08X" % addr)
break break;
bin = bin[1024:] bin = bin[1024:]
addr += 1024 addr += 1024
len -= 1024 len -= 1024
if len <= 0: if len <= 0 :
print("\nVerified!") print "\nVerified!"
stm32_manifest(dfudev) stm32_manifest(dfudev)
print("All operations complete!\n") print "All operations complete!\n"

View File

@ -442,10 +442,7 @@ int usbFeeder(void)
{ {
unsigned char *c=cbw; unsigned char *c=cbw;
if (options.dump) if (options.dump)
{ printf(cbw);
cbw[size] = 0;
printf("%s", (char*)cbw);
}
else else
while (size--) while (size--)
_protocolPump(c++); _protocolPump(c++);

View File

@ -1,6 +1,6 @@
PROBE_HOST ?= native PROBE_HOST ?= native
PLATFORM_DIR = platforms/$(PROBE_HOST) PLATFORM_DIR = platforms/$(PROBE_HOST)
VPATH += $(PLATFORM_DIR) target VPATH += $(PLATFORM_DIR) platforms/common target
ENABLE_DEBUG ?= ENABLE_DEBUG ?=
ifneq ($(V), 1) ifneq ($(V), 1)
@ -8,9 +8,12 @@ MAKEFLAGS += --no-print-dir
Q := @ Q := @
endif endif
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \ OPT_FLAGS ?= -O2
-std=gnu99 -MD -I./target \
-I. -Iinclude -I$(PLATFORM_DIR) CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts\
$(OPT_FLAGS) -std=gnu99 -g3 -MD \
-I. -Iinclude -Iplatforms/common -I$(PLATFORM_DIR)
LDFLAGS += $(OPT_FLAGS)
ifeq ($(ENABLE_DEBUG), 1) ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -DENABLE_DEBUG CFLAGS += -DENABLE_DEBUG
@ -31,88 +34,37 @@ SRC = \
gdb_hostio.c \ gdb_hostio.c \
gdb_packet.c \ gdb_packet.c \
hex_utils.c \ hex_utils.c \
jtag_devs.c \
jtag_scan.c \ jtag_scan.c \
jtagtap.c \
jtagtap_generic.c \
lmi.c \ lmi.c \
lpc_common.c \ lpc_common.c \
lpc11xx.c \ lpc11xx.c \
lpc17xx.c \ lpc17xx.c \
lpc15xx.c \ lpc15xx.c \
lpc43xx.c \ lpc43xx.c \
lpc546xx.c \
kinetis.c \ kinetis.c \
main.c \ main.c \
morse.c \ morse.c \
msp432.c \ msp432.c \
nrf51.c \ nrf51.c \
nxpke04.c \
platform.c \ platform.c \
remote.c \
rp.c \
sam3x.c \ sam3x.c \
sam4l.c \ sam4l.c \
samd.c \ samd.c \
samx5x.c \
stm32f1.c \ stm32f1.c \
ch32f1.c \
stm32f4.c \ stm32f4.c \
stm32h7.c \
stm32l0.c \ stm32l0.c \
stm32l4.c \ stm32l4.c \
stm32g0.c \ swdptap.c \
swdptap_generic.c \
target.c \ target.c \
include $(PLATFORM_DIR)/Makefile.inc include $(PLATFORM_DIR)/Makefile.inc
OPT_FLAGS ?= -Os OBJ = $(SRC:.c=.o)
CFLAGS += $(OPT_FLAGS)
LDFLAGS += $(OPT_FLAGS)
ifndef TARGET blackmagic: include/version.h $(OBJ)
ifdef PC_HOSTED
TARGET = blackmagic
else
TARGET = blackmagic.elf
endif
endif
ifdef NO_OWN_LL
SRC += jtagtap_generic.c swdptap_generic.c
endif
ifdef PC_HOSTED
CFLAGS += -DPC_HOSTED=1
else
SRC += swdptap.c jtagtap.c
CFLAGS += -DPC_HOSTED=0
VPATH += platforms/common
CFLAGS += -Iplatforms/common
endif
ifeq ($(ENABLE_RTT), 1)
CFLAGS += -DENABLE_RTT
SRC += rtt.c rtt_if.c
endif
ifdef RTT_IDENT
CFLAGS += -DRTT_IDENT=$(RTT_IDENT)
endif
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
OPTIMIZE := swdptap.o jtagtap.o \
adiv5_jtagdp.o adiv5_swdp.o adiv5.o \
cortexa.o cortexm.o \
gdb_if.o gdb_main.o gdb_hostio.o gdb_packet.o \
jtag_devs.o jtag_scan.o \
crc32.o main.o \
cdcacm.o jeff.o timing.o traceswo.o usbuart.o \
$(OPTIMIZE):: CFLAGS := $(filter-out -Os, $(CFLAGS))
$(OPTIMIZE):: CFLAGS += -O3
$(TARGET): include/version.h $(OBJ)
@echo " LD $@" @echo " LD $@"
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS) $(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
@ -120,84 +72,45 @@ $(TARGET): include/version.h $(OBJ)
@echo " CC $<" @echo " CC $<"
$(Q)$(CC) $(CFLAGS) -c $< -o $@ $(Q)$(CC) $(CFLAGS) -c $< -o $@
%.o: %.S %.bin: %
@echo " AS $<"
$(Q)$(CC) $(CFLAGS) -c $< -o $@
ifndef PC_HOSTED
%.bin: %.elf
@echo " OBJCOPY $@" @echo " OBJCOPY $@"
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@ $(Q)$(OBJCOPY) -O binary $^ $@
%.hex: %.elf %.hex: %
@echo " OBJCOPY $@" @echo " OBJCOPY $@"
$(Q)$(OBJCOPY) -O ihex $^ $@ $(Q)$(OBJCOPY) -O ihex $^ $@
endif
.PHONY: clean host_clean all_platforms clang-format FORCE .PHONY: clean host_clean all_platforms FORCE
clean: host_clean clean: host_clean
$(Q)echo " CLEAN" $(Q)echo " CLEAN"
-$(Q)$(RM) *.o *.d *.elf *~ $(TARGET) $(HOSTFILES) -$(Q)$(RM) -f *.o *.d *~ blackmagic $(HOSTFILES)
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h -$(Q)$(RM) -f platforms/*/*.o platforms/*/*.d mapfile include/version.h
all_platforms: all_platforms:
$(Q)if [ ! -f ../libopencm3/Makefile ]; then \
echo "Initialising git submodules..." ;\
git submodule init ;\
git submodule update ;\
fi
$(Q)$(MAKE) $(MFLAGS) -C ../libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
$(Q)set -e ;\ $(Q)set -e ;\
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\ mkdir -p artifacts/$(shell git describe --always) ;\
echo "<html><body><ul>" > artifacts/index.html ;\ echo "<html><body><ul>" > artifacts/index.html ;\
$(MAKE) clean ;\
for i in platforms/*/Makefile.inc ; do \ for i in platforms/*/Makefile.inc ; do \
export DIRNAME=`dirname $$i` ;\ export DIRNAME=`dirname $$i` ;\
export PROBE_HOST=`basename $$DIRNAME` ;\ export PROBE_HOST=`basename $$DIRNAME` ;\
export CFLAGS=-Werror ;\ export CFLAGS=-Werror ;\
echo "Building for hardware platform: $$PROBE_HOST" ;\ echo "Building for hardware platform: $$PROBE_HOST" ;\
$(MAKE);\ $(MAKE) $(MAKEFLAGS) clean ;\
if [ -f blackmagic ]; then \ $(MAKE) $(MAKEFLAGS);\
mv blackmagic artifacts/blackmagic-$$PROBE_HOST ;\
echo "<li><a href='blackmagic-$$PROBE_HOST'>$$PROBE_HOST</a></li>"\
>> artifacts/index.html ;\
fi ;\
if [ -f blackmagic.bin ]; then \ if [ -f blackmagic.bin ]; then \
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\ mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\ echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
>> artifacts/index.html ;\ >> artifacts/index.html ;\
fi ;\ fi ;\
if [ -f blackmagic_dfu.bin ]; then \
mv blackmagic_dfu.bin artifacts/blackmagic_dfu-$$PROBE_HOST.bin ;\
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
>> artifacts/index.html ;\
fi ;\
$(MAKE) clean ;\
done ;\ done ;\
echo "</ul></body></html>" >> artifacts/index.html ;\ echo "</ul></body></html>" >> artifacts/index.html ;\
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags) cp artifacts/*.bin artifacts/$(shell git describe --always)
command.c: include/version.h command.c: include/version.h
GIT_VERSION := $(shell git describe --always --dirty --tags)
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
include/version.h: FORCE include/version.h: FORCE
@# If git isn't found then GIT_VERSION will be an empty string. $(Q)echo " GIT include/version.h"
ifeq ($(GIT_VERSION),) $(Q)echo "#define FIRMWARE_VERSION \"`git describe --always --dirty`\"" > $@
@echo Git not found, assuming up to date include/version.h
else
@# Note that when we echo the version to the header file, echo writes a final newline
@# to the file. This is fine and probably makes the file more human-readable, but
@# also means we have to account for that newline in this comparison.
$(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$$(echo '$(VERSION_HEADER)\n')" ]; then \
echo " GEN $@"; \
echo '$(VERSION_HEADER)' > $@; \
fi
endif
clang-format:
$(Q)clang-format -i *.c */*.c */*/*.c *.h */*.h */*/*.h
-include *.d -include *.d

View File

@ -3,8 +3,6 @@
* *
* 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
@ -29,107 +27,81 @@
#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"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
# include "traceswo.h" # include "traceswo.h"
#endif #endif
static bool cmd_version(target *t, int argc, char **argv); typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
#ifdef PLATFORM_HAS_PRINTSERIAL
static bool cmd_serial(target *t, int argc, char **argv); struct command_s {
#endif const char *cmd;
static bool cmd_help(target *t, int argc, char **argv); cmd_handler handler;
const char *help;
};
enum assert_srst_t{
ASSERT_NEVER = 0,
ASSERT_UNTIL_SCAN,
ASSERT_UNTIL_ATTACH
};
static bool cmd_version(void);
static bool cmd_help(target *t);
static bool cmd_jtag_scan(target *t, int argc, char **argv); static bool cmd_jtag_scan(target *t, int argc, char **argv);
static bool cmd_swdp_scan(target *t, int argc, char **argv); static bool cmd_swdp_scan(void);
static bool cmd_frequency(target *t, int argc, char **argv); static bool cmd_targets(void);
static bool cmd_targets(target *t, int argc, char **argv); static bool cmd_morse(void);
static bool cmd_morse(target *t, int argc, char **argv); static bool cmd_assert_srst(target *t, int argc, const char **argv);
static bool cmd_halt_timeout(target *t, int argc, const char **argv); static bool cmd_halt_timeout(target *t, int argc, const char **argv);
static bool cmd_connect_srst(target *t, int argc, const char **argv); static bool cmd_hard_srst(void);
static bool cmd_hard_srst(target *t, int argc, const char **argv);
#ifdef PLATFORM_HAS_POWER_SWITCH #ifdef PLATFORM_HAS_POWER_SWITCH
static bool cmd_target_power(target *t, int argc, const char **argv); static bool cmd_target_power(target *t, int argc, const char **argv);
#endif #endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
static bool cmd_traceswo(target *t, int argc, const char **argv); static bool cmd_traceswo(target *t, int argc, const char **argv);
#endif #endif
static bool cmd_heapinfo(target *t, int argc, const char **argv); #ifdef PLATFORM_HAS_DEBUG
#ifdef ENABLE_RTT
static bool cmd_rtt(target *t, int argc, const char **argv);
#endif
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
static bool cmd_debug_bmp(target *t, int argc, const char **argv); static bool cmd_debug_bmp(target *t, int argc, const char **argv);
#endif #endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv);
static bool cmd_set_srst(target *t, int argc, const char **argv);
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv);
#endif
const struct command_s cmd_list[] = { const struct command_s cmd_list[] = {
{"version", (cmd_handler)cmd_version, "Display firmware version info"}, {"version", (cmd_handler)cmd_version, "Display firmware version info"},
#ifdef PLATFORM_HAS_PRINTSERIAL
{"serial", (cmd_handler)cmd_serial, "Display firmware serial number"},
#endif
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"}, {"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" }, {"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" }, {"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
{"frequency", (cmd_handler)cmd_frequency, "set minimum high and low times" },
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" }, {"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
{"morse", (cmd_handler)cmd_morse, "Display morse error message" }, {"morse", (cmd_handler)cmd_morse, "Display morse error message" },
{"assert_srst", (cmd_handler)cmd_assert_srst, "Assert SRST until:(never(default)| scan | attach)" },
{"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" }, {"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" },
{"connect_srst", (cmd_handler)cmd_connect_srst, "Configure connect under SRST: (enable|disable)" },
{"hard_srst", (cmd_handler)cmd_hard_srst, "Force a pulse on the hard SRST line - disconnects target" }, {"hard_srst", (cmd_handler)cmd_hard_srst, "Force a pulse on the hard SRST line - disconnects target" },
#ifdef PLATFORM_HAS_POWER_SWITCH #ifdef PLATFORM_HAS_POWER_SWITCH
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"}, {"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
#endif #endif
#ifdef ENABLE_RTT
{"rtt", (cmd_handler)cmd_rtt, "enable|disable|status|channel 0..15|ident (str)|cblock|poll maxms minms maxerr" },
#endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2 {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture [(baudrate) for async swo]" },
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
#else
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, Manchester mode: (decode channel ...)" },
#endif #endif
#endif #ifdef PLATFORM_HAS_DEBUG
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
#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)"}, {"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
{"convert_tdio", (cmd_handler)cmd_convert_tdio,"Switch TDI/O pins to UART TX/RX functions"},
{"set_srst", (cmd_handler)cmd_set_srst,"Set output state of SRST pin (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
{"enter_bootldr", (cmd_handler)cmd_enter_bootldr,"Force BMP into bootloader mode"},
#endif #endif
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
bool connect_assert_srst; static enum assert_srst_t assert_srst;
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) #ifdef PLATFORM_HAS_DEBUG
bool debug_bmp; bool debug_bmp;
#endif #endif
unsigned cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */ long cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */
int command_process(target *t, char *cmd) int command_process(target *t, char *cmd)
{ {
const struct command_s *c; const struct command_s *c;
int argc = 1; int argc = 0;
const char **argv; const char **argv;
const char *part;
/* Initial estimate for argc */ /* Initial estimate for argc */
for(char *s = cmd; *s; s++) for(char *s = cmd; *s; s++)
@ -138,9 +110,8 @@ int command_process(target *t, char *cmd)
argv = alloca(sizeof(const char *) * argc); argv = alloca(sizeof(const char *) * argc);
/* Tokenize cmd to find argv */ /* Tokenize cmd to find argv */
argc = 0; for(argc = 0, argv[argc] = strtok(cmd, " \t");
for (part = strtok(cmd, " \t"); part; part = strtok(NULL, " \t")) argv[argc]; argv[++argc] = strtok(NULL, " \t"));
argv[argc++] = part;
/* Look for match and call handler */ /* Look for match and call handler */
for(c = cmd_list; c->cmd; c++) { for(c = cmd_list; c->cmd; c++) {
@ -157,39 +128,24 @@ int command_process(target *t, char *cmd)
return target_command(t, argc, argv); return target_command(t, argc, argv);
} }
#define BOARD_IDENT "Black Magic Probe" PLATFORM_IDENT FIRMWARE_VERSION bool cmd_version(void)
bool cmd_version(target *t, int argc, char **argv)
{ {
(void)t; gdb_outf("Black Magic Probe (Firmware " FIRMWARE_VERSION ") (Hardware Version %d)\n", platform_hwversion());
(void)argc; gdb_out("Copyright (C) 2015 Black Sphere Technologies Ltd.\n");
(void)argv;
#if PC_HOSTED == 1
char ident[256];
gdb_ident(ident, sizeof(ident));
DEBUG_WARN("%s\n", ident);
#else
gdb_out(BOARD_IDENT);
gdb_outf(", Hardware Version %d\n", platform_hwversion());
gdb_out("Copyright (C) 2022 Black Magic Debug Project\n");
gdb_out("License GPLv3+: GNU GPL version 3 or later " gdb_out("License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>\n\n"); "<http://gnu.org/licenses/gpl.html>\n\n");
#endif
return true; return true;
} }
bool cmd_help(target *t, int argc, char **argv) bool cmd_help(target *t)
{ {
(void)argc;
(void)argv;
const struct command_s *c; const struct command_s *c;
if (!t || t->tc->destroy_callback) { gdb_out("General commands:\n");
gdb_out("General commands:\n"); for(c = cmd_list; c->cmd; c++)
for(c = cmd_list; c->cmd; c++) gdb_outf("\t%s -- %s\n", c->cmd, c->help);
gdb_outf("\t%s -- %s\n", c->cmd, c->help);
}
if (!t) if (!t)
return -1; return -1;
@ -203,8 +159,7 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
(void)t; (void)t;
uint8_t irlens[argc]; uint8_t irlens[argc];
if (platform_target_voltage()) gdb_outf("Target voltage: %s\n", platform_target_voltage());
gdb_outf("Target voltage: %s\n", platform_target_voltage());
if (argc > 1) { if (argc > 1) {
/* Accept a list of IR lengths on command line */ /* Accept a list of IR lengths on command line */
@ -213,17 +168,15 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
irlens[argc-1] = 0; irlens[argc-1] = 0;
} }
if(connect_assert_srst) if(assert_srst != ASSERT_NEVER)
platform_srst_set_val(true); /* will be deasserted after attach */ platform_srst_set_val(true);
if(assert_srst == ASSERT_UNTIL_SCAN)
platform_srst_set_val(false);
int devs = -1; int devs = -1;
volatile struct exception e; volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) { 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); devs = jtag_scan(argc > 1 ? irlens : NULL);
#endif
} }
switch (e.type) { switch (e.type) {
case EXCEPTION_TIMEOUT: case EXCEPTION_TIMEOUT:
@ -239,32 +192,25 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
gdb_out("JTAG device scan failed!\n"); gdb_out("JTAG device scan failed!\n");
return false; return false;
} }
cmd_targets(NULL, 0, NULL); cmd_targets();
morse(NULL, false); morse(NULL, false);
return true; return true;
} }
bool cmd_swdp_scan(target *t, int argc, char **argv) bool cmd_swdp_scan(void)
{ {
(void)t; gdb_outf("Target voltage: %s\n", platform_target_voltage());
volatile uint32_t targetid = 0;
if (argc > 1)
targetid = strtol(argv[1], NULL, 0);
if (platform_target_voltage())
gdb_outf("Target voltage: %s\n", platform_target_voltage());
if(connect_assert_srst) if(assert_srst != ASSERT_NEVER)
platform_srst_set_val(true); /* will be deasserted after attach */ platform_srst_set_val(true);
if(assert_srst == ASSERT_UNTIL_SCAN)
platform_srst_set_val(false);
int devs = -1; int devs = -1;
volatile struct exception e; volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) { TRY_CATCH (e, EXCEPTION_ALL) {
#if PC_HOSTED == 1 devs = adiv5_swdp_scan();
devs = platform_adiv5_swdp_scan(targetid); }
#else
devs = adiv5_swdp_scan(targetid);
#endif
}
switch (e.type) { switch (e.type) {
case EXCEPTION_TIMEOUT: case EXCEPTION_TIMEOUT:
gdb_outf("Timeout during scan. Is target stuck in WFI?\n"); gdb_outf("Timeout during scan. Is target stuck in WFI?\n");
@ -280,59 +226,20 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
return false; return false;
} }
cmd_targets(NULL, 0, NULL); cmd_targets();
morse(NULL, false); morse(NULL, false);
return true; return true;
} }
bool cmd_frequency(target *t, int argc, char **argv)
{
(void)t;
if (argc == 2) {
char *p;
uint32_t frequency = strtol(argv[1], &p, 10);
switch(*p) {
case 'k':
frequency *= 1000;
break;
case 'M':
frequency *= 1000*1000;
break;
}
platform_max_frequency_set(frequency);
}
uint32_t freq = platform_max_frequency_get();
if (freq == FREQ_FIXED)
gdb_outf("SWJ freq fixed\n");
else
gdb_outf("Max SWJ freq %08" PRIx32 "\n", freq);
return true;
}
static void display_target(int i, target *t, void *context) static void display_target(int i, target *t, void *context)
{ {
(void)context; (void)context;
if (!strcmp(target_driver_name(t), "ARM Cortex-M")) { gdb_outf("%2d %c %s\n", i, target_attached(t)?'*':' ', target_driver_name(t));
gdb_outf("***%2d%sUnknown %s Designer %3x Partno %3x %s\n",
i, target_attached(t)?" * ":" ",
target_driver_name(t),
target_designer(t),
target_idcode(t),
(target_core_name(t)) ? target_core_name(t): "");
} else {
gdb_outf("%2d %c %s %s\n", i, target_attached(t)?'*':' ',
target_driver_name(t),
(target_core_name(t)) ? target_core_name(t): "");
}
} }
bool cmd_targets(target *t, int argc, char **argv) bool cmd_targets(void)
{ {
(void)t;
(void)argc;
(void)argv;
gdb_out("Available Targets:\n"); gdb_out("Available Targets:\n");
gdb_out("No. Att Driver\n"); gdb_out("No. Att Driver\n");
if (!target_foreach(display_target, NULL)) { if (!target_foreach(display_target, NULL)) {
@ -343,52 +250,27 @@ bool cmd_targets(target *t, int argc, char **argv)
return true; return true;
} }
bool cmd_morse(target *t, int argc, char **argv) bool cmd_morse(void)
{ {
(void)t; if(morse_msg)
(void)argc;
(void)argv;
if(morse_msg) {
gdb_outf("%s\n", morse_msg); gdb_outf("%s\n", morse_msg);
DEBUG_WARN("%s\n", morse_msg);
}
return true; return true;
} }
bool parse_enable_or_disable(const char *s, bool *out) { static bool cmd_assert_srst(target *t, int argc, const char **argv)
if (strlen(s) == 0) {
gdb_outf("'enable' or 'disable' argument must be provided\n");
return false;
} else if (!strncmp(s, "enable", strlen(s))) {
*out = true;
return true;
} else if (!strncmp(s, "disable", strlen(s))) {
*out = false;
return true;
} else {
gdb_outf("Argument '%s' not recognized as 'enable' or 'disable'\n", s);
return false;
}
}
static bool cmd_connect_srst(target *t, int argc, const char **argv)
{ {
(void)t; (void)t;
bool print_status = false; if (argc > 1) {
if (argc == 1) { if (!strcmp(argv[1], "attach"))
print_status = true; assert_srst = ASSERT_UNTIL_ATTACH;
} else if (argc == 2) { else if (!strcmp(argv[1], "scan"))
if (parse_enable_or_disable(argv[1], &connect_assert_srst)) { assert_srst = ASSERT_UNTIL_SCAN;
print_status = true; else
} assert_srst = ASSERT_NEVER;
} else {
gdb_outf("Unrecognized command format\n");
}
if (print_status) {
gdb_outf("Assert SRST during connect: %s\n",
connect_assert_srst ? "enabled" : "disabled");
} }
gdb_outf("Assert SRST %s\n",
(assert_srst == ASSERT_UNTIL_ATTACH) ? "until attach" :
(assert_srst == ASSERT_UNTIL_SCAN) ? "until scan" : "never");
return true; return true;
} }
@ -402,11 +284,8 @@ static bool cmd_halt_timeout(target *t, int argc, const char **argv)
return true; return true;
} }
static bool cmd_hard_srst(target *t, int argc, const char **argv) static bool cmd_hard_srst(void)
{ {
(void)t;
(void)argc;
(void)argv;
target_list_free(); target_list_free();
platform_srst_set_val(true); platform_srst_set_val(true);
platform_srst_set_val(false); platform_srst_set_val(false);
@ -417,101 +296,11 @@ static bool cmd_hard_srst(target *t, int argc, const char **argv)
static bool cmd_target_power(target *t, int argc, const char **argv) static bool cmd_target_power(target *t, int argc, const char **argv)
{ {
(void)t; (void)t;
if (argc == 1) { if (argc == 1)
gdb_outf("Target Power: %s\n", gdb_outf("Target Power: %s\n",
platform_target_get_power() ? "enabled" : "disabled"); platform_target_get_power() ? "enabled" : "disabled");
} else if (argc == 2) { else
bool want_enable = false; platform_target_set_power(!strncmp(argv[1], "enable", strlen(argv[1])));
if (parse_enable_or_disable(argv[1], &want_enable)) {
if (want_enable
&& !platform_target_get_power()
&& platform_target_voltage_sense() > POWER_CONFLICT_THRESHOLD) {
/* want to enable target power, but VREF > 0.5V sensed -> cancel */
gdb_outf("Target already powered (%s)\n", platform_target_voltage());
} else {
platform_target_set_power(want_enable);
gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling");
}
}
} else {
gdb_outf("Unrecognized command format\n");
}
return true;
}
#endif
#ifdef ENABLE_RTT
static const char *on_or_off(const bool value)
{
return value ? "on" : "off";
}
static bool cmd_rtt(target *t, int argc, const char **argv)
{
(void)t;
const size_t command_len = strlen(argv[1]);
if (argc == 1 || (argc == 2 && !strncmp(argv[1], "enabled", command_len))) {
rtt_enabled = true;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "disabled", command_len)) {
rtt_enabled = false;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "status", command_len)) {
gdb_outf("rtt: %s found: %s ident: \"%s\"", on_or_off(rtt_enabled), rtt_found ? "yes" : "no",
rtt_ident[0] == '\0' ? "off" : rtt_ident);
gdb_outf(" halt: %s", on_or_off(target_no_background_memory_access(t)));
gdb_out(" channels: ");
if (rtt_auto_channel)
gdb_out("auto ");
for (size_t i = 0; i < MAX_RTT_CHAN; i++) {
if (rtt_channel[i].is_enabled)
gdb_outf("%d ", i);
}
gdb_outf(
"\nmax poll ms: %u min poll ms: %u max errs: %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
} else if (argc >= 2 && !strncmp(argv[1], "channel", command_len)) {
/* mon rtt channel switches to auto rtt channel selection
mon rtt channel number... selects channels given */
for (size_t i = 0; i < MAX_RTT_CHAN; i++)
rtt_channel[i].is_enabled = false;
if (argc == 2)
rtt_auto_channel = true;
else {
rtt_auto_channel = false;
for (size_t i = 2; i < (size_t)argc; ++i) {
const uint32_t channel = strtoul(argv[i], NULL, 0);
if (channel < MAX_RTT_CHAN)
rtt_channel[channel].is_enabled = true;
}
}
} else if (argc == 2 && !strncmp(argv[1], "ident", command_len))
rtt_ident[0] = '\0';
else if (argc == 2 && !strncmp(argv[1], "poll", command_len))
gdb_outf("%u %u %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
else if (argc == 2 && !strncmp(argv[1], "cblock", command_len)) {
gdb_outf("cbaddr: 0x%x\n", rtt_cbaddr);
gdb_out("ch ena cfg i/o buf@ size head@ tail@ flg\n");
for (size_t i = 0; i < MAX_RTT_CHAN; ++i) {
gdb_outf("%2zu %c %c %s 0x%08x %5d 0x%08x 0x%08x %d\n", i, rtt_channel[i].is_enabled ? 'y' : 'n',
rtt_channel[i].is_configured ? 'y' : 'n', rtt_channel[i].is_output ? "out" : "in ",
rtt_channel[i].buf_addr, rtt_channel[i].buf_size, rtt_channel[i].head_addr, rtt_channel[i].tail_addr,
rtt_channel[i].flag);
}
} else if (argc == 3 && !strncmp(argv[1], "ident", command_len)) {
strncpy(rtt_ident, argv[2], sizeof(rtt_ident));
rtt_ident[sizeof(rtt_ident) - 1] = '\0';
for (size_t i = 0; i < sizeof(rtt_ident); i++) {
if (rtt_ident[i] == '_')
rtt_ident[i] = ' ';
}
} else if (argc == 5 && !strncmp(argv[1], "poll", command_len)) {
/* set polling params */
rtt_max_poll_ms = strtoul(argv[2], NULL, 0);
rtt_min_poll_ms = strtoul(argv[3], NULL, 0);
rtt_max_poll_errs = strtoul(argv[4], NULL, 0);
} else
gdb_out("what?\n");
return true; return true;
} }
#endif #endif
@ -519,151 +308,32 @@ static bool cmd_rtt(target *t, int argc, const char **argv)
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
static bool cmd_traceswo(target *t, int argc, const char **argv) static bool cmd_traceswo(target *t, int argc, const char **argv)
{ {
char serial_no[DFU_SERIAL_LENGTH]; #if defined(STM32L0) || defined(STM32F3) || defined(STM32F4)
(void)t; extern char serial_no[13];
#if TRACESWO_PROTOCOL == 2
uint32_t baudrate = SWO_DEFAULT_BAUD;
#endif
uint32_t swo_channelmask = 0; /* swo decoding off */
uint8_t decode_arg = 1;
#if TRACESWO_PROTOCOL == 2
/* argument: optional baud rate for async mode */
if ((argc > 1) && (*argv[1] >= '0') && (*argv[1] <= '9')) {
baudrate = atoi(argv[1]);
if (baudrate == 0) baudrate = SWO_DEFAULT_BAUD;
decode_arg = 2;
}
#endif
/* argument: 'decode' literal */
if((argc > decode_arg) && !strncmp(argv[decode_arg], "decode", strlen(argv[decode_arg]))) {
swo_channelmask = 0xFFFFFFFF; /* decoding all channels */
/* arguments: channels to decode */
if (argc > decode_arg + 1) {
swo_channelmask = 0x0;
for (int i = decode_arg+1; i < argc; i++) { /* create bitmask of channels to decode */
int channel = atoi(argv[i]);
if ((channel >= 0) && (channel <= 31))
swo_channelmask |= (uint32_t)0x1 << channel;
}
}
}
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) && defined(ENABLE_DEBUG)
if (debug_bmp) {
#if TRACESWO_PROTOCOL == 2
gdb_outf("baudrate: %lu ", baudrate);
#endif
gdb_outf("channel mask: ");
for (int8_t i=31;i>=0;i--) {
uint8_t bit = (swo_channelmask >> i) & 0x1;
gdb_outf("%u", bit);
}
gdb_outf("\n");
}
#endif
#if TRACESWO_PROTOCOL == 2
traceswo_init(baudrate, swo_channelmask);
#else #else
traceswo_init(swo_channelmask); extern char serial_no[9];
#endif #endif
serial_no_read(serial_no); uint32_t baudrate = 0;
(void)t;
if (argc > 1)
baudrate = atoi(argv[1]);
traceswo_init(baudrate);
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85); gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
return true; return true;
} }
#endif #endif
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) #ifdef PLATFORM_HAS_DEBUG
static bool cmd_debug_bmp(target *t, int argc, const char **argv) static bool cmd_debug_bmp(target *t, int argc, const char **argv)
{ {
(void)t; (void)t;
bool print_status = false;
if (argc == 1) {
print_status = true;
} else if (argc == 2) {
if (parse_enable_or_disable(argv[1], &debug_bmp)) {
print_status = true;
}
} else {
gdb_outf("Unrecognized command format\n");
}
if (print_status) {
gdb_outf("Debug mode is %s\n",
debug_bmp ? "enabled" : "disabled");
}
return true;
}
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv)
{
(void)t;
uint8_t val;
if (argc > 1) { if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false; debug_bmp = !strcmp(argv[1], "enable");
usbuart_convert_tdio(val);
} else {
gdb_outf("Convert_tdio: %s\n",(usbuart_convert_tdio_enabled()) ?
"enabled" : "disabled");
} }
gdb_outf("Debug mode is %s\n",
return true; debug_bmp ? "enabled" : "disabled");
}
static bool cmd_set_srst(target *t, int argc, const char **argv)
{
(void) t;
uint8_t val;
if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false;
platform_srst_set_val(val);
} else {
gdb_outf("SRST: %s\n",(platform_srst_get_val()) ?
"enabled" : "disabled");
}
return true; return true;
} }
#endif #endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv)
{
(void) t;
(void) argc;
(void) argv;
scb_reset_system();
return true;
}
#endif
#ifdef PLATFORM_HAS_PRINTSERIAL
bool cmd_serial(target *t, int argc, char **argv)
{
(void) t;
(void) argc;
(void) argv;
print_serial();
return true;
}
#endif
static bool cmd_heapinfo(target *t, int argc, const char **argv)
{
if (t == NULL) gdb_out("not attached\n");
else if (argc == 5) {
target_addr heap_base = strtoul(argv[1], NULL, 16);
target_addr heap_limit = strtoul(argv[2], NULL, 16);
target_addr stack_base = strtoul(argv[3], NULL, 16);
target_addr stack_limit = strtoul(argv[4], NULL, 16);
gdb_outf("heapinfo heap_base: %p heap_limit: %p stack_base: %p stack_limit: %p\n",
heap_base, heap_limit, stack_base, stack_limit);
target_set_heapinfo(t, heap_base, heap_limit, stack_base, stack_limit);
} else gdb_outf("heapinfo heap_base heap_limit stack_base stack_limit\n");
return true;
}

View File

@ -20,12 +20,8 @@
#include "general.h" #include "general.h"
#include "target.h" #include "target.h"
#include "gdb_if.h"
#if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \ #if !defined(STM32F1) && !defined(STM32F4)
!defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \
!defined(STM32L0) && !defined(STM32L1) && !defined(STM32F4) && \
!defined(STM32G0) && !defined(STM32G4)
static const uint32_t crc32_table[] = { static const uint32_t crc32_table[] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
@ -98,33 +94,14 @@ static uint32_t crc32_calc(uint32_t crc, uint8_t data)
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255]; return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
} }
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len) uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{ {
uint32_t crc = -1; uint32_t crc = -1;
#if PC_HOSTED == 1
/* Reading a 2 MByte on a H743 takes about 80 s@128, 28s @ 1k,
* 22 s @ 4k and 21 s @ 64k
*/
uint8_t bytes[0x1000];
#else
uint8_t bytes[128]; uint8_t bytes[128];
#endif
#if defined(ENABLE_DEBUG)
uint32_t start_time = platform_time_ms();
#endif
uint32_t last_time = platform_time_ms();
while (len) { while (len) {
uint32_t actual_time = platform_time_ms();
if ( actual_time > last_time + 1000) {
last_time = actual_time;
gdb_if_putchar(0, true);
}
size_t read_len = MIN(sizeof(bytes), len); size_t read_len = MIN(sizeof(bytes), len);
if (target_mem_read(t, bytes, base, read_len)) { target_mem_read(t, bytes, base, read_len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
for (unsigned i = 0; i < read_len; i++) for (unsigned i = 0; i < read_len; i++)
crc = crc32_calc(crc, bytes[i]); crc = crc32_calc(crc, bytes[i]);
@ -132,32 +109,20 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
base += read_len; base += read_len;
len -= read_len; len -= read_len;
} }
DEBUG_WARN("%" PRIu32 " ms\n", platform_time_ms() - start_time); return crc;
*crc_res = crc;
return 0;
} }
#else #else
#include <libopencm3/stm32/crc.h> #include <libopencm3/stm32/crc.h>
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len) uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{ {
uint8_t bytes[128]; uint8_t bytes[128];
uint32_t crc; uint32_t crc;
CRC_CR |= CRC_CR_RESET; CRC_CR |= CRC_CR_RESET;
uint32_t last_time = platform_time_ms();
while (len > 3) { while (len > 3) {
uint32_t actual_time = platform_time_ms();
if ( actual_time > last_time + 1000) {
last_time = actual_time;
gdb_if_putchar(0, true);
}
size_t read_len = MIN(sizeof(bytes), len) & ~3; size_t read_len = MIN(sizeof(bytes), len) & ~3;
if (target_mem_read(t, bytes, base, read_len)) { target_mem_read(t, bytes, base, read_len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
for (unsigned i = 0; i < read_len; i += 4) for (unsigned i = 0; i < read_len; i += 4)
CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i)); CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i));
@ -168,11 +133,7 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
crc = CRC_DR; crc = CRC_DR;
if (target_mem_read(t, bytes, base, len)) { target_mem_read(t, bytes, base, len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
uint8_t *data = bytes; uint8_t *data = bytes;
while (len--) { while (len--) {
crc ^= *data++ << 24; crc ^= *data++ << 24;
@ -183,8 +144,7 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
crc <<= 1; crc <<= 1;
} }
} }
*crc_res = crc; return crc;
return 0;
} }
#endif #endif

View File

@ -26,6 +26,7 @@ struct exception *innermost_exception;
void raise_exception(uint32_t type, const char *msg) void raise_exception(uint32_t type, const char *msg)
{ {
struct exception *e; struct exception *e;
DEBUG("Exception: %s\n", msg);
for (e = innermost_exception; e; e = e->outer) { for (e = innermost_exception; e; e = e->outer) {
if (e->mask & type) { if (e->mask & type) {
e->type = type; e->type = type;
@ -34,7 +35,6 @@ void raise_exception(uint32_t type, const char *msg)
longjmp(e->jmpbuf, type); longjmp(e->jmpbuf, type);
} }
} }
DEBUG_WARN("Unhandled exception: %s\n", msg);
abort(); abort();
} }

View File

@ -130,3 +130,4 @@ int hostio_system(struct target_controller *tc,
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len); gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true); return gdb_main_loop(tc, true);
} }

View File

@ -25,7 +25,6 @@
*/ */
#include "general.h" #include "general.h"
#include "ctype.h"
#include "hex_utils.h" #include "hex_utils.h"
#include "gdb_if.h" #include "gdb_if.h"
#include "gdb_packet.h" #include "gdb_packet.h"
@ -35,9 +34,6 @@
#include "command.h" #include "command.h"
#include "crc32.h" #include "crc32.h"
#include "morse.h" #include "morse.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
enum gdb_signal { enum gdb_signal {
GDB_SIGINT = 2, GDB_SIGINT = 2,
@ -46,37 +42,25 @@ enum gdb_signal {
GDB_SIGLOST = 29, GDB_SIGLOST = 29,
}; };
#define BUF_SIZE 1024U #define BUF_SIZE 1024
#define ERROR_IF_NO_TARGET() \ #define ERROR_IF_NO_TARGET() \
if(!cur_target) { gdb_putpacketz("EFF"); break; } if(!cur_target) { gdb_putpacketz("EFF"); break; }
typedef struct static char pbuf[BUF_SIZE+1];
{
const char *cmd_prefix;
void (*func)(const char *packet, size_t len);
} cmd_executer;
static char pbuf[BUF_SIZE + 1U];
static target *cur_target; static target *cur_target;
static target *last_target; static target *last_target;
static bool gdb_needs_detach_notify = false;
static void handle_q_packet(char *packet, size_t len); static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, size_t len); static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, size_t len); static void handle_z_packet(char *packet, int len);
static void handle_kill_target(void);
static void gdb_target_destroy_callback(struct target_controller *tc, target *t) static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
{ {
(void)tc; (void)tc;
if (cur_target == t) { if (cur_target == t)
gdb_put_notificationz("%Stop:W00");
gdb_out("You are now detached from the previous target.\n");
cur_target = NULL; cur_target = NULL;
gdb_needs_detach_notify = true;
}
if (last_target == t) if (last_target == t)
last_target = NULL; last_target = NULL;
@ -109,22 +93,24 @@ static struct target_controller gdb_controller = {
int gdb_main_loop(struct target_controller *tc, bool in_syscall) int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{ {
int size;
bool single_step = false; bool single_step = false;
/* GDB protocol main loop */ /* GDB protocol main loop */
while (1) { while(1) {
SET_IDLE_STATE(1); SET_IDLE_STATE(1);
size_t size = gdb_getpacket(pbuf, BUF_SIZE); size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0); SET_IDLE_STATE(0);
switch (pbuf[0]) { switch(pbuf[0]) {
/* Implementation of these is mandatory! */ /* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */ case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)]; uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, gp_regs); target_regs_read(cur_target, arm_regs);
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U); gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2);
break; break;
} }
case 'm': { /* 'm addr,len': Read len bytes from addr */ case 'm': { /* 'm addr,len': Read len bytes from addr */
uint32_t addr, len; uint32_t addr, len;
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
@ -133,26 +119,24 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("E02"); gdb_putpacketz("E02");
break; break;
} }
DEBUG_GDB("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
addr, len);
uint8_t mem[len]; uint8_t mem[len];
if (target_mem_read(cur_target, mem, addr, len)) if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else else
gdb_putpacket(hexify(pbuf, mem, len), len * 2U); gdb_putpacket(hexify(pbuf, mem, len), len*2);
break; break;
} }
case 'G': { /* 'G XX': Write general registers */ case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)]; uint8_t arm_regs[target_regs_size(cur_target)];
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs)); unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, gp_regs); target_regs_write(cur_target, arm_regs);
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */ case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
uint32_t addr = 0; uint32_t addr, len;
uint32_t len = 0;
int hex; int hex;
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex); sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
@ -160,8 +144,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("E02"); gdb_putpacketz("E02");
break; break;
} }
DEBUG_GDB("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
addr, len);
uint8_t mem[len]; uint8_t mem[len];
unhexify(mem, pbuf + hex, len); unhexify(mem, pbuf + hex, len);
if (target_mem_write(cur_target, addr, mem, len)) if (target_mem_write(cur_target, addr, mem, len))
@ -169,25 +152,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
else else
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
/* '[m|M|g|G|c][thread-id]' : Set the thread ID for the given subsequent operation
* (we don't actually care which as we only care about the TID for whether to send OK or an error)
*/
case 'H': {
char operation = 0;
uint32_t thread_id = 0;
sscanf(pbuf, "H%c%" SCNx32, &operation, &thread_id);
if (thread_id <= 1)
gdb_putpacketz("OK");
else
gdb_putpacketz("E01");
break;
}
case 's': /* 's [addr]': Single step [start at addr] */ case 's': /* 's [addr]': Single step [start at addr] */
single_step = true; single_step = true;
/* fall through */ /* fall through */
case 'c': /* 'c [addr]': Continue [at addr] */ case 'c': /* 'c [addr]': Continue [at addr] */
if (!cur_target) { if(!cur_target) {
gdb_putpacketz("X1D"); gdb_putpacketz("X1D");
break; break;
} }
@ -202,7 +172,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
target_addr watch; target_addr watch;
enum target_halt_reason reason; enum target_halt_reason reason;
if (!cur_target) { if(!cur_target) {
/* Report "target exited" if no target */ /* Report "target exited" if no target */
gdb_putpacketz("W00"); gdb_putpacketz("W00");
break; break;
@ -210,13 +180,10 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
/* Wait for target halt */ /* Wait for target halt */
while(!(reason = target_halt_poll(cur_target, &watch))) { while(!(reason = target_halt_poll(cur_target, &watch))) {
char c = (char)gdb_if_getchar_to(0); unsigned char c = gdb_if_getchar_to(0);
if(c == '\x03' || c == '\x04') { if((c == '\x03') || (c == '\x04')) {
target_halt_request(cur_target); target_halt_request(cur_target);
} }
#ifdef ENABLE_RTT
if (rtt_enabled) poll_rtt(cur_target);
#endif
} }
SET_RUN_STATE(0); SET_RUN_STATE(0);
@ -239,45 +206,17 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacket_f("T%02X", GDB_SIGTRAP); gdb_putpacket_f("T%02X", GDB_SIGTRAP);
} }
break; break;
} }
/* Optional GDB packet support */
case 'p': { /* Read single register */
ERROR_IF_NO_TARGET();
uint32_t reg;
sscanf(pbuf, "p%" SCNx32, &reg);
uint8_t val[8];
size_t s = target_reg_read(cur_target, reg, val, sizeof(val));
if (s > 0)
gdb_putpacket(hexify(pbuf, val, s), s * 2);
else
gdb_putpacketz("EFF");
break;
}
case 'P': { /* Write single register */
ERROR_IF_NO_TARGET();
uint32_t reg;
int n;
sscanf(pbuf, "P%" SCNx32 "=%n", &reg, &n);
// TODO: FIXME, VLAs considered harmful.
uint8_t val[strlen(&pbuf[n]) / 2];
unhexify(val, pbuf + n, sizeof(val));
if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0)
gdb_putpacketz("OK");
else
gdb_putpacketz("EFF");
break;
}
case 'F': /* Semihosting call finished */ case 'F': /* Semihosting call finished */
if (in_syscall) if (in_syscall) {
return hostio_reply(tc, pbuf, size); return hostio_reply(tc, pbuf, size);
else { } else {
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf); DEBUG("*** F packet when not in syscall! '%s'\n", pbuf);
gdb_putpacketz(""); gdb_putpacketz("");
} }
break; break;
/* Optional GDB packet support */
case '!': /* Enable Extended GDB Protocol. */ case '!': /* Enable Extended GDB Protocol. */
/* This doesn't do anything, we support the extended /* This doesn't do anything, we support the extended
* protocol anyway, but GDB will never send us a 'R' * protocol anyway, but GDB will never send us a 'R'
@ -288,17 +227,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
case 0x04: case 0x04:
case 'D': /* GDB 'detach' command. */ case 'D': /* GDB 'detach' command. */
if(cur_target) { if(cur_target)
SET_RUN_STATE(1);
target_detach(cur_target); target_detach(cur_target);
}
last_target = cur_target; last_target = cur_target;
cur_target = NULL; cur_target = NULL;
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
case 'k': /* Kill the target */ case 'k': /* Kill the target */
handle_kill_target(); if(cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
break; break;
case 'r': /* Reset the target system */ case 'r': /* Reset the target system */
@ -308,8 +250,6 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
else if(last_target) { else if(last_target) {
cur_target = target_attach(last_target, cur_target = target_attach(last_target,
&gdb_controller); &gdb_controller);
if(cur_target)
morse(NULL, false);
target_reset(cur_target); target_reset(cur_target);
} }
break; break;
@ -323,20 +263,19 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("E02"); gdb_putpacketz("E02");
break; break;
} }
DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len);
addr, len); if (target_mem_write(cur_target, addr, pbuf+bin, len))
if (target_mem_write(cur_target, addr, pbuf + bin, len))
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else else
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 'q': /* General query packet */ case 'q': /* General query packet */
handle_q_packet(pbuf, size); handle_q_packet(pbuf, size);
break; break;
case 'v': /* Verbose command packet */ case 'v': /* General query packet */
handle_v_packet(pbuf, size); handle_v_packet(pbuf, size);
break; break;
@ -348,341 +287,197 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
break; break;
default: /* Packet not implemented */ default: /* Packet not implemented */
DEBUG_GDB("*** Unsupported packet: %s\n", pbuf); DEBUG("*** Unsupported packet: %s\n", pbuf);
gdb_putpacketz(""); gdb_putpacketz("");
} }
} }
} }
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec) static void
handle_q_string_reply(const char *str, const char *param)
{ {
while (exec->cmd_prefix) { unsigned long addr, len;
const size_t prefix_length = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) {
exec->func(packet + prefix_length, length - prefix_length);
return true;
}
++exec;
}
return false;
}
static void exec_q_rcmd(const char *packet, const size_t length) if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
{
/* calculate size and allocate buffer for command */
const size_t datalen = length / 2U;
char *data = alloca(datalen + 1);
/* dehexify command */
unhexify(data, packet, datalen);
data[datalen] = 0; /* add terminating null */
const int c = command_process(cur_target, data);
if (c < 0)
gdb_putpacketz("");
else if (c == 0)
gdb_putpacketz("OK");
else
gdb_putpacket(hexify(pbuf, "Failed\n", strlen("Failed\n")),
2 * strlen("Failed\n"));
}
static void handle_q_string_reply(const char *reply, const char *param)
{
const size_t reply_length = strlen(reply);
uint32_t addr = 0;
uint32_t len = 0;
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
if (addr > reply_length) { if (addr < strlen (str)) {
gdb_putpacketz("E01"); char reply[len+2];
return; reply[0] = 'm';
} strncpy (reply + 1, &str[addr], len);
if (addr == reply_length) { if(len > strlen(&str[addr]))
len = strlen(&str[addr]);
gdb_putpacket(reply, len + 1);
} else if (addr == strlen (str)) {
gdb_putpacketz("l"); gdb_putpacketz("l");
return; } else
}
size_t output_len = reply_length - addr;
if (output_len > len)
output_len = len;
gdb_putpacket2("m", 1U, reply + addr, output_len);
}
static void exec_q_supported(const char *packet, const size_t length)
{
(void)packet;
(void)length;
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
}
static void exec_q_memory_map(const char *packet, const size_t length)
{
(void)packet;
(void)length;
/* Read target XML memory map */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target,
&gdb_controller);
}
if (!cur_target) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return;
}
char buf[1024];
target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/
handle_q_string_reply(buf, packet);
} }
static void exec_q_feature_read(const char *packet, const size_t length) static void
handle_q_packet(char *packet, int len)
{ {
(void)length; uint32_t addr, alen;
/* Read target description */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target, &gdb_controller);
}
if (!cur_target) {
gdb_putpacketz("E01");
return;
}
handle_q_string_reply(target_tdesc(cur_target), packet);
}
static void exec_q_crc(const char *packet, const size_t length) if(!strncmp(packet, "qRcmd,", 6)) {
{ char *data;
(void)length; int datalen;
uint32_t addr;
uint32_t addr_length; /* calculate size and allocate buffer for command */
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) { datalen = (len - 6) / 2;
data = alloca(datalen+1);
/* dehexify command */
unhexify(data, packet+6, datalen);
data[datalen] = 0; /* add terminating null */
int c = command_process(cur_target, data);
if(c < 0)
gdb_putpacketz("");
else if(c == 0)
gdb_putpacketz("OK");
else
gdb_putpacketz("E");
} else if (!strncmp (packet, "qSupported", 10)) {
/* Query supported protocol features */
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
} else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
/* Read target XML memory map */
if((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target,
&gdb_controller);
}
if (!cur_target) { if (!cur_target) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
uint32_t crc; char buf[1024];
if (generic_crc32(cur_target, &crc, addr, addr_length)) target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/
gdb_putpacketz("E03"); handle_q_string_reply(buf, packet + 23);
else
gdb_putpacket_f("C%lx", crc); } else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
/* Read target description */
if((!cur_target) && last_target) {
/* Attach to last target if detached. */
cur_target = target_attach(last_target,
&gdb_controller);
}
if (!cur_target) {
gdb_putpacketz("E01");
return;
}
handle_q_string_reply(target_tdesc(cur_target), packet + 31);
} else if (sscanf(packet, "qCRC:%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
if(!cur_target) {
gdb_putpacketz("E01");
return;
}
gdb_putpacket_f("C%lx", generic_crc32(cur_target, addr, alen));
} else {
DEBUG("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
} }
} }
/* static void
* qC queries are for the current thread. We don't support threads but GDB 11 and 12 require this, handle_v_packet(char *packet, int plen)
* so we always answer that the current thread is thread 1.
*/
static void exec_q_c(const char *packet, const size_t length)
{ {
(void)packet; unsigned long addr, len;
(void)length;
gdb_putpacketz("QC1");
}
/*
* qfThreadInfo queries are required in GDB 11 and 12 as these GDBs require the server to support
* threading even when there's only the possiblity for one thread to exist. In this instance,
* we have to tell GDB that there is a single active thread so it doesn't think the "thread" died.
* qsThreadInfo will always follow qfThreadInfo when we reply as we have to specify 'l' at the
* end to terminate the list.. GDB doesn't like this not happening.
*/
static void exec_q_thread_info(const char *packet, const size_t length)
{
(void)length;
if (packet[-11] == 'f')
gdb_putpacketz("m1");
else
gdb_putpacketz("l");
}
static const cmd_executer q_commands[]=
{
{"qRcmd,", exec_q_rcmd},
{"qSupported", exec_q_supported},
{"qXfer:memory-map:read::", exec_q_memory_map},
{"qXfer:features:read:target.xml:",exec_q_feature_read},
{"qCRC:", exec_q_crc},
{"qC", exec_q_c},
{"qfThreadInfo", exec_q_thread_info},
{"qsThreadInfo", exec_q_thread_info},
{NULL, NULL},
};
static void handle_kill_target(void)
{
if (cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
}
static void handle_q_packet(char *packet, const size_t length)
{
if (exec_command(packet, length, q_commands))
return;
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
static void handle_v_packet(char *packet, const size_t plen)
{
uint32_t addr = 0;
uint32_t len = 0;
int bin; int bin;
static uint8_t flash_mode = 0; static uint8_t flash_mode = 0;
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) { if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
/* Attach to remote target processor */ /* Attach to remote target processor */
cur_target = target_attach_n(addr, &gdb_controller); cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target) { if(cur_target)
morse(NULL, false); gdb_putpacketz("T05");
/* else
* We don't actually support threads, but GDB 11 and 12 can't work without
* us saying we attached to thread 1.. see the following for the low-down of this:
* https://sourceware.org/bugzilla/show_bug.cgi?id=28405
* https://sourceware.org/bugzilla/show_bug.cgi?id=28874
* https://sourceware.org/pipermail/gdb-patches/2021-December/184171.html
* https://sourceware.org/pipermail/gdb-patches/2022-April/188058.html
* https://sourceware.org/pipermail/gdb-patches/2022-July/190869.html
*/
gdb_putpacketz("T05thread:1;");
} else
gdb_putpacketz("E01"); gdb_putpacketz("E01");
} else if (!strncmp(packet, "vKill;", 6)) { } else if (!strcmp(packet, "vRun;")) {
/* Kill the target - we don't actually care about the PID that follows "vKill;" */
handle_kill_target();
gdb_putpacketz("OK");
} else if (!strncmp(packet, "vRun", 4)) {
/* Parse command line for get_cmdline semihosting call */
char cmdline[83];
char *pcmdline = cmdline;
char *tok = packet + 4;
if (*tok == ';')
++tok;
cmdline[0] = '\0';
while(*tok != '\0') {
if (strlen(cmdline) + 3 >= sizeof(cmdline))
break;
if (*tok == ';') {
*pcmdline++ = ' ';
pcmdline[0] = '\0';
tok++;
continue;
}
if (isxdigit(tok[0]) && isxdigit(tok[1])) {
unhexify(pcmdline, tok, 2);
if ((*pcmdline == ' ') || (*pcmdline == '\\')) {
pcmdline[1] = *pcmdline;
*pcmdline++ = '\\';
}
pcmdline++;
tok += 2;
pcmdline[0] = '\0';
continue;
}
break;
}
#ifdef ENABLE_RTT
/* force searching rtt control block */
rtt_found = false;
#endif
/* Run target program. For us (embedded) this means reset. */ /* Run target program. For us (embedded) this means reset. */
if (cur_target) { if(cur_target) {
target_set_cmdline(cur_target, cmdline);
target_reset(cur_target); target_reset(cur_target);
gdb_putpacketz("T05"); gdb_putpacketz("T05");
} else if (last_target) { } else if(last_target) {
cur_target = target_attach(last_target, cur_target = target_attach(last_target,
&gdb_controller); &gdb_controller);
/* If we were able to attach to the target again */ /* If we were able to attach to the target again */
if (cur_target) { if (cur_target) {
target_set_cmdline(cur_target, cmdline); target_reset(cur_target);
target_reset(cur_target); gdb_putpacketz("T05");
morse(NULL, false); } else gdb_putpacketz("E01");
gdb_putpacketz("T05");
} else
gdb_putpacketz("E01");
} else } else gdb_putpacketz("E01");
gdb_putpacketz("E01");
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) { } else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
/* Erase Flash Memory */ /* Erase Flash Memory */
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len); DEBUG("Flash Erase %08lX %08lX\n", addr, len);
if (!cur_target) { if(!cur_target) { gdb_putpacketz("EFF"); return; }
gdb_putpacketz("EFF");
return;
}
if (!flash_mode) { if(!flash_mode) {
/* Reset target if first flash command! */ /* Reset target if first flash command! */
/* This saves us if we're interrupted in IRQ context */ /* This saves us if we're interrupted in IRQ context */
target_reset(cur_target); target_reset(cur_target);
flash_mode = 1; flash_mode = 1;
} }
if (target_flash_erase(cur_target, addr, len) == 0) if(target_flash_erase(cur_target, addr, len) == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else { else
flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) { } else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
/* Write Flash Memory */ /* Write Flash Memory */
const uint32_t count = plen - bin; len = plen - bin;
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count); DEBUG("Flash Write %08lX %08lX\n", addr, len);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0) if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else { else
flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
} else if (!strcmp(packet, "vFlashDone")) { } else if (!strcmp(packet, "vFlashDone")) {
/* Commit flash operations. */ /* Commit flash operations. */
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK"); gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
flash_mode = 0; flash_mode = 0;
} else if (!strcmp(packet, "vStopped")) {
if (gdb_needs_detach_notify) {
gdb_putpacketz("W00");
gdb_needs_detach_notify = false;
} else
gdb_putpacketz("OK");
} else { } else {
DEBUG_GDB("*** Unsupported packet: %s\n", packet); DEBUG("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0); gdb_putpacket("", 0);
} }
} }
static void handle_z_packet(char *packet, const size_t plen) static void
handle_z_packet(char *packet, int plen)
{ {
(void)plen; (void)plen;
uint32_t type; uint8_t set = (packet[0] == 'Z') ? 1 : 0;
uint32_t len; int type, len;
uint32_t addr; uint32_t addr;
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len); int ret;
int ret = 0; /* I have no idea why this doesn't work. Seems to work
if (packet[0] == 'Z') * with real sscanf() though... */
//sscanf(packet, "%*[zZ]%hhd,%08lX,%hhd", &type, &addr, &len);
type = packet[1] - '0';
sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len);
if(set)
ret = target_breakwatch_set(cur_target, type, addr, len); ret = target_breakwatch_set(cur_target, type, addr, len);
else else
ret = target_breakwatch_clear(cur_target, type, addr, len); ret = target_breakwatch_clear(cur_target, type, addr, len);
if (ret < 0) if (ret < 0) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else if (ret > 0) } else if (ret > 0) {
gdb_putpacketz(""); gdb_putpacketz("");
else } else {
gdb_putpacketz("OK"); gdb_putpacketz("OK");
}
} }
void gdb_main(void) void gdb_main(void)

View File

@ -26,200 +26,107 @@
#include "gdb_if.h" #include "gdb_if.h"
#include "gdb_packet.h" #include "gdb_packet.h"
#include "hex_utils.h" #include "hex_utils.h"
#include "remote.h"
#include <stdarg.h> #include <stdarg.h>
size_t gdb_getpacket(char *packet, size_t size) int gdb_getpacket(char *packet, int size)
{ {
unsigned char c;
unsigned char csum; unsigned char csum;
char recv_csum[3]; char recv_csum[3];
size_t offset = 0; int i;
while (1) { while(1) {
/* Wait for packet start */ /* Wait for packet start */
do { while((packet[0] = gdb_if_getchar()) != '$')
/* Spin waiting for a start of packet character - either a gdb if(packet[0] == 0x04) return 1;
* start ('$') or a BMP remote packet start ('!').
*/
do {
/* Smells like bad code */
packet[0] = (char)gdb_if_getchar();
if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
#if PC_HOSTED == 0
if (packet[0] == REMOTE_SOM) {
/* This is probably a remote control packet
* - get and handle it */
offset = 0;
bool gettingRemotePacket = true;
while (gettingRemotePacket) {
/* Smells like bad code */
const char c = (char)gdb_if_getchar();
switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */
offset = 0;
break;
case REMOTE_EOM: /* Complete packet for processing */ i = 0; csum = 0;
packet[offset] = 0;
remotePacketProcess(offset, packet);
gettingRemotePacket = false;
break;
case '$': /* A 'real' gdb packet, best stop squatting now */
packet[0] = '$';
gettingRemotePacket = false;
break;
default:
if (offset < size) {
packet[offset++] = c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket = false;
}
break;
}
}
/* Reset the packet buffer start character to zero, because function
* 'remotePacketProcess()' above overwrites this buffer, and
* an arbitrary character may have been placed there. If this is a '$'
* character, this will cause this loop to be terminated, which is wrong.
*/
packet[0] = 0;
}
#endif
} while (packet[0] != '$');
offset = 0;
csum = 0;
char c;
/* Capture packet data into buffer */ /* Capture packet data into buffer */
while ((c = (char)gdb_if_getchar()) != '#') { while((c = gdb_if_getchar()) != '#') {
/* If we run out of buffer space, exit early */ if(i == size) break; /* Oh shit */
if (offset == size)
break;
if (c == '$') { /* Restart capture */ if(c == '$') { /* Restart capture */
offset = 0; i = 0;
csum = 0; csum = 0;
continue; continue;
} }
if (c == '}') { /* escaped char */ if(c == '}') { /* escaped char */
c = gdb_if_getchar(); c = gdb_if_getchar();
csum += c + '}'; csum += c + '}';
packet[offset++] = c ^ 0x20; packet[i++] = c ^ 0x20;
continue; continue;
} }
csum += c; csum += c;
packet[offset++] = c; packet[i++] = c;
} }
recv_csum[0] = (char)gdb_if_getchar(); recv_csum[0] = gdb_if_getchar();
recv_csum[1] = (char)gdb_if_getchar(); recv_csum[1] = gdb_if_getchar();
recv_csum[2] = 0; recv_csum[2] = 0;
/* return packet if checksum matches */ /* return packet if checksum matches */
if (csum == strtol(recv_csum, NULL, 16)) if(csum == strtol(recv_csum, NULL, 16)) break;
break;
/* get here if checksum fails */ /* get here if checksum fails */
gdb_if_putchar('-', 1); /* send nack */ gdb_if_putchar('-', 1); /* send nack */
} }
gdb_if_putchar('+', 1); /* send ack */ gdb_if_putchar('+', 1); /* send ack */
packet[offset] = 0; packet[i] = 0;
#if PC_HOSTED == 1 #ifdef DEBUG_GDBPACKET
DEBUG_GDB_WIRE("%s : ", __func__); DEBUG("%s : ", __func__);
for (size_t j = 0; j < offset; j++) { for(int j = 0; j < i; j++) {
const char c = packet[j]; c = packet[j];
if (c >= ' ' && c < 0x7F) if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c); DEBUG("%c", c);
else else
DEBUG_GDB_WIRE("\\x%02X", c); DEBUG("\\x%02X", c);
} }
DEBUG_GDB_WIRE("\n"); DEBUG("\n");
#endif #endif
return offset; return i;
} }
static void gdb_next_char(char c, unsigned char *csum) void gdb_putpacket(const char *packet, int size)
{
#if PC_HOSTED == 1
if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c);
else
DEBUG_GDB_WIRE("\\x%02X", c);
#endif
if ((c == '$') || (c == '#') || (c == '}') || (c == '*')) {
gdb_if_putchar('}', 0);
gdb_if_putchar(c ^ 0x20, 0);
*csum += '}' + (c ^ 0x20);
}
else {
gdb_if_putchar(c, 0);
*csum += c;
}
}
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
{ {
int i;
unsigned char csum;
unsigned char c;
char xmit_csum[3]; char xmit_csum[3];
size_t tries = 0; int tries = 0;
do { do {
DEBUG_GDB_WIRE("%s: ", __func__); #ifdef DEBUG_GDBPACKET
unsigned char csum = 0; DEBUG("%s : ", __func__);
#endif
csum = 0;
gdb_if_putchar('$', 0); gdb_if_putchar('$', 0);
for(i = 0; i < size; i++) {
for (size_t i = 0; i < size1; ++i) c = packet[i];
gdb_next_char(packet1[i], &csum); #ifdef DEBUG_GDBPACKET
for (size_t i = 0; i < size2; ++i) if ((c >= 32) && (c < 127))
gdb_next_char(packet2[i], &csum); DEBUG("%c", c);
else
DEBUG("\\x%02X", c);
#endif
if((c == '$') || (c == '#') || (c == '}')) {
gdb_if_putchar('}', 0);
gdb_if_putchar(c ^ 0x20, 0);
csum += '}' + (c ^ 0x20);
} else {
gdb_if_putchar(c, 0);
csum += c;
}
}
gdb_if_putchar('#', 0); gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); sprintf(xmit_csum, "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1); gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n"); #ifdef DEBUG_GDBPACKET
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3); DEBUG("\n");
} #endif
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
void gdb_putpacket(const char *packet, size_t size)
{
char xmit_csum[3];
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_put_notification(const char *const packet, const size_t size)
{
char xmit_csum[3];
DEBUG_GDB_WIRE("%s: ", __func__);
uint8_t csum = 0;
gdb_if_putchar('%', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} }
void gdb_putpacket_f(const char *fmt, ...) void gdb_putpacket_f(const char *fmt, ...)
@ -237,13 +144,13 @@ void gdb_putpacket_f(const char *fmt, ...)
void gdb_out(const char *buf) void gdb_out(const char *buf)
{ {
int l = strlen(buf); char *hexdata;
char *hexdata = calloc(1, 2 * l + 1); int i;
if (!hexdata)
return; hexdata = alloca((i = strlen(buf)*2 + 1) + 1);
hexify(hexdata, buf, l); hexdata[0] = 'O';
gdb_putpacket2("O", 1, hexdata, 2 * l); hexify(hexdata+1, buf, strlen(buf));
free(hexdata); gdb_putpacket(hexdata, i);
} }
void gdb_voutf(const char *fmt, va_list ap) void gdb_voutf(const char *fmt, va_list ap)

View File

@ -26,16 +26,16 @@
static const char hexdigits[] = "0123456789abcdef"; static const char hexdigits[] = "0123456789abcdef";
char *hexify(char *hex, const void *buf, const size_t size) char * hexify(char *hex, const void *buf, size_t size)
{ {
char *dst = hex; char *tmp = hex;
const uint8_t *const src = buf; const uint8_t *b = buf;
for (size_t idx = 0; idx < size; ++idx) { while (size--) {
*dst++ = hexdigits[src[idx] >> 4]; *tmp++ = hexdigits[*b >> 4];
*dst++ = hexdigits[src[idx] & 0xF]; *tmp++ = hexdigits[*b++ & 0xF];
} }
*dst++ = 0; *tmp++ = 0;
return hex; return hex;
} }
@ -43,18 +43,20 @@ char *hexify(char *hex, const void *buf, const size_t size)
static uint8_t unhex_digit(char hex) static uint8_t unhex_digit(char hex)
{ {
uint8_t tmp = hex - '0'; uint8_t tmp = hex - '0';
if (tmp > 9) if(tmp > 9)
tmp -= 'A' - '0' - 10; tmp -= 'A' - '0' - 10;
if (tmp > 16) if(tmp > 16)
tmp -= 'a' - 'A'; tmp -= 'a' - 'A';
return tmp; return tmp;
} }
char *unhexify(void *buf, const char *hex, const size_t size) char * unhexify(void *buf, const char *hex, size_t size)
{ {
uint8_t *const dst = buf; uint8_t *b = buf;
for (size_t idx = 0; idx < size; ++idx, hex += 2) { while (size--) {
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]); *b = unhex_digit(*hex++) << 4;
*b++ |= unhex_digit(*hex++);
} }
return buf; return buf;
} }

View File

@ -21,19 +21,9 @@
#ifndef __COMMAND_H #ifndef __COMMAND_H
#define __COMMAND_H #define __COMMAND_H
#include <stdbool.h>
#include "target.h" #include "target.h"
int command_process(target *t, char *cmd); int command_process(target *t, char *cmd);
/*
* Attempts to parse a string as either being "enable" or "disable".
* If the parse is successful, returns true and sets the out param to
* indicate what was parsed. If not successful, emits a warning to the
* gdb port, returns false and leaves out untouched.
*/
bool parse_enable_or_disable(const char *s, bool *out);
#endif #endif

View File

@ -21,6 +21,6 @@
#ifndef __CRC32_H #ifndef __CRC32_H
#define __CRC32_H #define __CRC32_H
int generic_crc32(target *t, uint32_t *crc, uint32_t base, int len); uint32_t generic_crc32(target *t, uint32_t base, int len);
#endif #endif

View File

@ -21,7 +21,7 @@
#ifndef __GDB_IF_H #ifndef __GDB_IF_H
#define __GDB_IF_H #define __GDB_IF_H
#if PC_HOSTED == 0 #if !defined(LIBFTDI)
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep); void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
#endif #endif
@ -29,8 +29,6 @@ void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
int gdb_if_init(void); int gdb_if_init(void);
unsigned char gdb_if_getchar(void); unsigned char gdb_if_getchar(void);
unsigned char gdb_if_getchar_to(int timeout); unsigned char gdb_if_getchar_to(int timeout);
/* sending gdb_if_putchar(0, true) seems to work as keep alive */
void gdb_if_putchar(unsigned char c, int flush); void gdb_if_putchar(unsigned char c, int flush);
#endif #endif

View File

@ -21,19 +21,17 @@
#ifndef __GDB_PACKET_H #ifndef __GDB_PACKET_H
#define __GDB_PACKET_H #define __GDB_PACKET_H
#include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
size_t gdb_getpacket(char *packet, size_t size); int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, size_t size); void gdb_putpacket(const char *packet, int size);
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2);
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet)) #define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
void gdb_putpacket_f(const char *packet, ...); void gdb_putpacket_f(const char *packet, ...);
void gdb_put_notification(const char *packet, size_t size);
#define gdb_put_notificationz(packet) gdb_put_notification((packet), strlen(packet))
void gdb_out(const char *buf); void gdb_out(const char *buf);
void gdb_voutf(const char *fmt, va_list); void gdb_voutf(const char *fmt, va_list);
void gdb_outf(const char *fmt, ...); void gdb_outf(const char *fmt, ...);
#endif #endif

View File

@ -21,12 +21,7 @@
#ifndef __GENERAL_H #ifndef __GENERAL_H
#define __GENERAL_H #define __GENERAL_H
#if !defined(_GNU_SOURCE) #define _GNU_SOURCE
# define _GNU_SOURCE
#endif
#if !defined(__USE_MINGW_ANSI_STDIO)
# define __USE_MINGW_ANSI_STDIO 1
#endif
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
@ -34,128 +29,13 @@
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/types.h>
#include "platform.h" #include "platform.h"
#include "platform_support.h" #include "platform_support.h"
extern uint32_t delay_cnt; #ifndef DEBUG
#include <stdio.h>
enum BMP_DEBUG { #define DEBUG printf
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,
};
#define FREQ_FIXED 0xffffffff
#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(PLATFORM_PRINTF)
# define PLATFORM_PRINTF printf
# endif
# if defined(ENABLE_DEBUG)
# define DEBUG_WARN PLATFORM_PRINTF
# define DEBUG_INFO PLATFORM_PRINTF
# else
# define DEBUG_WARN(...) do {} while(0)
# define DEBUG_INFO(...) do {} while(0)
# endif
# define DEBUG_GDB(...) do {} while(0)
# define DEBUG_TARGET(...) do {} while(0)
# define DEBUG_PROBE(...) do {} while(0)
# define DEBUG_WIRE(...) do {} while(0)
# define DEBUG_GDB_WIRE(...) do {} while(0)
#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 #endif
#define ALIGN(x, n) (((x) + (n) - 1) & ~((n) - 1)) #define ALIGN(x, n) (((x) + (n) - 1) & ~((n) - 1))
@ -164,11 +44,5 @@ static inline void DEBUG_WIRE(const char *format, ...)
#undef MAX #undef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y))
#if !defined(SYSTICKHZ)
# define SYSTICKHZ 100
#endif
#define SYSTICKMS (1000 / SYSTICKHZ)
#define MORSECNT ((SYSTICKHZ / 10) - 1)
#endif #endif

View File

@ -21,12 +21,13 @@
#ifndef __JTAGTAP_H #ifndef __JTAGTAP_H
#define __JTAGTAP_H #define __JTAGTAP_H
typedef struct jtag_proc_s {
/* Note: Signal names are as for the device under test. */ /* Note: Signal names are as for the device under test. */
void (*jtagtap_reset)(void); int jtagtap_init(void);
uint8_t (*jtagtap_next)(const uint8_t TMS, const uint8_t TDI); void jtagtap_reset(void);
uint8_t jtagtap_next(const uint8_t TMS, const uint8_t TDI);
/* tap_next executes one state transision in the JTAG TAP state machine: /* tap_next executes one state transision in the JTAG TAP state machine:
* - Ensure TCK is low * - Ensure TCK is low
* - Assert the values of TMS and TDI * - Assert the values of TMS and TDI
@ -35,39 +36,30 @@ typedef struct jtag_proc_s {
* - Release TCK. * - Release TCK.
*/ */
void (*jtagtap_tms_seq)(uint32_t MS, int ticks); void jtagtap_tms_seq(uint32_t MS, int ticks);
void (*jtagtap_tdi_tdo_seq) void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
(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);
/* Shift out a sequence on MS and DI, capture data to DO. /* 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. * - This is not endian safe: First byte will always be first shifted out.
* - DO may be NULL to ignore captured data. * - DO may be NULL to ignore captured data.
* - DO may be point to the same address as DI. * - 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 */ /* generic soft reset: 1, 1, 1, 1, 1, 0 */
#define jtagtap_soft_reset() \ #define jtagtap_soft_reset() \
jtag_proc.jtagtap_tms_seq(0x1F, 6) jtagtap_tms_seq(0x1F, 6)
/* Goto Shift-IR: 1, 1, 0, 0 */ /* Goto Shift-IR: 1, 1, 0, 0 */
#define jtagtap_shift_ir() \ #define jtagtap_shift_ir() \
jtag_proc.jtagtap_tms_seq(0x03, 4) jtagtap_tms_seq(0x03, 4)
/* Goto Shift-DR: 1, 0, 0 */ /* Goto Shift-DR: 1, 0, 0 */
#define jtagtap_shift_dr() \ #define jtagtap_shift_dr() \
jtag_proc.jtagtap_tms_seq(0x01, 3) jtagtap_tms_seq(0x01, 3)
/* Goto Run-test/Idle: 1, 1, 0 */ /* Goto Run-test/Idle: 1, 1, 0 */
#define jtagtap_return_idle() \ #define jtagtap_return_idle() \
jtag_proc.jtagtap_tms_seq(0x01, 2) jtagtap_tms_seq(0x01, 2)
# if PC_HOSTED == 1
int platform_jtagtap_init(void);
# else
int jtagtap_init(void);
# endif
#endif #endif

View File

@ -24,9 +24,7 @@
# error "Include 'general.h' instead" # error "Include 'general.h' instead"
#endif #endif
#include "target.h" #if defined(LIBFTDI)
#if PC_HOSTED == 1
void platform_init(int argc, char **argv); void platform_init(int argc, char **argv);
#else #else
void platform_init(void); void platform_init(void);
@ -37,9 +35,6 @@ void platform_timeout_set(platform_timeout *t, uint32_t ms);
bool platform_timeout_is_expired(platform_timeout *t); bool platform_timeout_is_expired(platform_timeout *t);
void platform_delay(uint32_t ms); void platform_delay(uint32_t ms);
#define POWER_CONFLICT_THRESHOLD 5 /* in 0.1V, so 5 stands for 0.5V */
extern bool connect_assert_srst;
uint32_t platform_target_voltage_sense(void);
const char *platform_target_voltage(void); const char *platform_target_voltage(void);
int platform_hwversion(void); int platform_hwversion(void);
void platform_srst_set_val(bool assert); void platform_srst_set_val(bool assert);
@ -47,8 +42,6 @@ bool platform_srst_get_val(void);
bool platform_target_get_power(void); bool platform_target_get_power(void);
void platform_target_set_power(bool power); void platform_target_set_power(bool power);
void platform_request_boot(void); void platform_request_boot(void);
void platform_max_frequency_set(uint32_t frequency);
uint32_t platform_max_frequency_get(void);
#endif #endif

View File

@ -1,85 +0,0 @@
/*
* Copyright 2018 Robert C. Curtis. 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.
*
* THIS SOFTWARE IS PROVIDED BY ROBERT C. CURTIS ``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 ROBERT C. CURTIS 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of Robert C. Curtis.
*/
/** @file util/queue.h
* Static queue primitives.
*
* This file contains a set of static queue primitives that are common among
* all of the low level queue implementations. The primitives are inline
* functions, and will be optimal if size is a constant power of 2.
*/
#ifndef I__QUEUE_H__
#define I__QUEUE_H__
/** Increment a queue index.
* @param[in] idx Queue index
* @param[in] size Queue size
* @returns The new queue index value
*/
static inline size_t qinc(size_t idx, size_t size)
{
return ((idx + 1) % size);
}
/** Decrement a queue index.
* @param[in] idx Queue index
* @param[in] size Queue size
* @returns The new queue index value
*/
static inline size_t qdec(size_t idx, size_t size)
{
return ((idx - 1) % size);
}
/** Tests if a queue is full.
* @param[in] head Head index
* @param[in] tail Tail index
* @param[in] size Queue size
*/
static inline int qfull(size_t head, size_t tail, size_t size)
{
size_t next_head = qinc(head, size);
return (next_head == tail);
}
/** Tests if a queue is empty.
* @param[in] head Head index
* @param[in] tail Tail index
*/
static inline int qempty(size_t head, size_t tail)
{
return (head == tail);
}
#endif /* I__QUEUE_H__ */

View File

@ -1,34 +0,0 @@
#ifndef RTT_H
#define RTT_H
#include <target.h>
#define MAX_RTT_CHAN 16
extern char rtt_ident[16]; // string
extern bool rtt_enabled; // rtt on/off
extern bool rtt_found; // control block found
extern uint32_t rtt_cbaddr; // control block address
extern uint32_t rtt_min_poll_ms; // min time between polls (ms)
extern uint32_t rtt_max_poll_ms; // max time between polls (ms)
extern uint32_t rtt_max_poll_errs; // max number of errors before disconnect
extern bool rtt_auto_channel; // manual or auto channel selection
extern bool rtt_flag_skip; // skip if host-to-target fifo full
extern bool rtt_flag_block; // block if host-to-target fifo full
struct rtt_channel_struct {
bool is_enabled; // does user want to see this channel?
bool is_configured; // is channel configured in control block?
bool is_output;
uint32_t buf_addr;
uint32_t buf_size;
uint32_t head_addr;
uint32_t tail_addr;
uint32_t flag;
};
extern struct rtt_channel_struct rtt_channel[MAX_RTT_CHAN];
// true if target memory access does not work when target running
extern bool target_no_background_memory_access(target *cur_target);
extern void poll_rtt(target *cur_target);
#endif

View File

@ -1,36 +0,0 @@
#ifndef RTT_IF_H
#define RTT_IF_H
/* rtt i/o to terminal */
/* default buffer sizes, 8 bytes added to up buffer for alignment and padding */
/* override RTT_UP_BUF_SIZE and RTT_DOWN_BUF_SIZE in platform.h if needed */
#if !defined(RTT_UP_BUF_SIZE) || !defined(RTT_DOWN_BUF_SIZE)
#if (PC_HOSTED == 1)
#define RTT_UP_BUF_SIZE (4096 + 8)
#define RTT_DOWN_BUF_SIZE (512)
#elif defined(STM32F7)
#define RTT_UP_BUF_SIZE (4096 + 8)
#define RTT_DOWN_BUF_SIZE (2048)
#elif defined(STM32F4)
#define RTT_UP_BUF_SIZE (2048 + 8)
#define RTT_DOWN_BUF_SIZE (256)
#else /* stm32f103 */
#define RTT_UP_BUF_SIZE (1024 + 8)
#define RTT_DOWN_BUF_SIZE (256)
#endif
#endif
/* hosted initialisation */
extern int rtt_if_init(void);
/* hosted teardown */
extern int rtt_if_exit(void);
/* target to host: write len bytes from the buffer starting at buf. return number bytes written */
extern uint32_t rtt_write(const char *buf, uint32_t len);
/* host to target: read one character, non-blocking. return character, -1 if no character */
extern int32_t rtt_getchar();
/* host to target: true if no characters available for reading */
extern bool rtt_nodata();
#endif

View File

@ -18,11 +18,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
typedef const struct jtag_dev_descr_s { #ifndef __SWDPTAP_H
const uint32_t idcode; #define __SWDPTAP_H
const uint32_t idmask;
const char * const descr; int swdptap_init(void);
void (*const handler)(uint8_t jd_index);
} jtag_dev_descr_t; /* Primitive functions */
extern jtag_dev_descr_t dev_descr[]; bool swdptap_bit_in(void);
void swdptap_bit_out(bool val);
/* High level functions, provided as weak in swdptap_generic.c */
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

View File

@ -26,22 +26,15 @@
#define __TARGET_H #define __TARGET_H
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
typedef struct target_s target; typedef struct target_s target;
typedef uint32_t target_addr; typedef uint32_t target_addr;
struct target_controller; struct target_controller;
#if PC_HOSTED == 1 int adiv5_swdp_scan(void);
int platform_adiv5_swdp_scan(uint32_t targetid);
int platform_jtag_scan(const uint8_t *lrlens);
#endif
int adiv5_swdp_scan(uint32_t targetid);
int jtag_scan(const uint8_t *lrlens); int jtag_scan(const uint8_t *lrlens);
int target_foreach(void (*cb)(int i, target *t, void *context), void *context); bool 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 */
@ -50,9 +43,6 @@ target *target_attach_n(int n, struct target_controller *);
void target_detach(target *t); void target_detach(target *t);
bool target_attached(target *t); bool target_attached(target *t);
const char *target_driver_name(target *t); const char *target_driver_name(target *t);
const char *target_core_name(target *t);
unsigned int target_designer(target *t);
unsigned int target_idcode(target *t);
/* Memory access functions */ /* Memory access functions */
bool target_mem_map(target *t, char *buf, size_t len); bool target_mem_map(target *t, char *buf, size_t len);
@ -68,8 +58,6 @@ size_t target_regs_size(target *t);
const char *target_tdesc(target *t); const char *target_tdesc(target *t);
void target_regs_read(target *t, void *data); void target_regs_read(target *t, void *data);
void target_regs_write(target *t, const void *data); void target_regs_write(target *t, const void *data);
ssize_t target_reg_read(target *t, int reg, void *data, size_t max);
ssize_t target_reg_write(target *t, int reg, const void *data, size_t size);
/* Halt/resume functions */ /* Halt/resume functions */
enum target_halt_reason { enum target_halt_reason {
@ -86,9 +74,6 @@ void target_reset(target *t);
void target_halt_request(target *t); void target_halt_request(target *t);
enum target_halt_reason target_halt_poll(target *t, target_addr *watch); enum target_halt_reason target_halt_poll(target *t, target_addr *watch);
void target_halt_resume(target *t, bool step); void target_halt_resume(target *t, bool step);
void target_set_cmdline(target *t, char *cmdline);
void target_set_heapinfo(target *t, target_addr heap_base, target_addr heap_limit,
target_addr stack_base, target_addr stack_limit);
/* Break-/watchpoint functions */ /* Break-/watchpoint functions */
enum target_breakwatch { enum target_breakwatch {
@ -105,12 +90,11 @@ int target_breakwatch_clear(target *t, enum target_breakwatch, target_addr, size
void target_command_help(target *t); void target_command_help(target *t);
int target_command(target *t, int argc, const char *argv[]); int target_command(target *t, int argc, const char *argv[]);
/* keep target_errno in sync with errno values in gdb/include/gdb/fileio.h */
enum target_errno { enum target_errno {
TARGET_EPERM = 1, TARGET_EPERM = 1,
TARGET_ENOENT = 2, TARGET_ENOENT = 2,
TARGET_EINTR = 4, TARGET_EINTR = 4,
TARGET_EIO = 5,
TARGET_EBADF = 9, TARGET_EBADF = 9,
TARGET_EACCES = 13, TARGET_EACCES = 13,
TARGET_EFAULT = 14, TARGET_EFAULT = 14,
@ -120,15 +104,13 @@ enum target_errno {
TARGET_ENOTDIR = 20, TARGET_ENOTDIR = 20,
TARGET_EISDIR = 21, TARGET_EISDIR = 21,
TARGET_EINVAL = 22, TARGET_EINVAL = 22,
TARGET_ENFILE = 23,
TARGET_EMFILE = 24, TARGET_EMFILE = 24,
TARGET_ENFILE = 23,
TARGET_EFBIG = 27, TARGET_EFBIG = 27,
TARGET_ENOSPC = 28, TARGET_ENOSPC = 28,
TARGET_ESPIPE = 29, TARGET_ESPIPE = 29,
TARGET_EROFS = 30, TARGET_EROFS = 30,
TARGET_ENOSYS = 88, TARGET_ENAMETOOLONG = 36,
TARGET_ENAMETOOLONG = 91,
TARGET_EUNKNOWN = 9999,
}; };
enum target_open_flags { enum target_open_flags {

View File

@ -33,7 +33,7 @@
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
#if PC_HOSTED == 1 #if defined(LIBFTDI)
platform_init(argc, argv); platform_init(argc, argv);
#else #else
(void) argc; (void) argc;

View File

@ -59,14 +59,8 @@ static char morse_repeat;
void morse(const char *msg, char repeat) void morse(const char *msg, char repeat)
{ {
#if PC_HOSTED == 1
if (msg)
DEBUG_WARN("%s\n", msg);
(void) repeat;
#else
morse_msg = morse_ptr = msg; morse_msg = morse_ptr = msg;
morse_repeat = repeat; morse_repeat = repeat;
#endif
} }
bool morse_update(void) bool morse_update(void)

View File

@ -1,23 +0,0 @@
# Platforms and platform support files
This directory contains the implementation of platforms and support file
used by (multiple) platforms.
## Implementation directories
native : Firmware for original Black Magic Probe<br>
stlink : Firmware for STLINK-V2 and V21<br>
swlink : Firmware for STLINK-V1 and Bluepill<br>
hydrabus : Firmware https://hydrabus.com/ <br>
f4discovery : Firmware for STM32F407DISCO<br>
launchpad-icdi :<br>
tm4c: <br>
hosted: PC-hosted BMP running as PC application talking to firmware BMPs,
STLINK-V2/21/3, FTDI MPSSE probes, CMSIS-DAP and JLINK
## Support directories
common: libopencm3 based support for firmware BMPs<br>
stm32: STM32 specific libopencm3 based support for firmware BMPs<br>
pc: Support for PC-hosted BMPs.<br>

View File

@ -24,18 +24,6 @@
* field firmware upgrade. * field firmware upgrade.
* *
* The device's unique id is used as the USB serial number string. * The device's unique id is used as the USB serial number string.
*
* Endpoint Usage
*
* 0 Control Endpoint
* IN 1 GDB CDC DATA
* OUT 1 GDB CDC DATA
* IN 2 GDB CDC CTR
* IN 3 UART CDC DATA
* OUT 3 UART CDC DATA
* OUT 4 UART CDC CTRL
* In 5 Trace Capture
*
*/ */
#include "general.h" #include "general.h"
@ -46,23 +34,15 @@
#endif #endif
#include "usbuart.h" #include "usbuart.h"
#include "serialno.h" #include "serialno.h"
#include "version.h"
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h> #include <libopencm3/usb/cdc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/dfu.h> #include <libopencm3/usb/dfu.h>
#include <stdlib.h>
#define GDB_IF_NO 0 #define DFU_IF_NO 4
#define UART_IF_NO 2
#define DFU_IF_NO 4
#if defined(PLATFORM_HAS_TRACESWO)
# define TRACE_IF_NO 5
# define TOTAL_INTERFACES 6
#else
# define TOTAL_INTERFACES 5
#endif
usbd_device * usbdev; usbd_device * usbdev;
@ -71,18 +51,14 @@ static int cdcacm_gdb_dtr = 1;
static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd); static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd);
static const struct usb_device_descriptor dev_desc = { static const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE, .bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
.bDeviceClass = 0xEF, /* Miscellaneous Device */ .bDeviceClass = 0xEF, /* Miscellaneous Device */
.bDeviceSubClass = 2, /* Common Class */ .bDeviceSubClass = 2, /* Common Class */
.bDeviceProtocol = 1, /* Interface Association */ .bDeviceProtocol = 1, /* Interface Association */
#if defined(SAMD21E17) || defined(LM4F) .bMaxPacketSize0 = 64,
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
#else
.bMaxPacketSize0 = 32,
#endif
.idVendor = 0x1D50, .idVendor = 0x1D50,
.idProduct = 0x6018, .idProduct = 0x6018,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
@ -98,7 +74,7 @@ static const struct usb_device_descriptor dev_desc = {
static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{ static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN, .bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16, .wMaxPacketSize = 16,
.bInterval = 255, .bInterval = 255,
@ -107,14 +83,14 @@ static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
static const struct usb_endpoint_descriptor gdb_data_endp[] = {{ static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_GDB_ENDPOINT, .bEndpointAddress = 0x01,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
}, { }, {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
@ -138,7 +114,7 @@ static const struct {
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
.bmCapabilities = 0, .bmCapabilities = 0,
.bDataInterface = GDB_IF_NO + 1, .bDataInterface = 1,
}, },
.acm = { .acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
@ -150,8 +126,8 @@ static const struct {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor), .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_UNION, .bDescriptorSubtype = USB_CDC_TYPE_UNION,
.bControlInterface = GDB_IF_NO, .bControlInterface = 0,
.bSubordinateInterface0 = GDB_IF_NO + 1, .bSubordinateInterface0 = 1,
} }
}; };
@ -163,7 +139,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_NONE, .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 4, .iInterface = 4,
.endpoint = gdb_comm_endp, .endpoint = gdb_comm_endp,
@ -175,7 +151,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
static const struct usb_interface_descriptor gdb_data_iface[] = {{ static const struct usb_interface_descriptor gdb_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = GDB_IF_NO + 1, .bInterfaceNumber = 1,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA, .bInterfaceClass = USB_CLASS_DATA,
@ -189,19 +165,19 @@ static const struct usb_interface_descriptor gdb_data_iface[] = {{
static const struct usb_iface_assoc_descriptor gdb_assoc = { static const struct usb_iface_assoc_descriptor gdb_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = GDB_IF_NO, .bFirstInterface = 0,
.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_NONE, .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
.iFunction = 4, .iFunction = 0,
}; };
/* Serial ACM interface */ /* Serial ACM interface */
static const struct usb_endpoint_descriptor uart_comm_endp[] = {{ static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN, .bEndpointAddress = 0x84,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16, .wMaxPacketSize = 16,
.bInterval = 255, .bInterval = 255,
@ -210,14 +186,14 @@ static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
static const struct usb_endpoint_descriptor uart_data_endp[] = {{ static const struct usb_endpoint_descriptor uart_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_UART_ENDPOINT, .bEndpointAddress = 0x03,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE / 2, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
}, { }, {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x83,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
@ -241,7 +217,7 @@ static const struct {
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
.bmCapabilities = 0, .bmCapabilities = 0,
.bDataInterface = UART_IF_NO + 1, .bDataInterface = 3,
}, },
.acm = { .acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
@ -253,20 +229,20 @@ static const struct {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor), .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_UNION, .bDescriptorSubtype = USB_CDC_TYPE_UNION,
.bControlInterface = UART_IF_NO, .bControlInterface = 2,
.bSubordinateInterface0 = UART_IF_NO + 1, .bSubordinateInterface0 = 3,
} }
}; };
static const struct usb_interface_descriptor uart_comm_iface[] = {{ static const struct usb_interface_descriptor uart_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UART_IF_NO, .bInterfaceNumber = 2,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.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_NONE, .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 5, .iInterface = 5,
.endpoint = uart_comm_endp, .endpoint = uart_comm_endp,
@ -278,7 +254,7 @@ static const struct usb_interface_descriptor uart_comm_iface[] = {{
static const struct usb_interface_descriptor uart_data_iface[] = {{ static const struct usb_interface_descriptor uart_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UART_IF_NO + 1, .bInterfaceNumber = 3,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA, .bInterfaceClass = USB_CLASS_DATA,
@ -292,12 +268,12 @@ static const struct usb_interface_descriptor uart_data_iface[] = {{
static const struct usb_iface_assoc_descriptor uart_assoc = { static const struct usb_iface_assoc_descriptor uart_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = UART_IF_NO, .bFirstInterface = 2,
.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_NONE, .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
.iFunction = 5, .iFunction = 0,
}; };
const struct usb_dfu_descriptor dfu_function = { const struct usb_dfu_descriptor dfu_function = {
@ -327,7 +303,7 @@ const struct usb_interface_descriptor dfu_iface = {
static const struct usb_iface_assoc_descriptor dfu_assoc = { static const struct usb_iface_assoc_descriptor dfu_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = DFU_IF_NO, .bFirstInterface = 4,
.bInterfaceCount = 1, .bInterfaceCount = 1,
.bFunctionClass = 0xFE, .bFunctionClass = 0xFE,
.bFunctionSubClass = 1, .bFunctionSubClass = 1,
@ -339,7 +315,7 @@ static const struct usb_iface_assoc_descriptor dfu_assoc = {
static const struct usb_endpoint_descriptor trace_endp[] = {{ static const struct usb_endpoint_descriptor trace_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = TRACE_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x85,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0, .bInterval = 0,
@ -348,7 +324,7 @@ static const struct usb_endpoint_descriptor trace_endp[] = {{
const struct usb_interface_descriptor trace_iface = { const struct usb_interface_descriptor trace_iface = {
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = TRACE_IF_NO, .bInterfaceNumber = 5,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 1, .bNumEndpoints = 1,
.bInterfaceClass = 0xFF, .bInterfaceClass = 0xFF,
@ -362,7 +338,7 @@ const struct usb_interface_descriptor trace_iface = {
static const struct usb_iface_assoc_descriptor trace_assoc = { static const struct usb_iface_assoc_descriptor trace_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = TRACE_IF_NO, .bFirstInterface = 5,
.bInterfaceCount = 1, .bInterfaceCount = 1,
.bFunctionClass = 0xFF, .bFunctionClass = 0xFF,
.bFunctionSubClass = 0xFF, .bFunctionSubClass = 0xFF,
@ -401,7 +377,11 @@ static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
.bNumInterfaces = TOTAL_INTERFACES, #if defined(PLATFORM_HAS_TRACESWO)
.bNumInterfaces = 6,
#else
.bNumInterfaces = 5,
#endif
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
@ -409,17 +389,20 @@ static const struct usb_config_descriptor config = {
.interface = ifaces, .interface = ifaces,
}; };
static char serial_no[DFU_SERIAL_LENGTH];
#define BOARD_IDENT "Black Magic Probe " PLATFORM_IDENT FIRMWARE_VERSION #if defined(STM32L0) || defined(STM32F3) || defined(STM32F4)
char serial_no[13];
#else
char serial_no[9];
#endif
static const char *usb_strings[] = { static const char *usb_strings[] = {
"Black Magic Debug", "Black Sphere Technologies",
BOARD_IDENT, BOARD_IDENT,
serial_no, serial_no,
"Black Magic GDB Server", "Black Magic GDB Server",
"Black Magic UART Port", "Black Magic UART Port",
"Black Magic DFU", DFU_IDENT,
#if defined(PLATFORM_HAS_TRACESWO) #if defined(PLATFORM_HAS_TRACESWO)
"Black Magic Trace Capture", "Black Magic Trace Capture",
#endif #endif
@ -433,14 +416,10 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
platform_request_boot(); platform_request_boot();
/* Reset core to enter bootloader */ /* Reset core to enter bootloader */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) SCB_RESET();
scb_reset_core();
#else
scb_reset_system();
#endif
} }
static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev, static int cdcacm_control_request(usbd_device *dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req)) void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{ {
@ -453,24 +432,24 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
cdcacm_set_modem_state(dev, req->wIndex, true, true); cdcacm_set_modem_state(dev, req->wIndex, true, true);
/* Ignore if not for GDB interface */ /* Ignore if not for GDB interface */
if(req->wIndex != GDB_IF_NO) if(req->wIndex != 0)
return USBD_REQ_HANDLED; return 1;
cdcacm_gdb_dtr = req->wValue & 1; cdcacm_gdb_dtr = req->wValue & 1;
return USBD_REQ_HANDLED; return 1;
case USB_CDC_REQ_SET_LINE_CODING: case USB_CDC_REQ_SET_LINE_CODING:
if(*len < sizeof(struct usb_cdc_line_coding)) if(*len < sizeof(struct usb_cdc_line_coding))
return USBD_REQ_NOTSUPP; return 0;
switch(req->wIndex) { switch(req->wIndex) {
case UART_IF_NO: case 2:
usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf); usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf);
return USBD_REQ_HANDLED; return 1;
case GDB_IF_NO: case 0:
return USBD_REQ_HANDLED; /* Ignore on GDB Port */ return 1; /* Ignore on GDB Port */
default: default:
return USBD_REQ_NOTSUPP; return 0;
} }
case DFU_GETSTATUS: case DFU_GETSTATUS:
if(req->wIndex == DFU_IF_NO) { if(req->wIndex == DFU_IF_NO) {
@ -482,17 +461,17 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
(*buf)[5] = 0; /* iString not used here */ (*buf)[5] = 0; /* iString not used here */
*len = 6; *len = 6;
return USBD_REQ_HANDLED; return 1;
} }
return USBD_REQ_NOTSUPP; return 0;
case DFU_DETACH: case DFU_DETACH:
if(req->wIndex == DFU_IF_NO) { if(req->wIndex == DFU_IF_NO) {
*complete = dfu_detach_complete; *complete = dfu_detach_complete;
return USBD_REQ_HANDLED; return 1;
} }
return USBD_REQ_NOTSUPP; return 0;
} }
return USBD_REQ_NOTSUPP; return 0;
} }
int cdcacm_get_config(void) int cdcacm_get_config(void)
@ -517,7 +496,6 @@ static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool d
notif->wLength = 2; notif->wLength = 2;
buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0); buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0);
buf[9] = 0; buf[9] = 0;
/* FIXME: Remove magic numbers */
usbd_ep_write_packet(dev, 0x82 + iface, buf, 10); usbd_ep_write_packet(dev, 0x82 + iface, buf, 10);
} }
@ -527,29 +505,26 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
/* GDB interface */ /* GDB interface */
#if defined(STM32F4) || defined(LM4F) || defined(SAMD) #if defined(STM32F4) || defined(LM4F) || defined(SAMD)
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, gdb_usb_out_cb); CDCACM_PACKET_SIZE, gdb_usb_out_cb);
#else #else
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, NULL);
#endif #endif
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK,
USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, NULL);
usbd_ep_setup(dev, (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
/* Serial interface */ /* Serial interface */
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb); CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb);
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK,
USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, usbuart_usb_in_cb); CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
usbd_ep_setup(dev, (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
#if defined(PLATFORM_HAS_TRACESWO) #if defined(PLATFORM_HAS_TRACESWO)
/* Trace interface */ /* Trace interface */
usbd_ep_setup(dev, TRACE_ENDPOINT | USB_REQ_TYPE_IN, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK,
64, trace_buf_drain); 64, trace_buf_drain);
#endif #endif
@ -561,8 +536,8 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
/* Notify the host that DCD is asserted. /* Notify the host that DCD is asserted.
* Allows the use of /dev/tty* devices on *BSD/MacOS * Allows the use of /dev/tty* devices on *BSD/MacOS
*/ */
cdcacm_set_modem_state(dev, GDB_IF_NO, true, true); cdcacm_set_modem_state(dev, 0, true, true);
cdcacm_set_modem_state(dev, UART_IF_NO, true, true); cdcacm_set_modem_state(dev, 2, true, true);
} }
/* We need a special large control buffer for this device: */ /* We need a special large control buffer for this device: */
@ -572,9 +547,9 @@ void cdcacm_init(void)
{ {
void exti15_10_isr(void); void exti15_10_isr(void);
serial_no_read(serial_no); serialno_read(serial_no);
usbdev = usbd_init(&USB_DRIVER, &dev_desc, &config, usb_strings, usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings,
sizeof(usb_strings)/sizeof(char *), sizeof(usb_strings)/sizeof(char *),
usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_control_buffer, sizeof(usbd_control_buffer));

View File

@ -34,7 +34,6 @@
#define CDCACM_GDB_ENDPOINT 1 #define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3 #define CDCACM_UART_ENDPOINT 3
#define TRACE_ENDPOINT 5
extern usbd_device *usbdev; extern usbd_device *usbdev;

View File

@ -1,199 +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/>.
*/
/* This file implements the low-level JTAG TAP interface. */
#include <stdio.h>
#include "general.h"
#include "jtagtap.h"
#include "gdb_packet.h"
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 */
jtagtap_soft_reset();
return 0;
}
static void jtagtap_reset(void)
{
#ifdef TRST_PORT
if (platform_hwversion() == 0) {
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();
}
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
{
uint16_t ret;
register volatile int32_t cnt;
gpio_set_val(TMS_PORT, TMS_PIN, dTMS);
gpio_set_val(TDI_PORT, TDI_PIN, dTDI);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
ret = gpio_get(TDO_PORT, TDO_PIN);
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt - 2; cnt > 0; cnt--);
//DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret);
return ret != 0;
}
static void jtagtap_tms_seq(uint32_t MS, int ticks)
{
gpio_set_val(TDI_PORT, TDI_PIN, 1);
int data = MS & 1;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks) {
gpio_set_val(TMS_PORT, TMS_PIN, data);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
MS >>= 1;
data = MS & 1;
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks) {
gpio_set_val(TMS_PORT, TMS_PIN, data);
gpio_set(TCK_PORT, TCK_PIN);
MS >>= 1;
data = MS & 1;
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
}
}
}
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);
uint8_t res = 0;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks > 1) {
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if (gpio_get(TDO_PORT, TDO_PIN)) {
res |= index;
}
if(!(index <<= 1)) {
*DO = res;
res = 0;
index = 1;
DI++; DO++;
}
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks > 1) {
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
if (gpio_get(TDO_PORT, TDO_PIN)) {
res |= index;
}
if(!(index <<= 1)) {
*DO = res;
res = 0;
index = 1;
DI++; DO++;
}
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
}
}
gpio_set_val(TMS_PORT, TMS_PIN, final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if (gpio_get(TDO_PORT, TDO_PIN)) {
res |= index;
}
*DO = res;
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
{
uint8_t index = 1;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks--) {
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if(!(index <<= 1)) {
index = 1;
DI++;
}
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks--) {
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
if(!(index <<= 1)) {
index = 1;
DI++;
}
gpio_clear(TCK_PORT, TCK_PIN);
}
}
}

View File

@ -20,7 +20,7 @@
#ifndef __SERIALNO_H #ifndef __SERIALNO_H
#define __SERIALNO_H #define __SERIALNO_H
char *serial_no_read(char *s); char *serialno_read(char *s);
#endif #endif

View File

@ -18,29 +18,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* This file implements the SW-DP interface. */ /* This file implements the low-level SW-DP interface. */
#include "general.h" #include "general.h"
#include "timing.h" #include "swdptap.h"
#include "adiv5.h"
enum { int swdptap_init(void)
SWDIO_STATUS_FLOAT = 0,
SWDIO_STATUS_DRIVE
};
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)
{ {
static int olddir = SWDIO_STATUS_FLOAT; return 0;
register volatile int32_t cnt; }
static void swdptap_turnaround(uint8_t dir)
{
static uint8_t olddir = 0;
/* Don't turnaround if direction not changing */ /* Don't turnaround if direction not changing */
if(dir == olddir) return; if(dir == olddir) return;
@ -50,166 +40,41 @@ static void swdptap_turnaround(int dir)
DEBUG("%s", dir ? "\n-> ":"\n<- "); DEBUG("%s", dir ? "\n-> ":"\n<- ");
#endif #endif
if(dir == SWDIO_STATUS_FLOAT) if(dir)
SWDIO_MODE_FLOAT(); SWDIO_MODE_FLOAT();
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;); if(!dir)
if(dir == SWDIO_STATUS_DRIVE)
SWDIO_MODE_DRIVE(); SWDIO_MODE_DRIVE();
} }
static uint32_t swdptap_seq_in(int ticks) bool swdptap_bit_in(void)
{ {
uint32_t index = 1; uint16_t ret;
uint32_t ret = 0;
int len = ticks;
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_FLOAT); swdptap_turnaround(1);
if (swd_delay_cnt) {
while (len--) {
int res;
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
ret |= (res) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
volatile int res;
while (len--) {
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
ret |= (res) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
}
#ifdef DEBUG_SWD_BITS
for (int i = 0; i < len; i++)
DEBUG("%d", (ret & (1 << i)) ? 1 : 0);
#endif
return ret;
}
static bool swdptap_seq_in_parity(uint32_t *ret, int ticks) ret = gpio_get(SWDIO_PORT, SWDIO_PIN);
{
uint32_t index = 1;
uint32_t res = 0;
bool bit;
int len = ticks;
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_FLOAT);
if (swd_delay_cnt) {
while (len--) {
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
res |= (bit) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (len--) {
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
res |= (bit) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
}
int parity = __builtin_popcount(res);
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
parity += (bit) ? 1 : 0;
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
#ifdef DEBUG_SWD_BITS #ifdef DEBUG_SWD_BITS
for (int i = 0; i < len; i++) DEBUG("%d", ret?1:0);
DEBUG("%d", (res & (1 << i)) ? 1 : 0);
#endif #endif
*ret = res;
/* Terminate the read cycle now */ return ret != 0;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
return (parity & 1);
} }
static void swdptap_seq_out(uint32_t MS, int ticks) void swdptap_bit_out(bool val)
{ {
#ifdef DEBUG_SWD_BITS #ifdef DEBUG_SWD_BITS
for (int i = 0; i < ticks; i++) DEBUG("%d", val);
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif #endif
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
if (swd_delay_cnt) {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
MS >>= 1;
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
MS >>= 1;
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
}
}
static void swdptap_seq_out_parity(uint32_t MS, int ticks) swdptap_turnaround(0);
{
int parity = __builtin_popcount(MS); gpio_set_val(SWDIO_PORT, SWDIO_PIN, val);
#ifdef DEBUG_SWD_BITS
for (int i = 0; i < ticks; i++)
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
if (swd_delay_cnt) {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
}
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
} }
int swdptap_init(ADIv5_DP_t *dp)
{
dp->seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity;
return 0;
}

View File

@ -21,8 +21,6 @@
void platform_timeout_set(platform_timeout *t, uint32_t ms) void platform_timeout_set(platform_timeout *t, uint32_t ms)
{ {
if (ms <= SYSTICKMS)
ms = SYSTICKMS;
t->time = platform_time_ms() + ms; t->time = platform_time_ms() + ms;
} }
@ -30,3 +28,4 @@ bool platform_timeout_is_expired(platform_timeout *t)
{ {
return platform_time_ms() > t->time; return platform_time_ms() > t->time;
} }

View File

@ -24,7 +24,7 @@ struct platform_timeout {
uint32_t time; uint32_t time;
}; };
extern int32_t swj_delay_cnt;
uint32_t platform_time_ms(void); uint32_t platform_time_ms(void);
#endif /* __TIMING_H */ #endif /* __TIMING_H */

View File

@ -22,21 +22,7 @@
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2 void traceswo_init(uint32_t baudrate);
/* Default line rate, used as default for a request without baudrate */
#define SWO_DEFAULT_BAUD (2250000)
void traceswo_init(uint32_t baudrate, uint32_t swo_chan_bitmask);
#else
void traceswo_init(uint32_t swo_chan_bitmask);
#endif
void trace_buf_drain(usbd_device *dev, uint8_t ep); void trace_buf_drain(usbd_device *dev, uint8_t ep);
/* set bitmask of swo channels to be decoded */
void traceswo_setmask(uint32_t mask);
/* print decoded swo packet on usb serial */
uint16_t traceswo_decode(usbd_device *usbd_dev, uint8_t addr,
const void *buf, uint16_t len);
#endif #endif

View File

@ -1,57 +1,28 @@
CROSS_COMPILE ?= arm-none-eabi- CROSS_COMPILE ?= arm-none-eabi-
BMP_BOOTLOADER ?=
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-DSTM32F4 -I../libopencm3/include \ -DSTM32F4 -DF4DISCOVERY -I../libopencm3/include \
-Iplatforms/stm32 -Iplatforms/stm32
ifeq ($(BLACKPILL), 1) LDFLAGS = -lopencm3_stm32f4 -Wl,--defsym,_stack=0x20010000 \
LINKER_SCRIPT=platforms/stm32/blackpillv2.ld -Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
CFLAGS += -DBLACKPILL=1
else
LINKER_SCRIPT=platforms/stm32/f4discovery.ld
endif
LDFLAGS_BOOT = -lopencm3_stm32f4 \
-Wl,-T,$(LINKER_SCRIPT) -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-L../libopencm3/lib -L../libopencm3/lib
ifeq ($(BMP_BOOTLOADER), 1)
$(info Load address 0x08004000 for BMPBootloader)
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000
CFLAGS += -DDFU_SERIAL_LENGTH=9
else
LDFLAGS += $(LDFLAGS_BOOT)
CFLAGS += -DDFU_SERIAL_LENGTH=13
endif
VPATH += platforms/stm32 VPATH += platforms/stm32
SRC += cdcacm.c \ SRC += cdcacm.c \
traceswodecode.c \
traceswo.c \ traceswo.c \
usbuart.c \ usbuart.c \
serialno.c \ serialno.c \
timing.c \ timing.c \
timing_stm32.c \ timing_stm32.c \
ifneq ($(BMP_BOOTLOADER), 1)
all: blackmagic.bin all: blackmagic.bin
else
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic_dfu: usbdfu.o dfucore.o dfu_f4.o serialno.o
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
endif
host_clean: host_clean:
-$(Q)$(RM) blackmagic.bin -$(Q)$(RM) blackmagic.bin

View File

@ -0,0 +1,28 @@
System vs BMP Bootloader
========================
For the BMP bootloader, flashing was not reliable. So we use the system
bootloder unconditional.
Connections:
====================
PA0: User button to force system bootloader entry with reset
PA2/PA3 eventual connected to the STLINK/ STM32F103C8
PC2: TDI
PC4: TMS/SWDIO
PC5: TCK/SWCLK
PC6: TDO/TRACESWO
PC1: TRST
PC8: SRST
PD15/Blue Led: Indicator that system bootloader is entered via BMP
Bootstrapping the F4Discovery on-board ST-Link
==============================================
http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe has some hints
how to modify the F4Discovery on-board ST-Link. If you try to do so and hit
a problem that stands some test like that you load the right firmware to the
right device via the right BMP probe, explain, report and ask on the
blackmagic mailing list http://sourceforge.net/mail/?group_id=407419.

View File

@ -1,65 +0,0 @@
# Firmware BMP for STM32F407 DISCO boards
Kept for historical reasons to load BMP bootloader to the STM32F103 of the onboard STLINK or external STLINKs. As stlink-tool now allows to load BMP firmware via the original STLINK bootloader is no longer really needed.
## Connections:
PC2: TDI<br>
PC4: TMS/SWDIO<br>
PC5: TCK/SWCLK<br>
PC6: TDO/TRACESWO<br>
PC1: TRST<br>
PC8: SRST<br>
# Alternate build for stm32f401 stm32f411 MiniF4 aka BlackPillV2 boards.
https://github.com/WeActTC/MiniSTM32F4x1
## Connections:
* JTAG/SWD
* PA1: TDI
* PA13: TMS/SWDIO
* PA14: TCK/SWCLK
* PB3: TDO/TRACESWO
* PB5: TRST
* PB4: SRST
* USB USART
* PB6: USART1 TX (usbuart_xxx)
* PB7: USART1 RX (usbuart_xxx)
* +3V3.
* PB8 - turn on IRLML5103 transistor
How to Build
========================================
```
cd blackmagic
make clean
make PROBE_HOST=f4discovery BLACKPILL=1
```
How to Flash with dfu
========================================
* After build:
* 1) `apt install dfu-util`
* 2) Force the F4 into system bootloader mode by jumpering "BOOT0" to "3V3" and "PB2/BOOT1" to "GND" and reset (RESET button). System bootloader should appear.
* 3) `dfu-util -a 0 --dfuse-address 0x08000000 -D blackmagic.bin`
To exit from dfu mode press a "key" and "reset", release reset. BMP firmware should appear
10 pin male from pins
========================================
| PB3/TDO | PB7/RX | PB6/TX | X | PA1/TDI |
| -------- | ----------- | ---------- | ---------- | ------- |
| PB4/SRST | +3V3/PB8 SW | PA13/SWDIO | PA14/SWCLK | GND |
SWJ frequency setting
====================================
https://github.com/blackmagic-debug/blackmagic/pull/783#issue-529197718
`mon freq 900k` helps at most

View File

@ -27,7 +27,7 @@
#include "usbuart.h" #include "usbuart.h"
#include "morse.h" #include "morse.h"
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h> #include <libopencm3/stm32/exti.h>
@ -37,32 +37,20 @@
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h> #include <libopencm3/cm3/cortex.h>
#ifdef BLACKPILL
#include <libopencm3/usb/dwc/otg_fs.h>
#endif
jmp_buf fatal_error_jmpbuf; jmp_buf fatal_error_jmpbuf;
extern char _ebss[]; extern uint32_t _ebss;
void platform_init(void) void platform_init(void)
{ {
volatile uint32_t *magic = (uint32_t *)_ebss; volatile uint32_t *magic = (uint32_t *) &_ebss;
/* Enable GPIO peripherals */
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOC);
#ifdef BLACKPILL
rcc_periph_clock_enable(RCC_GPIOB);
#else
rcc_periph_clock_enable(RCC_GPIOD);
#endif
/* Check the USER button*/ /* Check the USER button*/
rcc_periph_clock_enable(RCC_GPIOA);
if (gpio_get(GPIOA, GPIO0) || if (gpio_get(GPIOA, GPIO0) ||
((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) ((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) {
{
magic[0] = 0; magic[0] = 0;
magic[1] = 0; magic[1] = 0;
/* Assert blue LED as indicator we are in the bootloader */ /* Assert blue LED as indicator we are in the bootloader */
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, LED_BOOTLOADER); GPIO_PUPD_NONE, LED_BOOTLOADER);
gpio_set(LED_PORT, LED_BOOTLOADER); gpio_set(LED_PORT, LED_BOOTLOADER);
@ -70,65 +58,39 @@ void platform_init(void)
As we just come out of reset, no other deinit is needed!*/ As we just come out of reset, no other deinit is needed!*/
rcc_periph_clock_enable(RCC_SYSCFG); rcc_periph_clock_enable(RCC_SYSCFG);
SYSCFG_MEMRM &= ~3; SYSCFG_MEMRM &= ~3;
SYSCFG_MEMRM |= 1; SYSCFG_MEMRM |= 1;
scb_reset_core(); scb_reset_core();
} }
#ifdef BLACKPILL
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_84MHZ]); rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_48MHZ]);
#else
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
#endif
/* Enable peripherals */ /* Enable peripherals */
rcc_periph_clock_enable(RCC_OTGFS); rcc_periph_clock_enable(RCC_OTGFS);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_GPIOD);
rcc_periph_clock_enable(RCC_CRC); rcc_periph_clock_enable(RCC_CRC);
/* Set up USB Pins and alternate function*/ /* Set up USB Pins and alternate function*/
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO10 | GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
#ifdef BLACKPILL GPIOC_OSPEEDR &=~0xF30;
GPIOA_OSPEEDR &= 0x3C00000C;
GPIOA_OSPEEDR |= 0x28000008;
#else
GPIOC_OSPEEDR &= ~0xF30;
GPIOC_OSPEEDR |= 0xA20; GPIOC_OSPEEDR |= 0xA20;
#endif
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
TCK_PIN | TDI_PIN); TMS_PIN | TCK_PIN | TDI_PIN);
gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, TMS_PIN);
gpio_set_output_options(JTAG_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
TCK_PIN | TDI_PIN | TMS_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
TDO_PIN); TDO_PIN);
gpio_set_output_options(TDO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
TDO_PIN | TMS_PIN);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER); LED_UART | LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER);
gpio_mode_setup(LED_PORT_UART, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_UART);
#ifdef PLATFORM_HAS_POWER_SWITCH
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_mode_setup(PWR_BR_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
PWR_BR_PIN);
#endif
platform_timing_init(); platform_timing_init();
usbuart_init(); usbuart_init();
cdcacm_init(); cdcacm_init();
#ifdef BLACKPILL
// https://github.com/libopencm3/libopencm3/pull/1256#issuecomment-779424001
OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN;
OTG_FS_GCCFG &= ~(OTG_GCCFG_VBUSBSEN | OTG_GCCFG_VBUSASEN);
#endif
} }
void platform_srst_set_val(bool assert) { (void)assert; } void platform_srst_set_val(bool assert) { (void)assert; }
@ -136,25 +98,13 @@ bool platform_srst_get_val(void) { return false; }
const char *platform_target_voltage(void) const char *platform_target_voltage(void)
{ {
return NULL; return "ABSENT!";
} }
void platform_request_boot(void) void platform_request_boot(void)
{ {
uint32_t *magic = (uint32_t *)&_ebss; uint32_t *magic = (uint32_t *) &_ebss;
magic[0] = BOOTMAGIC0; magic[0] = BOOTMAGIC0;
magic[1] = BOOTMAGIC1; magic[1] = BOOTMAGIC1;
scb_reset_system(); scb_reset_system();
} }
#ifdef PLATFORM_HAS_POWER_SWITCH
bool platform_target_get_power(void)
{
return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
}
void platform_target_set_power(bool power)
{
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
}
#endif

View File

@ -27,80 +27,15 @@
#include "gpio.h" #include "gpio.h"
#include "timing.h" #include "timing.h"
#include "timing_stm32.h" #include "timing_stm32.h"
#include "version.h"
#include <setjmp.h> #include <setjmp.h>
#define PLATFORM_HAS_TRACESWO #define PLATFORM_HAS_TRACESWO
#ifdef BLACKPILL #define BOARD_IDENT "Black Magic Probe (F4Discovery), (Firmware " FIRMWARE_VERSION ")"
#define PLATFORM_IDENT "(F4Discovery/BlackPillV2) " #define DFU_IDENT "Black Magic Firmware Upgrade (F4Discovery)"
/* Important pin mappings for STM32 implementation:
* JTAG/SWD
* PA1: TDI<br>
* PA13: TMS/SWDIO<br>
* PA14: TCK/SWCLK<br>
* PB3: TDO/TRACESWO<br>
* PB5: TRST<br>
* PB4: SRST<br>
* USB USART
* PB6: USART1 TX
* PB7: USART1 RX
* +3V3
* PB8 - turn on IRLML5103 transistor
* Force DFU mode button: PA0
*/
/* Hardware definitions... */ #define SCB_RESET() scb_reset_core();
#define JTAG_PORT GPIOA
#define TDI_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT GPIOB
#define TDI_PIN GPIO1
#define TMS_PIN GPIO13
#define TCK_PIN GPIO14
#define TDO_PIN GPIO3
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_PIN TMS_PIN
#define SWCLK_PIN TCK_PIN
#define TRST_PORT GPIOB
#define TRST_PIN GPIO5
#define SRST_PORT GPIOB
#define SRST_PIN GPIO4
#define PWR_BR_PORT GPIOB
#define PWR_BR_PIN GPIO8
#define LED_PORT GPIOC
#define LED_PORT_UART GPIOA
#define LED_UART GPIO1
#define LED_IDLE_RUN GPIO15
#define LED_ERROR GPIO14
#define LED_BOOTLOADER GPIO13
#define USBUSART USART1
#define USBUSART_CR1 USART1_CR1
#define USBUSART_DR USART1_DR
#define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_CLK RCC_USART1
#define USBUSART_PORT GPIOB
#define USBUSART_TX_PIN GPIO6
#define USBUSART_RX_PIN GPIO7
#define USBUSART_ISR(x) usart1_isr(x)
#define USBUSART_DMA_BUS DMA2
#define USBUSART_DMA_CLK RCC_DMA2
#define USBUSART_DMA_TX_CHAN DMA_STREAM7
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x)
#define USBUSART_DMA_RX_CHAN DMA_STREAM5
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x)
/* For STM32F4 DMA trigger source must be specified */
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
#else
#define PLATFORM_IDENT "(F4Discovery) "
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
@ -147,28 +82,6 @@
#define LED_IDLE_RUN GPIO13 #define LED_IDLE_RUN GPIO13
#define LED_ERROR GPIO14 #define LED_ERROR GPIO14
#define LED_BOOTLOADER GPIO15 #define LED_BOOTLOADER GPIO15
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_DR USART3_DR
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_CLK RCC_USART3
#define USBUSART_PORT GPIOD
#define USBUSART_TX_PIN GPIO8
#define USBUSART_RX_PIN GPIO9
#define USBUSART_ISR(x) usart3_isr(x)
#define USBUSART_DMA_BUS DMA1
#define USBUSART_DMA_CLK RCC_DMA1
#define USBUSART_DMA_TX_CHAN DMA_STREAM3
#define USBUSART_DMA_TX_IRQ NVIC_DMA1_STREAM3_IRQ
#define USBUSART_DMA_TX_ISR(x) dma1_stream3_isr(x)
#define USBUSART_DMA_RX_CHAN DMA_STREAM1
#define USBUSART_DMA_RX_IRQ NVIC_DMA1_STREAM1_IRQ
#define USBUSART_DMA_RX_ISR(x) dma1_stream1_isr(x)
/* For STM32F4 DMA trigger source must be specified */
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
#endif
#define BOOTMAGIC0 0xb007da7a #define BOOTMAGIC0 0xb007da7a
#define BOOTMAGIC1 0xbaadfeed #define BOOTMAGIC1 0xbaadfeed
@ -182,35 +95,49 @@
#define SWDIO_MODE_DRIVE() \ #define SWDIO_MODE_DRIVE() \
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \ gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN); GPIO_PUPD_NONE, SWDIO_PIN);
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
USBUSART_RX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define USB_DRIVER stm32f107_usb_driver #define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ #define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR(x) otg_fs_isr(x) #define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (1 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (2 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USBUSART_DMA (2 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4)
#define IRQ_PRI_TRACE (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_CLK RCC_USART3
#define USBUSART_TX_PORT GPIOD
#define USBUSART_TX_PIN GPIO8
#define USBUSART_RX_PORT GPIOD
#define USBUSART_RX_PIN GPIO9
#define USBUSART_ISR usart3_isr
#define USBUSART_TIM TIM4
#define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
#define USBUSART_TIM_ISR tim4_isr
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3 #define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) #define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
#define TRACE_IRQ NVIC_TIM3_IRQ #define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR(x) tim3_isr(x) #define TRACE_ISR tim3_isr
#define DEBUG(...)
#define gpio_set_val(port, pin, val) do { \ #define gpio_set_val(port, pin, val) do { \
if(val) \ if(val) \
@ -228,37 +155,11 @@ static inline int platform_hwversion(void)
return 0; return 0;
} }
/* /* Use newlib provided integer only stdio functions */
* Use newlib provided integer only stdio functions
*/
/* sscanf */
#ifdef sscanf
#undef sscanf
#define sscanf siscanf #define sscanf siscanf
#else
#define sscanf siscanf
#endif
/* sprintf */
#ifdef sprintf
#undef sprintf
#define sprintf siprintf #define sprintf siprintf
#else
#define sprintf siprintf
#endif
/* vasprintf */
#ifdef vasprintf
#undef vasprintf
#define vasprintf vasiprintf #define vasprintf vasiprintf
#else
#define vasprintf vasiprintf
#endif
/* snprintf */
#ifdef snprintf
#undef snprintf
#define snprintf sniprintf #define snprintf sniprintf
#else
#define snprintf sniprintf
#endif
#endif #endif

View File

@ -1,85 +0,0 @@
CC ?= gcc
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
CFLAGS +=-I ./target -I./platforms/pc
# Define HOSTED_BMP_ONLY to '0' in order to build the hosted blackmagic
# executable with support for other probes beside BMP. Default HOSTED_BMP_ONLY
# == 1 on Windows makes linking against the libftdi and libusb libraries
# unnecessary.
# This can be useful to minimize external dependencies, and make building on
# windows systems easier and is default now.
ifneq (, $(findstring linux, $(SYS)))
HOSTED_BMP_ONLY ?= 0
else
HOSTED_BMP_ONLY ?= 1
endif
CFLAGS += -DHOSTED_BMP_ONLY=$(HOSTED_BMP_ONLY)
ifneq (, $(findstring linux, $(SYS)))
SRC += serial_unix.c
HIDAPILIB = hidapi-hidraw
ifeq ($(ASAN), 1)
CFLAGS += -fsanitize=address -Wno-format-truncation
LDFLAGS += -lasan
endif
else ifneq (, $(findstring mingw, $(SYS)))
# Build for windows versions Vista, and above, where the
# 'SetupDiGetDevicePropertyW()' function is available
CFLAGS += -D_WIN32_WINNT=0x600
SRC += serial_win.c
LDFLAGS += -lws2_32
LDFLAGS += -lsetupapi
else ifneq (, $(findstring cygwin, $(SYS)))
# Build for windows versions Vista, and above, where the
# 'SetupDiGetDevicePropertyW()' function is available
CFLAGS += -D_WIN32_WINNT=0x600
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))
SRC += serial_unix.c
LDFLAGS += -lhidapi
LDFLAGS += -framework CoreFoundation
CFLAGS += -Ihidapi/hidapi
HIDAPILIB = hidapi
endif
ifneq ($(HOSTED_BMP_ONLY), 1)
$(shell pkg-config --exists libftdi1)
ifneq ($(.SHELLSTATUS), 0)
$(error Please install libftdi1 dependency or set HOSTED_BMP_ONLY to 1)
endif
LDFLAGS += -lusb-1.0
CFLAGS += $(shell pkg-config --cflags libftdi1)
LDFLAGS += $(shell pkg-config --libs libftdi1)
CFLAGS += -Wno-missing-field-initializers
endif
ifneq ($(HOSTED_BMP_ONLY), 1)
CFLAGS += -DCMSIS_DAP
SRC += cmsis_dap.c dap.c
ifneq (, $(findstring mingw, $(SYS)))
SRC += hid.c
else
$(shell pkg-config --exists $(HIDAPILIB))
ifneq ($(.SHELLSTATUS), 0)
$(error Please install $(HIDAPILIB) dependency or set HOSTED_BMP_ONLY to 1)
endif
CFLAGS += $(shell pkg-config --cflags $(HIDAPILIB))
LDFLAGS += $(shell pkg-config --libs $(HIDAPILIB))
endif
endif
VPATH += platforms/pc
SRC += timing.c cl_utils.c utils.c
SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c
ifneq ($(HOSTED_BMP_ONLY), 1)
SRC += bmp_libusb.c stlinkv2.c
SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c
SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c
else
SRC += bmp_serial.c
endif
PC_HOSTED = 1

View File

@ -1,177 +0,0 @@
# PC-Hosted BMP
Compile in src with "make PROBE_HOST=hosted". This needs minimal external
support. "make PROBE_HOST=hosted HOSTED_BMP_ONLY=0" will compile support for FTDI,
STLink, CMSIS-DAP and JLINK probes, but requires external libraries.
## 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 on 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
```
blackmagic -t
```
### Directly flash a binary file at lowest flash address
```
blackmagic <file.bin>
```
or with the -S argument at some other address
```
blackmagic -S 0x08002000 <file.bin>
```
### Read flash to binary file
```
blackmagic -r <file>.bin
```
### Verify flash against binary file
```
blackmagic -V <file>.bin
```
### Show more options
```
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:
### libusb
### libftdi, for FTDI support
## Other used libraries:
### hidapi-libusb, for CMSIS-DAP support
## Compiling on windows
You can crosscompile blackmagic for windows with mingw or on windows
with cygwin. For suppport of other probes beside BMP, 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.
PC-hosted BMP for windows can also be built with [MSYS2](https://www.msys2.org/),
in windows. Make sure to use the `mingw64` shell from msys2, otherwise,
you may get compilation errors. You will need to install the libusb
and libftdi libraries, and have the correct mingw compiler.
You can use these commands to install dependencies, and build PC-hosted BMP
from a mingw64 shell, from within the `src` directory:
```
pacman -S mingw-w64-x86_64-libusb --needed
pacman -S mingw-w64-x86_64-libftdi --needed
pacman -S mingw-w64-x86_64-gcc --needed
PROBE_HOST=hosted make
```
For suppport of other probes beside BMP, libusb access is needed. To prepare
libusb access to the ftdi/stlink/jlink/cmsis-dap devices, run zadig
https://zadig.akeo.ie/. Choose WinUSB(libusb-1.0).
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)".
## Supported debuggers
REMOTE_BMP is a "normal" BMP usb connected
| Debugger | Speed | Remarks
| ------------ | ----- | ------
| REMOTE_BMP | +++ | Requires recent firmware for decent speed
Probes below only when compiled with HOSTED_BMP_ONLY=0
| 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
## Device matching
As other USB dongles already connected to the host PC may use FTDI chips,
cable descriptions must be provided to match with the dongle.
To match the dongle, at least USB VID/PID that must match.
If a description is given, the USB device must provide that string. If a
serial number string is given on the command line, that number must match
with serial number in the USB descriptor of the device.
## FTDI connection possibilities:
| Direct Connection |
| ----------------------|
| MPSSE_SK --> JTAG_TCK |
| MPSSE_DO --> JTAG_TDI |
| MPSSE_DI <-- JTAG_TDO |
| MPSSE_CS <-> JTAG_TMS |
\+ JTAG and bitbanging SWD is possible<br>
\- No level translation, no buffering, no isolation<br>
Example: [Flossjtag](https://randomprojects.org/wiki/Floss-JTAG).
| Resistor SWD |
|------------------------|
| MPSSE_SK ---> JTAG_TCK |
| MPSSE_DO -R-> JTAG_TMS |
| MPSSE_DI <--- JTAG_TMS |
BMP would allow direct MPSSE_DO ->JTAG_TMS connections as BMP tristates DO
when reading. Resistor defeats contentions anyways. R is typical choosen
in the range of 470R
\+ MPSSE SWD possible<br>
\- No Jtag, no level translation, no buffering, no isolation<br>
|Direct buffered Connection|
|--------------------------|
| MPSSE_SK -B-> JTAG_TCK |
| MPSSE_DO -B-> JTAG_TDI |
| MPSSE_DI <-B- JTAG_TDO |
| MPSSE_CS -B-> JTAG_TMS |
\+ Only Jtag, buffered, possible level translation and isolation<br>
\- No SWD<br>
Example: [Turtelizer]http://www.ethernut.de/en/hardware/turtelizer/index.html)
[schematics](http://www.ethernut.de/pdf/turtelizer20c-schematic.pdf)
The 'r' command line arguments allows to specify an external SWD
resistor connection added to some existing cable. Jtag is not possible
together with the 'r' argument.
### Many variants possible
As the FTDI has more pins, these pins may be used to control
enables of buffers and multiplexer selection in many variants.
### FTDI SWD speed
SWD read needs two USB round trip, one for the acknowledge and one
round-trip after the data phase, while JTAG only needs one round-trip.
For that, SWD read speed is about half the JTAG read speed.
### Reset, Target voltage readback etc
The additional pins may also control Reset functionality, provide
information if target voltage is applied. etc.
### Cable descriptions
Please help to verify the cable description and give feedback on the
cables already listed and propose other cable. A link to the schematics
is welcome.
## Feedback
### Issues and Pull request on https://github.com/blackmagic-debug/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

View File

@ -1,52 +0,0 @@
#if !defined(__BMP_LIBUSB_H)
#define __BMP_LIBUSB_H
#include "cl_utils.h"
#if HOSTED_BMP_ONLY != 1
# 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 usb_link_s {
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
typedef struct bmp_info_s {
bmp_type_t bmp_type;
char dev;
char serial[64];
char manufacturer[512];
char product[256];
char version[256];
bool is_jtag;
#if HOSTED_BMP_ONLY != 1
libusb_context *libusb_ctx;
struct ftdi_context *ftdic;
usb_link_t *usb_link;
unsigned int vid;
unsigned int pid;
uint8_t interface_num;
uint8_t in_ep;
uint8_t out_ep;
#endif
} bmp_info_t;
extern bmp_info_t info;
void bmp_ident(bmp_info_t *info);
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info);
void libusb_exit_function(bmp_info_t *info);
#endif

View File

@ -1,473 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright(C) 2020 - 2022 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/>.
*/
/* Find all known usb connected debuggers */
#include "general.h"
#include "libusb-1.0/libusb.h"
#include "cl_utils.h"
#include "ftdi_bmp.h"
#include "version.h"
#define NO_SERIAL_NUMBER "<no serial number>"
void bmp_ident(bmp_info_t *info)
{
DEBUG_INFO("BMP hosted %s\n for ST-Link V2/3, CMSIS_DAP, JLINK and "
"LIBFTDI/MPSSE\n", FIRMWARE_VERSION);
if (info && info->vid && info->pid)
DEBUG_INFO("Using %04x:%04x %s %s\n %s\n", info->vid, info->pid,
(info->serial[0]) ? info->serial : NO_SERIAL_NUMBER,
info->manufacturer,
info->product);
}
void libusb_exit_function(bmp_info_t *info)
{
if (!info->usb_link)
return;
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);
}
}
static bmp_type_t find_cmsis_dap_interface(libusb_device *dev,bmp_info_t *info) {
bmp_type_t type = BMP_TYPE_NONE;
struct libusb_config_descriptor *conf;
char interface_string[128];
int res = libusb_get_active_config_descriptor(dev, &conf);
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_active_config_descriptor() failed: %s",
libusb_strerror(res));
return type;
}
libusb_device_handle *handle;
res = libusb_open(dev, &handle);
if (res != LIBUSB_SUCCESS) {
DEBUG_INFO("INFO: libusb_open() failed: %s\n",
libusb_strerror(res));
libusb_free_config_descriptor(conf);
return type;
}
for (int i = 0; i < conf->bNumInterfaces; i++) {
const struct libusb_interface_descriptor *interface = &conf->interface[i].altsetting[0];
if (!interface->iInterface) {
continue;
}
res = libusb_get_string_descriptor_ascii(
handle, interface->iInterface, (uint8_t*)interface_string,
sizeof(interface_string));
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_string_descriptor_ascii() failed: %s\n",
libusb_strerror(res));
continue;
}
if (!strstr(interface_string, "CMSIS")) {
continue;
}
type = BMP_TYPE_CMSIS_DAP;
if (interface->bInterfaceClass == 0xff && interface->bNumEndpoints == 2) {
info->interface_num = interface->bInterfaceNumber;
for (int j = 0; j < interface->bNumEndpoints; j++) {
uint8_t n = interface->endpoint[j].bEndpointAddress;
if (n & 0x80) {
info->in_ep = n;
} else {
info->out_ep = n;
}
}
/* V2 is preferred, return early. */
break;
}
}
libusb_free_config_descriptor(conf);
return type;
}
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
libusb_device **devs;
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_cable) {
if (!strcmp(cl_opts->opt_cable, "list") ||
!strcmp(cl_opts->opt_cable, "l")) {
cable_desc_t *cable = cable_desc;
DEBUG_WARN("Available cables:\n");
for (; cable->name; ++cable) {
DEBUG_WARN("\t%s\n", cable->name);
}
exit(0);
}
info->bmp_type = BMP_TYPE_LIBFTDI;
}
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];
bool access_problems = false;
char *active_cable = NULL;
bool ftdi_unknown = false;
rescan:
found_debuggers = 0;
serial[0] = 0;
manufacturer[0] = 0;
product[0] = 0;
access_problems = false;
active_cable = NULL;
ftdi_unknown = false;
for (size_t i = 0; devs[i]; ++i) {
bmp_type_t type = BMP_TYPE_NONE;
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;
}
/* Exclude hubs from testing. Probably more classes could be excluded here!*/
switch (desc.bDeviceClass) {
case LIBUSB_CLASS_HUB:
case LIBUSB_CLASS_WIRELESS:
continue;
}
libusb_device_handle *handle = NULL;
res = libusb_open(dev, &handle);
if (res != LIBUSB_SUCCESS) {
if (!access_problems) {
DEBUG_INFO("INFO: Open USB %04x:%04x class %2x failed\n",
desc.idVendor, desc.idProduct, desc.bDeviceClass);
access_problems = true;
}
continue;
}
/* If the device even has a serial number string, fetch it */
if (desc.iSerialNumber) {
res = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
(uint8_t *)serial, sizeof(serial));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
libusb_close(handle);
continue;
}
/* Device has no serial and that's ok. */
else if (res <= 0)
serial[0] = '\0';
}
else
serial[0] = '\0';
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
libusb_close(handle);
continue;
}
/* Attempt to get the manufacturer string */
if (desc.iManufacturer) {
res = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
(uint8_t *)manufacturer, sizeof(manufacturer));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch manufacturer string failed: %s\n",
libusb_strerror(res));
libusb_close(handle);
continue;
}
/* Device has no manufacturer string and that's ok. */
else if (res <= 0)
manufacturer[0] = '\0';
}
else
manufacturer[0] = '\0';
/* Attempt to get the product string */
if (desc.iProduct) {
res = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
(uint8_t *)product, sizeof(product));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch product string failed: %s\n",
libusb_strerror(res));
libusb_close(handle);
continue;
}
/* Device has no product string and that's ok. */
else if (res <= 0)
product[0] = '\0';
}
else
product[0] = '\0';
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) {
if (desc.idProduct == PRODUCT_ID_BMP)
type = BMP_TYPE_BMP;
else {
if (desc.idProduct == PRODUCT_ID_BMP_BL)
DEBUG_WARN("BMP in bootloader mode found. Restart or reflash!\n");
continue;
}
} else if (type == BMP_TYPE_NONE &&
(type = find_cmsis_dap_interface(dev, info)) != BMP_TYPE_NONE) {
/* find_cmsis_dap_interface has set valid type*/
} else if (strstr(manufacturer, "CMSIS") || strstr(product, "CMSIS"))
type = BMP_TYPE_CMSIS_DAP;
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_NO_MSD ||
desc.idProduct == PRODUCT_ID_STLINKV3_BL ||
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 (desc.idVendor == VENDOR_ID_SEGGER)
type = BMP_TYPE_JLINK;
else {
cable_desc_t *cable = cable_desc;
for (; cable->name; ++cable) {
bool found = false;
if (cable->vendor != desc.idVendor || cable->product != desc.idProduct)
continue; /* VID/PID do not match*/
if (cl_opts->opt_cable) {
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)))
continue; /* cable names do not match*/
else
found = true;
}
if (cable->description) {
if (strncmp(cable->description, product, strlen(cable->description)))
continue; /* discriptions do not match*/
else
found = true;
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
if (cable->vendor == 0x0403 && /* FTDI*/
(cable->product == 0x6010 || /* FT2232C/D/H*/
cable->product == 0x6011 || /* FT4232H Quad HS USB-UART/FIFO IC */
cable->product == 0x6014)) { /* FT232H Single HS USB-UART/FIFO IC */
ftdi_unknown = true;
continue; /* Cable name is needed */
}
}
if (found) {
active_cable = cable->name;
type = BMP_TYPE_LIBFTDI;
break;
}
}
if (!cable->name)
continue;
}
if (report) {
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
serial[0] ? serial : NO_SERIAL_NUMBER,
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 + 1) {
found_debuggers = 1;
break;
} else
++found_debuggers;
}
if (found_debuggers == 0 && ftdi_unknown)
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
if (found_debuggers == 1 && !cl_opts->opt_cable && info->bmp_type == BMP_TYPE_LIBFTDI)
cl_opts->opt_cable = active_cable;
if (!found_debuggers && cl_opts->opt_list_only)
DEBUG_WARN("No usable debugger found\n");
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> "
"or -s <(partial)serial no.>\n",
found_debuggers);
report = true;
goto rescan;
} else {
if (found_debuggers > 0)
access_problems = false;
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;
}
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) {
libusb_fill_bulk_transfer(link->req_trans,
link->ul_libusb_device_handle,
link->ep_tx | LIBUSB_ENDPOINT_OUT,
txbuf, txsize,
NULL, NULL, 0);
size_t i = 0;
DEBUG_WIRE(" Send (%3zu): ", txsize);
for (; i < txsize; ++i) {
DEBUG_WIRE("%02x", txbuf[i]);
if ((i & 7U) == 7U)
DEBUG_WIRE(".");
if ((i & 31U) == 31U)
DEBUG_WIRE("\n ");
}
if (!(i & 31U))
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) {
const size_t rxlen = (size_t)res;
DEBUG_WIRE(" Rec (%zu/%zu)", rxsize, rxlen);
for (size_t i = 0; i < rxlen && i < 32 ; ++i) {
if (i && ((i & 7U) == 0U))
DEBUG_WIRE(".");
DEBUG_WIRE("%02x", rxbuf[i]);
}
}
}
DEBUG_WIRE("\n");
return res;
}

View File

@ -1,404 +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>
* 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 "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 "adiv5.h"
int remote_init(void)
{
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 < 1) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("Remote Start failed, error %s\n",
c ? (char *)&(construct[1]) : "unknown");
return -1;
}
DEBUG_PROBE("Remote is %s\n", &construct[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 < 1) || (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');
}
bool 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 < 1) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("platform_target_set_power failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown");
return false;
}
return true;
}
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 < 1) || (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 < 1) || (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');
}
void remote_max_frequency_set(uint32_t freq)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s;
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_FREQ_SET_STR,
freq);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("Update Firmware to allow to set max SWJ frequency\n");
}
}
uint32_t remote_max_frequency_get(void)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s;
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,"%s",
REMOTE_FREQ_GET_STR);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR))
return FREQ_FIXED;
uint32_t freq[1];
unhexify(freq, (const char*)&construct[1], 4);
return freq[0];
}
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 < 1) || (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,
dp->dp_jd_index, addr);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (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, dp->dp_jd_index, RnW, addr, value);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (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->dp->dp_jd_index, ap->apsel, addr);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (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->dp->dp_jd_index, ap->apsel, addr, value);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (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->dp->dp_jd_index, 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->dp->dp_jd_index, 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)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
REMOTE_HL_CHECK_STR);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR) ||
((construct[1] - '0') < REMOTE_HL_VERSION)) {
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;
}
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
REMOTE_JTAG_ADD_DEV_STR,
i,
jtag_dev->dr_prescan,
jtag_dev->dr_postscan,
jtag_dev->ir_len,
jtag_dev->ir_prescan,
jtag_dev->ir_postscan,
jtag_dev->current_ir);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
/* No check for error here. Done in remote_adiv5_dp_defaults!*/
}

View File

@ -1,45 +0,0 @@
/*
* 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 "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(void);
int remote_swdptap_init(ADIv5_DP_t *dp);
int remote_jtagtap_init(jtag_proc_t *jtag_proc);
bool remote_target_get_power(void);
const char *remote_target_voltage(void);
bool remote_target_set_power(bool power);
void remote_srst_set_val(bool assert);
bool remote_srst_get_val(void);
void remote_max_frequency_set(uint32_t freq);
uint32_t remote_max_frequency_get(void);
const char *platform_target_voltage(void);
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp);
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev);
#define __BMP_REMOTE_H_
#endif

View File

@ -1,296 +0,0 @@
/*
* 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/>.
*/
/* Find all known serial connected debuggers */
#include "general.h"
#include <dirent.h>
#include <errno.h>
#include "bmp_hosted.h"
#include "version.h"
void bmp_ident(bmp_info_t *info)
{
if (!info)
return;
DEBUG_INFO("BMP hosted (BMP Only) %s\n", FIRMWARE_VERSION);
DEBUG_INFO("Using:\n %s %s %s\n", info->manufacturer, info->version, info->serial);
}
void libusb_exit_function(bmp_info_t *info) {(void)info;};
#ifdef __APPLE__
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
DEBUG_WARN("Please implement find_debuggers for MACOS!\n");
(void)cl_opts;
(void)info;
return -1;
}
#elif defined(__WIN32__) || defined(__CYGWIN__)
/* This source has been used as an example:
* https://stackoverflow.com/questions/3438366/setupdigetdeviceproperty-usage-example */
#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#include <tchar.h>
#include <stdio.h>
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpropdef.h */
#ifdef DEFINE_DEVPROPKEY
#undef DEFINE_DEVPROPKEY
#endif
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpkey.h */
DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
/* List all USB devices with some additional information.
* Unfortunately, this code is quite ugly. */
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
unsigned i;
DWORD dwSize;
DEVPROPTYPE ulPropertyType;
CONFIGRET status;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
WCHAR busReportedDeviceSesc[4096];
int probes_found = 0;
bool is_printing_probes_info = cl_opts->opt_list_only != 0;
info->bmp_type = BMP_TYPE_BMP;
hDevInfo = SetupDiGetClassDevs (0, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
return -1;
print_probes_info:
for (i = 0; ; i++) {
char serial_number[sizeof info->serial];
DeviceInfoData.cbSize = sizeof (DeviceInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
break;
status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
if (status != CR_SUCCESS)
continue;
if (!sscanf(szDeviceInstanceID, "USB\\VID_1D50&PID_6018\\%s", serial_number))
continue;
if (SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
&ulPropertyType, (BYTE*)busReportedDeviceSesc, sizeof busReportedDeviceSesc, &dwSize, 0))
{
probes_found ++;
if (is_printing_probes_info)
{
DEBUG_WARN("%2d: %s, %ls\n", probes_found,
serial_number, busReportedDeviceSesc);
}
else
{
bool probe_identified = true;
if ((cl_opts->opt_serial && strstr(serial_number, cl_opts->opt_serial)) ||
(cl_opts->opt_position && cl_opts->opt_position == probes_found) ||
/* Special case for the very first probe found. */
(probe_identified = false, probes_found == 1)) {
strncpy(info->serial, serial_number, sizeof info->serial);
strncpy(info->manufacturer, "BMP", sizeof info->manufacturer);
snprintf(info->product, sizeof info->product, "%ls", busReportedDeviceSesc);
/* Don't bother to parse the version string. It is a part of the
* product description string. It seems that at the moment it
* is only being used to print a version string in response
* to the 'monitor version' command, so it doesn't really matter
* if the version string is printed as a part of the product string,
* or as a separate string, the result is pretty much the same. */
info->version[0] = 0;
if (probe_identified)
return 0;
}
}
}
}
if (is_printing_probes_info)
return 1;
if (probes_found == 1)
/* Exactly one probe found. Its information has already been filled
* in the detection loop, so use this probe. */
return 0;
if (probes_found < 1) {
DEBUG_WARN("No BMP probe found\n");
return -1;
}
/* Otherwise, if this line is reached, then more than one probe has been found,
* and no probe was identified as selected by the user.
* Restart the identification loop, this time printing the probe information,
* and then return. */
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, or "
"-s <(partial)serial no.>\n",
probes_found);
probes_found = 0;
is_printing_probes_info = true;
goto print_probes_info;
}
#else
/* Old ID: Black_Sphere_Technologies_Black_Magic_Probe_BFE4D6EC-if00
* Recent: Black_Sphere_Technologies_Black_Magic_Probe_v1.7.1-212-g212292ab_7BAE7AB8-if00
* usb-Black_Sphere_Technologies_Black_Magic_Probe__SWLINK__v1.7.1-155-gf55ad67b-dirty_DECB8811-if00
*/
#define BMP_IDSTRING_BLACKSPHERE "usb-Black_Sphere_Technologies_Black_Magic_Probe"
#define BMP_IDSTRING_BLACKMAGIC "usb-Black_Magic_Debug_Black_Magic_Probe"
#define BMP_IDSTRING_1BITSQUARED "usb-1BitSquared_Black_Magic_Probe"
#define DEVICE_BY_ID "/dev/serial/by-id/"
/*
* Extract type, version and serial from /dev/serial/by_id
* Return 0 on success
*
* Old versions have different strings. Try to cope!
*/
static int scan_linux_id(char *name, char *type, char *version, char *serial)
{
name += strlen(BMP_IDSTRING_BLACKSPHERE) + 1;
while (*name == '_')
name++;
if (!*name) {
DEBUG_WARN("Unexpected end\n");
return -1;
}
char *p = name;
char *delims[4] = {0,0,0,0};
int underscores = 0;
while (*p) {
if (*p == '_') {
while (p[1] == '_')
p++; /* remove multiple underscores */
if (underscores > 2)
return -1;
delims[underscores] = p;
underscores ++;
}
p++;
}
if (underscores == 0) { /* Old BMP native */
int res;
res = sscanf(name, "%8s-if00", serial);
if (res != 1)
return -1;
strcpy(type, "Native");
strcpy(version, "Unknown");
} else if (underscores == 2) {
strncpy(type, name, delims[0] - name - 1);
strncpy(version, delims[0] + 1, delims[1] - delims[0] - 1);
int res = sscanf(delims[1] + 1, "%8s-if00", serial);
if (!res)
return -1;
} else {
int res = sscanf(delims[0] + 1, "%8s-if00", serial);
if (!res)
return -1;
if (name[0] == 'v') {
strcpy(type, "Unknown");
strncpy(version, name, delims[0] - name - 1);
} else {
strncpy(type, name, delims[0] - name);
strcpy(type, "Unknown");
}
}
return 0;
}
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
if (cl_opts->opt_device)
return 1;
info->bmp_type = BMP_TYPE_BMP;
DIR *dir = opendir(DEVICE_BY_ID);
if (!dir) /* No serial device connected!*/
return 0;
int found_bmps = 0;
struct dirent *dp;
int i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
if (scan_linux_id(dp->d_name, type, version, serial)) {
DEBUG_WARN("Unexpected device name found \"%s\"\n",
dp->d_name);
}
if ((cl_opts->opt_serial && strstr(serial, cl_opts->opt_serial)) ||
(cl_opts->opt_position && cl_opts->opt_position == i)) {
/* With serial number given and partial match, we are done!*/
strncpy(info->serial, serial, sizeof(info->serial));
int res = snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
if (res)
DEBUG_WARN("Overflow\n");
strncpy(info->version, version, sizeof(info->version));
found_bmps = 1;
break;
} else {
found_bmps++;
}
}
}
closedir(dir);
if (found_bmps < 1) {
DEBUG_WARN("No BMP probe found\n");
return -1;
} else if ((found_bmps > 1) || cl_opts->opt_list_only) {
DEBUG_WARN("Available Probes:\n");
}
dir = opendir(DEVICE_BY_ID);
i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
if (scan_linux_id(dp->d_name, type, version, serial)) {
DEBUG_WARN("Unexpected device name found \"%s\"\n",
dp->d_name);
} else if ((found_bmps == 1) && (!cl_opts->opt_list_only)) {
strncpy(info->serial, serial, sizeof(info->serial));
found_bmps = 1;
strncpy(info->serial, serial, sizeof(info->serial));
snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
strncpy(info->version, version, sizeof(info->version));
break;
} else if (found_bmps > 0) {
DEBUG_WARN("%2d: %s, Black Magic Debug, Black Magic "
"Probe (%s), %s\n", i, serial, type, version);
}
}
}
closedir(dir);
return (found_bmps == 1 && !cl_opts->opt_list_only) ? 0 : 1;
}
#endif

View File

@ -1,470 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* 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
* 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 "bmp_hosted.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;
typedef enum cmsis_type_s {
CMSIS_TYPE_NONE = 0,
CMSIS_TYPE_HID,
CMSIS_TYPE_BULK
} cmsis_type_t;
/*- Variables ---------------------------------------------------------------*/
static cmsis_type_t type;
static libusb_device_handle *usb_handle = NULL;
static uint8_t in_ep;
static uint8_t out_ep;
static hid_device *handle = NULL;
static uint8_t buffer[1024 + 1];
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 */
int dap_init(bmp_info_t *info)
{
type = (info->in_ep && info->out_ep) ? CMSIS_TYPE_BULK : CMSIS_TYPE_HID;
int size;
if (type == CMSIS_TYPE_HID) {
DEBUG_INFO("Using hid transfer\n");
if (hid_init())
return -1;
size = strlen(info->serial);
wchar_t serial[64] = {0}, *wc = serial;
for (int i = 0; i < size; i++)
*wc++ = info->serial[i];
*wc = 0;
/* Blacklist devices that do not work 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[0]) ? serial : NULL);
if (!handle) {
DEBUG_WARN("hid_open failed\n");
return -1;
}
} else if (type == CMSIS_TYPE_BULK) {
DEBUG_INFO("Using bulk transfer\n");
usb_handle = libusb_open_device_with_vid_pid(info->libusb_ctx, info->vid, info->pid);
if (!usb_handle) {
DEBUG_WARN("WARN: libusb_open_device_with_vid_pid() failed\n");
return -1;
}
if (libusb_claim_interface(usb_handle, info->interface_num) < 0) {
DEBUG_WARN("WARN: libusb_claim_interface() failed\n");
return -1;
}
in_ep = info->in_ep;
out_ep = info->out_ep;
}
dap_disconnect();
size = dap_info(DAP_INFO_FW_VER, buffer, sizeof(buffer));
if (size) {
DEBUG_INFO("Ver %s, ", buffer);
int major = -1, minor = -1, sub = -1;
if (sscanf((const char *)buffer, "%d.%d.%d",
&major, &minor, &sub)) {
if (sub == -1) {
if (minor >= 10) {
minor /= 10;
sub = 0;
}
}
has_swd_sequence = ((major > 1 ) || ((major > 0 ) && (minor > 1)));
}
}
size = dap_info(DAP_INFO_CAPABILITIES, buffer, sizeof(buffer));
dap_caps = buffer[0];
DEBUG_INFO("Cap (0x%2x): %s%s%s", dap_caps,
(dap_caps & 1)? "SWD" : "",
((dap_caps & 3) == 3) ? "/" : "",
(dap_caps & 2)? "JTAG" : "");
if (dap_caps & 4)
DEBUG_INFO(", SWO_UART");
if (dap_caps & 8)
DEBUG_INFO(", SWO_MANCHESTER");
if (dap_caps & 0x10)
DEBUG_INFO(", Atomic Cmds");
if (has_swd_sequence)
DEBUG_INFO(", DAP_SWD_Sequence");
DEBUG_INFO("\n");
return 0;
}
void dap_srst_set_val(bool assert)
{
dap_reset_pin(!assert);
}
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)
{
/* Not used for SWD debugging, so no TARGETID switch needed!*/
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)
{
uint32_t res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
return res;
}
void dap_exit_function(void)
{
if (type == CMSIS_TYPE_HID) {
if (handle) {
dap_disconnect();
hid_close(handle);
}
} else if (type == CMSIS_TYPE_BULK) {
if (usb_handle) {
dap_disconnect();
libusb_close(usb_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 = -1;
memset(buffer, 0xff, report_size + 1);
buffer[0] = 0x00; // Report ID??
memcpy(&buffer[1], data, rsize);
DEBUG_WIRE("cmd : ");
for(int i = 0; (i < 32) && (i < rsize + 1); i++)
DEBUG_WIRE("%02x.", buffer[i]);
DEBUG_WIRE("\n");
if (type == CMSIS_TYPE_HID) {
res = hid_write(handle, buffer, 65);
if (res < 0) {
DEBUG_WARN( "Error: %ls\n", hid_error(handle));
exit(-1);
}
res = hid_read_timeout(handle, buffer, 65, 1000);
if (res < 0) {
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
exit(-1);
} else if (res == 0) {
DEBUG_WARN( "timeout\n");
exit(-1);
}
} else if (type == CMSIS_TYPE_BULK) {
int transferred = 0;
res = libusb_bulk_transfer(usb_handle, out_ep, data, rsize, &transferred, 500);
if (res < 0) {
DEBUG_WARN("OUT error: %d\n", res);
return res;
}
res = libusb_bulk_transfer(usb_handle, in_ep, buffer, report_size, &transferred, 500);
if (res < 0) {
DEBUG_WARN("IN error: %d\n", res);
return res;
}
res = transferred;
}
DEBUG_WIRE("cmd res:");
for(int i = 0; (i < 16) && (i < size + 1); i++)
DEBUG_WIRE("%02x.", buffer[i]);
DEBUG_WIRE("\n");
if (buffer[0] != cmd) {
DEBUG_WARN("cmd %02x not implemented\n", cmd);
buffer[1] = 0xff /*DAP_ERROR*/;
}
if (size)
memcpy(data, &buffer[1], (size < res) ? size : res);
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() - 6) >> (2 - align)) & ~3;
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() - 6) >> (2 - align) & ~3);
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");
}
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)? DO[0] : 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_reset_link(true);
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;
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;
}
#define SWD_SEQUENCE_IN 0x80
#define DAP_SWD_SEQUENCE 0x1d
static bool dap_dp_low_write(ADIv5_DP_t *dp, uint16_t addr, const uint32_t data)
{
DEBUG_PROBE("dap_dp_low_write %08" PRIx32 "\n", data);
(void)dp;
unsigned int paket_request = make_packet_request(ADIV5_LOW_WRITE, addr);
uint8_t buf[32] = {
DAP_SWD_SEQUENCE,
5,
8,
paket_request,
4 + SWD_SEQUENCE_IN, /* one turn-around + read 3 bit ACK */
1, /* one bit turn around to drive SWDIO */
0,
32, /* write 32 bit data */
(data >> 0) & 0xff,
(data >> 8) & 0xff,
(data >> 16) & 0xff,
(data >> 24) & 0xff,
1, /* write parity biT */
__builtin_parity(data)
};
dbg_dap_cmd(buf, sizeof(buf), 14);
if (buf[0])
DEBUG_WARN("dap_dp_low_write failed\n");
uint32_t ack = (buf[1] >> 1) & 7;
return (ack != SWDP_ACK_OK);
}
int dap_swdptap_init(ADIv5_DP_t *dp)
{
if (!(dap_caps & DAP_CAP_SWD))
return 1;
mode = DAP_CAP_SWD;
dap_transfer_configure(2, 128, 128);
dap_swd_configure(0);
dap_connect(false);
dap_led(0, 1);
dap_reset_link(false);
if ((has_swd_sequence) && dap_sequence_test()) {
/* DAP_SWD_SEQUENCE does not do auto turnaround, use own!*/
dp->dp_low_write = dap_dp_low_write;
} else {
dp->dp_low_write = NULL;
}
dp->seq_out = dap_swdptap_seq_out;
dp->dp_read = dap_dp_read_reg;
/* For error() use the TARGETID switching firmware_swdp_error */
dp->low_access = dap_dp_low_access;
dp->abort = dap_dp_abort;
return 0;
}

View File

@ -1,56 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* 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
* 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);
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_swdptap_init(ADIv5_DP_t *dp);
int dap_jtag_dp_init(ADIv5_DP_t *dp);
uint32_t dap_swj_clock(uint32_t clock);
void dap_swd_configure(uint8_t cfg);
void dap_srst_set_val(bool assert);
#else
int dap_init(bmp_info_t *info)
{
DEBUG_WARN("FATAL: Missing hidapi-libusb\n");
(void)info;
return -1;
}
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
uint32_t dap_swj_clock(uint32_t clock) {return 0;}
void dap_exit_function(void) {};
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) {return -1;}
int dap_swdptap_init(ADIv5_DP_t *dp) {return -1;}
int dap_jtag_dp_init(ADIv5_DP_t *dp) {return -1;}
void dap_swd_configure(uint8_t cfg) {};
void dap_srst_set_val(bool assert) {};
# pragma GCC diagnostic pop
#endif
#endif

View File

@ -1,849 +0,0 @@
/*
* 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-21 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
*/
/*- Includes ----------------------------------------------------------------*/
#include <general.h>
#include "exception.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,
ID_DAP_SWD_SEQUENCE = 0x1D,
};
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[65];
buf[0] = ID_DAP_DISCONNECT;
dbg_dap_cmd(buf, sizeof(buf), 1);
}
static uint32_t swj_clock;
/* Set/Get JTAG/SWD clock frequency
*
* With clock == 0, return last set value.
*/
uint32_t dap_swj_clock(uint32_t clock)
{
if (clock == 0)
return swj_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);
if (buf[0])
DEBUG_WARN("dap_swj_clock failed\n");
else
swj_clock = clock;
return swj_clock;
}
//-----------------------------------------------------------------------------
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; // Wait
buf[5] = 0; // Wait
buf[6] = 0; // Wait
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)
{
uint8_t cmd_copy[len];
memcpy(cmd_copy, buf, len);
do {
memcpy(buf, cmd_copy, len);
dbg_dap_cmd(buf, size, len);
if (buf[1] < DAP_TRANSFER_WAIT)
break;
} while (buf[1] == DAP_TRANSFER_WAIT);
if(buf[1] == SWDP_ACK_FAULT) {
*dp_fault = 1;
return 0;
}
if(buf[1] != SWDP_ACK_OK)
raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK");
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;
dap_index = dp->dp_jd_index;
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;
dap_index = dp->dp_jd_index;
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;
uint8_t cmd_copy[8];
memcpy(cmd_copy, buf, 8);
do {
memcpy(buf, cmd_copy, 8);
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_WARN("dap_write_reg %02x data %08x:fault\n", reg, data);
dp->fault = 1;
}
if (buf[1] == DAP_TRANSFER_ERROR) {
DEBUG_WARN("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;
dap_index = ap->dp->dp_jd_index;
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);
unsigned int transferred = buf[0] + (buf[1] << 8);
if (buf[2] >= DAP_TRANSFER_FAULT) {
DEBUG_WARN("dap_read_block @ %08" PRIx32 " fault -> line reset\n", src);
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);
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;
dap_index = ap->dp->dp_jd_index;
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;
dap_index = ap->dp->dp_jd_index;
*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 addr %x\n", addr);
uint8_t buf[63], *p = buf;
buf[0] = ID_DAP_TRANSFER;
uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index;
*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);
if ((buf[0] != 2) || (buf[1] != 1)) {
DEBUG_WARN("dap_ap_read error %x\n", buf[1]);
}
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;
dap_index = ap->dp->dp_jd_index;
*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);
if ((buf[0] != 2) || (buf[1] != 1)) {
DEBUG_WARN("dap_ap_write error %x\n", buf[1]);
}
}
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;
*p++ = SWD_DP_R_RDBUFF | DAP_TRANSFER_RnW;
buf[2] = 5;
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)
{
DEBUG_PROBE("dap_jtagtap_tdi_tdo_seq %s %d ticks\n",
(final_tms) ? "final" : "", ticks);
uint8_t buf[64];
const uint8_t *din = DI;
uint8_t *dout = DO;
if (!TMS) {
int last_byte = last_byte = (ticks - 1) >> 3;
int last_bit = (ticks - 1) & 7;
if (final_tms)
ticks --;
while (ticks) {
int transfers = ticks;
if (transfers > 64)
transfers = 64;
uint8_t *p = buf;
*p++ = ID_DAP_JTAG_SEQUENCE;
*p++ = 1;
*p++ = ((transfers == 64) ? 0 : transfers) |
((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
int n_di_bytes = (transfers + 7) >> 3;
if (din) {
p = memcpy(p, din, n_di_bytes);
din += 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 (dout) {
memcpy(dout, &buf[1], (transfers + 7) >> 3);
dout += (transfers + 7) >> 3;
}
ticks -= transfers;
}
if (final_tms) {
uint8_t *p = buf;
*p++ = ID_DAP_JTAG_SEQUENCE;
*p++ = 1;
*p++ = 1 | ((dout) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
if (din) {
*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 (dout) {
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 >> 3] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
if (DI)
*p++ = (DI[i >> 3] & (1 << (i & 7))) ? 1 : 0;
else
*p++ = 1;
}
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 >> 3] |= (1 << (i & 7));
else
DO[i >> 3] &= ~(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;
}
void dap_swdptap_seq_out(uint32_t MS, int ticks)
{
uint8_t buf[64] = {
ID_DAP_SWJ_SEQUENCE,
ticks,
(MS >> 0) & 0xff,
(MS >> 8) & 0xff,
(MS >> 16) & 0xff,
(MS >> 24) & 0xff
};
dbg_dap_cmd(buf, 64, 2 + ((ticks +7) >> 3));
if (buf[0])
DEBUG_WARN("dap_swdptap_seq_out error\n");
}
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t buf[] = {
ID_DAP_SWJ_SEQUENCE,
ticks + 1,
(MS >> 0) & 0xff,
(MS >> 8) & 0xff,
(MS >> 16) & 0xff,
(MS >> 24) & 0xff,
__builtin_parity(MS) & 1
};
dbg_dap_cmd(buf, 1, sizeof(buf));
if (buf[0])
DEBUG_WARN("dap_swdptap_seq_out error\n");
}
bool dap_sequence_test(void)
{
uint8_t buf[4] = {
ID_DAP_SWD_SEQUENCE,
0x1,
0x81, /* Read one bit */
0 /* one idle cycle */
};
dbg_dap_cmd(buf, sizeof(buf), 3);
return (buf[0] == DAP_OK);
}
#define SWD_SEQUENCE_IN 0x80
uint32_t dap_swdptap_seq_in(int ticks)
{
uint8_t buf[5] = {
ID_DAP_SWD_SEQUENCE,
1,
ticks + SWD_SEQUENCE_IN
};
dbg_dap_cmd(buf, 2 + ((ticks + 7) >> 3), 3);
uint32_t res = 0;
int len = (ticks + 7) >> 3;
while (len--) {
res <<= 8;
res += buf[len + 1];
}
return res;
}
bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
(void)ticks;
uint8_t buf[8] = {
ID_DAP_SWD_SEQUENCE,
1,
33 + SWD_SEQUENCE_IN,
};
dbg_dap_cmd(buf, 7, 4);
uint32_t res = 0;
int len = 4;
while (len--) {
res <<= 8;
res += buf[len + 1];
}
*ret = res;
unsigned int parity = __builtin_parity(res) & 1;
parity ^= (buf[5] % 1);
DEBUG_WARN("Res %08" PRIx32" %d\n", *ret, parity & 1);
return (!(parity & 1));
}

View File

@ -1,97 +0,0 @@
/*
* 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_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_srst_set_val(bool assert);
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);
void dap_swdptap_seq_out(uint32_t MS, int ticks);
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks);
bool dap_sequence_test(void);
#endif // _DAP_H_

View File

@ -1,661 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Copyright (C) 2018 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
* 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/>.
*/
#include "general.h"
#include "gdb_if.h"
#include "target.h"
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#include "ftdi_bmp.h"
#include <ftdi.h>
struct ftdi_context *ftdic;
#define BUF_SIZE 4096
static uint8_t outbuf[BUF_SIZE];
static uint16_t bufptr = 0;
cable_desc_t *active_cable;
data_desc_t active_state;
cable_desc_t cable_desc[] = {
{
/* Direct connection from FTDI to Jtag/Swd.
Pin 6 direct connected to RST.*/
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
// No explicit reset
.bb_swdio_in_port_cmd = GET_BITS_LOW,
.bb_swdio_in_pin = MPSSE_CS,
.description = "UM232H",
.name = "um232h"
},
{
/* Direct connection from FTDI to Jtag/Swd.
Pin 6 direct connected to RST.*/
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
.init.data_low = PIN6, /* PULL nRST high*/
.bb_swdio_in_port_cmd = GET_BITS_LOW,
.bb_swdio_in_pin = MPSSE_CS,
.assert_srst.data_low = ~PIN6,
.assert_srst.ddr_low = PIN6,
.deassert_srst.data_low = PIN6,
.deassert_srst.ddr_low = ~PIN6,
.description = "FLOSS-JTAG",
.name = "flossjtag"
},
{
/* MPSSE_SK (DB0) ----------- SWDCK/JTCK
* MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
* MPSSE-DI (DB2) ----------- SWDIO/JTMS
* DO is tristated with SWD read, so
* resistor is not necessary, but protects
* from contentions in case of errors.
* JTAG not possible
* PIN6 (DB6) ----------- NRST */
.vendor = 0x0403,
.product = 0x6010,/*FT2232H*/
.interface = INTERFACE_B,
.init.data_low = PIN4, /* Pull up pin 4 */
.init.ddr_low = PIN4, /* Pull up pin 4 */
.mpsse_swd_read.set_data_low = MPSSE_DO,
.mpsse_swd_write.set_data_low = MPSSE_DO,
.assert_srst.data_low = ~PIN6,
.assert_srst.ddr_low = PIN6,
.deassert_srst.data_low = PIN6,
.deassert_srst.ddr_low = ~PIN6,
.target_voltage_cmd = GET_BITS_LOW,
.target_voltage_pin = PIN4, /* Always read as target voltage present.*/
.description = "USBMATE",
.name = "usbmate"
},
{
/* MPSSE_SK (DB0) ----------- SWDCK/JTCK
* MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
* MPSSE-DI (DB2) ----------- SWDIO/JTMS
* DO is tristated with SWD read, so
* resistor is not necessary, but protects
* from contentions in case of errors.
* JTAG not possible.*/
.vendor = 0x0403,
.product = 0x6014,/*FT232H*/
.interface = INTERFACE_A,
.mpsse_swd_read.set_data_low = MPSSE_DO,
.mpsse_swd_write.set_data_low = MPSSE_DO,
.name = "ft232h_resistor_swd"
},
{
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
* SWD not possible.
* PIN4 low enables buffers
* PIN5 Low indicates VRef applied
* PIN6 reads back SRST
* CBUS PIN1 Sets SRST
* CBUS PIN2 low drives SRST
*/
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
.init.ddr_low = PIN4,
.init.data_high = PIN4 | PIN3 | PIN2,
.init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.assert_srst.data_high = ~PIN3,
.deassert_srst.data_high = PIN3,
.srst_get_port_cmd = GET_BITS_LOW,
.srst_get_pin = PIN6,
.description = "FTDIJTAG",
.name = "ftdijtag"
},
{
/* UART/SWO on Interface A
* JTAG and control on INTERFACE_B
* Bit 5 high selects SWD-WRITE (TMS routed to MPSSE_DI)
* Bit 6 high selects JTAG vs SWD (TMS routed to MPSSE_CS)
* BCBUS 1 (Output) N_SRST
* BCBUS 2 (Input/ Internal Pull Up) V_ISO available
*
* For bitbanged SWD, set Bit 5 low and select SWD read with
* Bit 6 low. Read Connector TMS as MPSSE_DI.
*
* TDO is routed to Interface 0 RXD as SWO or with Uart
* Connector pin 10 pulled to ground will connect Interface 0 RXD
* to UART connector RXD
*/
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_B,
.init.data_low = PIN6 | PIN5,
.init.ddr_low = PIN6 | PIN5,
.init.data_high = PIN1 | PIN2,
.assert_srst.data_high = ~PIN1,
.assert_srst.ddr_high = PIN1,
.deassert_srst.data_high = PIN1,
.deassert_srst.ddr_high = ~PIN1,
.mpsse_swd_read.clr_data_low = PIN5 | PIN6,
.mpsse_swd_write.set_data_low = PIN5,
.mpsse_swd_write.clr_data_low = PIN6,
.jtag.set_data_low = PIN6,
.target_voltage_cmd = GET_BITS_HIGH,
.target_voltage_pin = ~PIN2,
.name = "ftdiswd",
.description = "FTDISWD"
},
{
.vendor = 0x15b1,
.product = 0x0003,
.interface = INTERFACE_A,
.init.ddr_low = PIN5,
.name = "olimex"
},
{
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
* => SWD not possible.
* DBUS PIN4 / JTAGOE low enables buffers
* DBUS PIN5 / TRST high drives nTRST low OC
* DBUS PIN6 / RST high drives nSRST low OC
* CBUS PIN0 reads back SRST
*/
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
/* Drive low to activate JTAGOE and deassert TRST/RST.*/
.init.data_low = 0,
.init.ddr_low = PIN6 | PIN5 | PIN4,
.init.ddr_high = PIN2, /* ONE LED */
.assert_srst.data_low = PIN6,
.deassert_srst.data_low = ~PIN6,
.srst_get_port_cmd = GET_BITS_HIGH,
.srst_get_pin = PIN0,
.name = "turtelizer",
.description = "Turtelizer JTAG/RS232 Adapter"
},
{
/* https://reference.digilentinc.com/jtag_hs1/jtag_hs1
* No schmeatics available.
* Buffered from FTDI to Jtag/Swd announced
* Independant switch for TMS not known
* => SWD not possible. */
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.name = "jtaghs1"
},
{
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
.init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
.init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bb_swdio_in_port_cmd = GET_BITS_LOW,
.bb_swdio_in_pin = MPSSE_CS,
.name = "ftdi"
},
{
/* Product name not unique! Assume SWD not possible.*/
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
.init.data_low = PIN7,
.init.ddr_low = PIN7,
.init.data_high = PIN5,
.init.ddr_high = PIN5 | PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.name = "digilent"
},
{
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
.init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
.init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
.bb_swdio_in_port_cmd = GET_BITS_LOW,
.bb_swdio_in_pin = MPSSE_CS,
.name = "ft232h"
},
{
/* Direct connection from FTDI to Jtag/Swd assumed.*/
.vendor = 0x0403,
.product = 0x6011,
.interface = INTERFACE_A,
.bb_swdio_in_port_cmd = GET_BITS_LOW,
.bb_swdio_in_pin = MPSSE_CS,
.name = "ft4232h"
},
{
/* http://www.olimex.com/dev/pdf/ARM-USB-OCD.pdf.
* DBUS 4 global enables JTAG Buffer.
* => TCK and TMS not independant switchable!
* => SWD not possible. */
.vendor = 0x15ba,
.product = 0x002b,
.interface = INTERFACE_A,
.init.ddr_low = PIN4,
.init.data_high = PIN3 | PIN1 | PIN0,
.init.ddr_high = PIN4 | PIN3 | PIN1 | PIN0,
.name = "arm-usb-ocd-h"
},
{
}
};
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
int err;
cable_desc_t *cable = &cable_desc[0];
for(; cable->name; cable++) {
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)) == 0)
break;
}
if (!cable->name ) {
DEBUG_WARN( "No cable matching found for %s\n", cl_opts->opt_cable);
return -1;
}
active_cable = cable;
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
/* If swd_(read|write) is not given for the selected cable and
the 'e' command line argument is give, assume resistor SWD
connection.*/
if (cl_opts->external_resistor_swd &&
(active_cable->mpsse_swd_read.set_data_low == 0) &&
(active_cable->mpsse_swd_read.clr_data_low == 0) &&
(active_cable->mpsse_swd_read.set_data_high == 0) &&
(active_cable->mpsse_swd_read.clr_data_high == 0) &&
(active_cable->mpsse_swd_write.set_data_low == 0) &&
(active_cable->mpsse_swd_write.clr_data_low == 0) &&
(active_cable->mpsse_swd_write.set_data_high == 0) &&
(active_cable->mpsse_swd_write.clr_data_high == 0)) {
DEBUG_INFO("Using external resistor SWD\n");
active_cable->mpsse_swd_read.set_data_low = MPSSE_DO;
active_cable->mpsse_swd_write.set_data_low = MPSSE_DO;
} else if (!libftdi_swd_possible(NULL, NULL) &&
!cl_opts->opt_usejtag) {
DEBUG_WARN("SWD with cable not possible, trying JTAG\n");
cl_opts->opt_usejtag = true;
}
if(ftdic) {
ftdi_usb_close(ftdic);
ftdi_free(ftdic);
ftdic = NULL;
}
if((ftdic = ftdi_new()) == NULL) {
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) {
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) {
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) {
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) {
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) {
DEBUG_WARN( "ftdi_write_data_set_chunksize: %d: %s\n",
err, ftdi_get_error_string(ftdic));
goto error_2;
}
assert(ftdic != NULL);
#ifdef _Ftdi_Pragma
err = ftdi_tcioflush(ftdic);
#else
err = ftdi_usb_purge_buffers(ftdic);
#endif
if (err != 0) {
DEBUG_WARN("ftdi_tcioflush(ftdi_usb_purge_buffer): %d: %s\n",
err, ftdi_get_error_string(ftdic));
goto error_2;
}
/* Reset MPSSE controller. */
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
if (err != 0) {
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic));
goto error_2;
}
/* Enable MPSSE controller. Pin directions are set later.*/
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
if (err != 0) {
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic));
goto error_2;
}
uint8_t ftdi_init[16];
/* Test for pending garbage.*/
int garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
if (garbage > 0) {
DEBUG_WARN("FTDI init garbage at start:");
for (int i = 0; i < garbage; i++)
DEBUG_WARN(" %02x", ftdi_init[i]);
DEBUG_WARN("\n");
}
int index = 0;
ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
switch(ftdic->type) {
case TYPE_2232H:
case TYPE_4232H:
case TYPE_232H:
ftdi_init[index++] = DIS_DIV_5;
break;
case TYPE_2232C:
break;
default:
DEBUG_WARN("FTDI Chip has no MPSSE\n");
goto error_2;
}
ftdi_init[index++]= TCK_DIVISOR;
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
ftdi_init[index++]= 1;
ftdi_init[index++]= 0;
ftdi_init[index++]= SET_BITS_LOW;
ftdi_init[index++]= active_state.data_low;
ftdi_init[index++]= active_state.ddr_low;
ftdi_init[index++]= SET_BITS_HIGH;
ftdi_init[index++]= active_state.data_high;
ftdi_init[index++]= active_state.ddr_high;
libftdi_buffer_write(ftdi_init, index);
libftdi_buffer_flush();
garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
if (garbage > 0) {
DEBUG_WARN("FTDI init garbage at end:");
for (int i = 0; i < garbage; i++)
DEBUG_WARN(" %02x", ftdi_init[i]);
DEBUG_WARN("\n");
} return 0;
error_2:
ftdi_usb_close(ftdic);
error_1:
ftdi_free(ftdic);
return -1;
}
static void libftdi_set_data(data_desc_t* data)
{
uint8_t cmd[6];
int index = 0;
if ((data->data_low) || (data->ddr_low)) {
if (data->data_low > 0)
active_state.data_low |= (data->data_low & 0xff);
else if (data->data_low < 0)
active_state.data_low &= (data->data_low & 0xff);
if (data->ddr_low > 0)
active_state.ddr_low |= (data->ddr_low & 0xff);
else if (data->ddr_low < 0)
active_state.ddr_low &= (data->ddr_low & 0xff);
cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_state.data_low;
cmd[index++] = active_state.ddr_low;
}
if ((data->data_high) || (data->ddr_high)) {
if (data->data_high > 0)
active_state.data_high |= (data->data_high & 0xff);
else if (data->data_high < 0)
active_state.data_high &= (data->data_high & 0xff);
if (data->ddr_high > 0)
active_state.ddr_high |= (data->ddr_high & 0xff);
else if (data->ddr_high < 0)
active_state.ddr_high &= (data->ddr_high & 0xff);
cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_state.data_high;
cmd[index++] = active_state.ddr_high;
}
if (index) {
libftdi_buffer_write(cmd, index);
libftdi_buffer_flush();
}
}
void libftdi_srst_set_val(bool assert)
{
if (assert)
libftdi_set_data(&active_cable->assert_srst);
else
libftdi_set_data(&active_cable->deassert_srst);
}
bool libftdi_srst_get_val(void)
{
uint8_t cmd[1] = {0};
uint8_t pin = 0;
if (active_cable->srst_get_port_cmd && active_cable->srst_get_pin) {
cmd[0]= active_cable->srst_get_port_cmd;
pin = active_cable->srst_get_pin;
} else if (active_cable->assert_srst.data_low &&
active_cable->assert_srst.ddr_low) {
cmd[0]= GET_BITS_LOW;
pin = active_cable->assert_srst.data_low;
} else if (active_cable->assert_srst.data_high &&
active_cable->assert_srst.ddr_high) {
cmd[0]= GET_BITS_HIGH;
pin = active_cable->assert_srst.data_high;
}else {
return false;
}
libftdi_buffer_write(cmd, 1);
uint8_t data[1];
libftdi_buffer_read(data, 1);
bool res = false;
if (((pin < 0x7f) || (pin == PIN7)))
res = data[0] & pin;
else
res = !(data[0] & ~pin);
return res;
}
void libftdi_buffer_flush(void)
{
if (!bufptr)
return;
DEBUG_WIRE("Flush %d\n", bufptr);
#if defined(USE_USB_VERSION_BIT)
static struct ftdi_transfer_control *tc_write = NULL;
if (tc_write)
ftdi_transfer_data_done(tc_write);
tc_write = ftdi_write_data_submit(ftdic, outbuf, bufptr);
#else
assert(ftdi_write_data(ftdic, outbuf, bufptr) == bufptr);
DEBUG_WIRE("FT2232 libftdi_buffer flush: %d bytes\n", bufptr);
#endif
bufptr = 0;
}
int libftdi_buffer_write(const uint8_t *data, int size)
{
if((bufptr + size) / BUF_SIZE > 0) libftdi_buffer_flush();
DEBUG_WIRE("Write %d bytes:", size);
for (int i = 0; i < size; i++) {
DEBUG_WIRE(" %02x", data[i]);
if (i && ((i & 0xf) == 0xf))
DEBUG_WIRE("\n\t");
}
DEBUG_WIRE("\n");
memcpy(outbuf + bufptr, data, size);
bufptr += size;
return size;
}
int libftdi_buffer_read(uint8_t *data, int size)
{
#if defined(USE_USB_VERSION_BIT)
struct ftdi_transfer_control *tc;
outbuf[bufptr++] = SEND_IMMEDIATE;
libftdi_buffer_flush();
tc = ftdi_read_data_submit(ftdic, data, size);
ftdi_transfer_data_done(tc);
#else
int index = 0;
const uint8_t cmd[1] = {SEND_IMMEDIATE};
libftdi_buffer_write(cmd, 1);
libftdi_buffer_flush();
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
#endif
DEBUG_WIRE("Read %d bytes:", size);
for (int i = 0; i < size; i++) {
DEBUG_WIRE(" %02x", data[i]);
if (i && ((i & 0xf) == 0xf))
DEBUG_WIRE("\n\t");
}
DEBUG_WIRE("\n");
return size;
}
void libftdi_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;
DEBUG_WIRE("libftdi_jtagtap_tdi_tdo_seq %s ticks: %d\n",
(DI && DO) ? "read/write" : ((DI) ? "write" : "read"), ticks);
if(final_tms) ticks--;
rticks = ticks & 7;
ticks >>= 3;
uint8_t data[8];
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;
libftdi_buffer_write(data, 3);
if (DI)
libftdi_buffer_write(DI, ticks);
}
int index = 0;
if(rticks) {
rsize++;
data[index++] = cmd | MPSSE_BITMODE;
data[index++] = rticks - 1;
if (DI)
data[index++] = DI[ticks];
}
if(final_tms) {
rsize++;
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] & (1 << rticks)) ? 0x81 : 0x01;
}
if (index)
libftdi_buffer_write(data, index);
if (DO) {
int index = 0;
uint8_t *tmp = alloca(rsize);
libftdi_buffer_read(tmp, rsize);
if(final_tms) rsize--;
while(rsize--) {
*DO++ = tmp[index++];
}
if (rticks == 0)
*DO++ = 0;
if(final_tms) {
rticks++;
*(--DO) >>= 1;
*DO |= tmp[index] & 0x80;
} else DO--;
if(rticks) {
*DO >>= (8-rticks);
}
}
}
const char *libftdi_target_voltage(void)
{
uint8_t pin = active_cable->target_voltage_pin;
if (active_cable->target_voltage_cmd && pin) {
libftdi_buffer_write(&active_cable->target_voltage_cmd, 1);
uint8_t data[1];
libftdi_buffer_read(data, 1);
bool res = false;
if (((pin < 0x7f) || (pin == PIN7)))
res = data[0] & pin;
else
res = !(data[0] & ~pin);
if (res)
return "Present";
else
return "Absent";
}
return NULL;
}
static uint16_t divisor;
void libftdi_max_frequency_set(uint32_t freq)
{
uint32_t clock;
if (ftdic->type == TYPE_2232C)
clock = 12 * 1000 * 1000;
else
/* Undivided clock set during startup*/
clock = 60 * 1000 * 1000;
uint32_t div = (clock + 2 * freq - 1)/ freq;
if ((div < 4) && (ftdic->type = TYPE_2232C))
div = 4; /* Avoid bad unsymetrict FT2232C clock at 6 MHz*/
divisor = div / 2 - 1;
uint8_t buf[3];
buf[0] = TCK_DIVISOR;
buf[1] = divisor & 0xff;
buf[2] = (divisor >> 8) & 0xff;
libftdi_buffer_write(buf, 3);
}
uint32_t libftdi_max_frequency_get(void)
{
uint32_t clock;
if (ftdic->type == TYPE_2232C)
clock = 12 * 1000 * 1000;
else
/* Undivided clock set during startup*/
clock = 60 * 1000 * 1000;
return clock/ ( 2 *(divisor + 1));
}

View File

@ -1,155 +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) 2018 Uwe Bonnes (non@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/>.
*/
#ifndef __FTDI_BMP_H
#define __FTDI_BMP_H
#include "cl_utils.h"
#include "jtagtap.h"
#include "bmp_hosted.h"
typedef struct data_desc_s {
int16_t data_low;
int16_t ddr_low;
int16_t data_high;
int16_t ddr_high;
}data_desc_t;
typedef struct pin_settings_s {
uint8_t set_data_low;
uint8_t clr_data_low;
uint8_t set_data_high;
uint8_t clr_data_high;
}pin_settings_t;
typedef struct cable_desc_s {
int vendor;
int product;
int interface;
/* Initial (C|D)(Bus|Ddr) values for additional pins.
* MPSSE_CS|DI|DO|SK are initialized accordig to mode.*/
data_desc_t init;
/* MPSSE command to read TMS/SWDIO in bitbanging SWD.
* In many cases this is the TMS port, so then use "GET_PIN_LOW".*/
uint8_t bb_swdio_in_port_cmd;
/* bus bit to read TMS/SWDIO in bitbanging SWD.
* In many cases this is the TMS port, so then use "MPSSE_CS".*/
uint8_t bb_swdio_in_pin;
/* Bus data to allow bitbanging switched SWD read.
* TMS is routed to bb_swdio_in_port/pin.*/
pin_settings_t bb_swd_read;
/* Bus data to allow bitbanging switched SWD write.
* TMS is routed to MPSSE_CS.*/
pin_settings_t bb_swd_write;
/* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST.
* E.g. with CBUS Pin 1 low,
* give data_high = ~PIN1, ddr_high = PIN1 */
data_desc_t assert_srst;
/* Bus_data, dbus_ddr, cbus_data, cbus_ddr value to release SRST.
* E.g. with CBUS Pin 1 floating with internal pull up,
* give data_high = PIN1, ddr_high = ~PIN1 */
data_desc_t deassert_srst;
/* Command to read back SRST. If 0, port from assert_srst is used*/
uint8_t srst_get_port_cmd;
/* PIN to read back as SRST. if 0 port from assert_srst is ised.
* Use PINX if active high, use Complement (~PINX) if active low*/
uint8_t srst_get_pin;
/* Bbus data for pure MPSSE SWD read.
* Use together with swd_write if by some bits on DBUS,
* SWDIO can be routed to TDI and TDO.
* If both mpsse_swd_read|write and
* bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
* are provided, pure MPSSE SWD is choosen.
* If neither a complete set of swd_read|write or
* bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
* are provided, SWD can not be done.
* swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO
* indicated resistor SWD and inhibits Jtag.*/
pin_settings_t mpsse_swd_read;
/* dbus data for pure MPSSE SWD write.*/
pin_settings_t mpsse_swd_write;
/* dbus data for jtag.*/
pin_settings_t jtag;
/* Command to read port to check target voltage.*/
uint8_t target_voltage_cmd;
/* Pin to check target voltage.*/
uint8_t target_voltage_pin;
/* USB readable description of the device.*/
char *description;
/* Command line argument to -c option to select this device.*/
char * name;
}cable_desc_t;
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info) {return -1;};
int libftdi_swdptap_init(ADIv5_DP_t *dp) {return -1;};
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) {return 0;};
void libftdi_buffer_flush(void) {};
int libftdi_buffer_write(const uint8_t *data, int size) {return size;};
int libftdi_buffer_read(uint8_t *data, int size) {return size;};
const char *libftdi_target_voltage(void) {return "ERROR";};
void libftdi_jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) {};
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd) {return false;};
void libftdi_max_frequency_set(uint32_t freq) {};
uint32_t libftdi_max_frequency_get(void) {return 0;};
void libftdi_srst_set_val(bool assert){};
bool libftdi_srst_get_val(void) { return false;};
# pragma GCC diagnostic pop
#else
#include <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 libftdi_swdptap_init(ADIv5_DP_t *dp);
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);
void libftdi_jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
void libftdi_max_frequency_set(uint32_t freq);
uint32_t libftdi_max_frequency_get(void);
void libftdi_srst_set_val(bool assert);
bool libftdi_srst_get_val(void);
#endif
#define MPSSE_SK 1
#define PIN0 1
#define MPSSE_DO 2
#define PIN1 2
#define MPSSE_DI 4
#define PIN2 4
#define MPSSE_CS 8
#define PIN3 8
#define PIN4 0x10
#define PIN5 0x20
#define PIN6 0x40
#define PIN7 0x80
#endif

View File

@ -1,271 +0,0 @@
/*
* 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
#define USB_VID_SEGGER_1020 0x1020
static uint32_t emu_caps;
static uint32_t emu_speed_kHz;
static uint16_t emu_min_divisor;
static uint16_t emu_current_divisor;
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));
emu_caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
DEBUG_INFO("Caps %" PRIx32 "\n", emu_caps);
if (emu_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_SPEEDS};
uint8_t res[6];
send_recv(info->usb_link, cmd, 1, res, sizeof(res));
emu_speed_kHz = (res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24)) /
1000;
emu_min_divisor = res[4] | (res[5] << 8);
DEBUG_INFO("Emulator speed %d kHz, Mindiv %d%s\n", emu_speed_kHz,
emu_min_divisor,
(emu_caps & JLINK_CAP_GET_SPEEDS) ? "" : ", fixed");
}
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_INFO(", %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_caps(info);
jlink_print_speed(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) &&
(desc.idProduct != USB_VID_SEGGER_1020))
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]);
}
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
{
if (!(emu_caps & JLINK_CAP_GET_SPEEDS))
return;
if (!info->is_jtag)
return;
uint16_t freq_kHz = freq /1000;
uint16_t divisor = (emu_speed_kHz + freq_kHz - 1) / freq_kHz;
if (divisor < emu_min_divisor)
divisor = emu_min_divisor;
emu_current_divisor = divisor;
uint16_t speed_kHz = emu_speed_kHz / divisor;
uint8_t cmd[3] = {CMD_SET_SPEED, speed_kHz & 0xff, speed_kHz >> 8};
DEBUG_WARN("Set Speed %d\n", speed_kHz);
send_recv(info->usb_link, cmd, 3, NULL, 0);
}
uint32_t jlink_max_frequency_get(bmp_info_t *info)
{
if ((emu_caps & JLINK_CAP_GET_SPEEDS) && (info->is_jtag))
return (emu_speed_kHz * 1000L)/ emu_current_divisor;
return FREQ_FIXED;
}

View File

@ -1,108 +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(__JLINK_H_)
#define __JLINK_H_
#include "bmp_hosted.h"
#include "jtagtap.h"
/** @cond PRIVATE */
#define CMD_GET_VERSION 0x01
#define CMD_SET_SPEED 0x05
#define CMD_GET_HW_STATUS 0x07
#define CMD_GET_SPEEDS 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_SPEEDS (1 << 9)
#define JLINK_CAP_GET_HW_VERSION (1 << 1)
#define JLINK_IF_JTAG 1
#define JLINK_IF_SWD 2
#define SELECT_IF_JTAG 0
#define SELECT_IF_SWD 1
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int jlink_init(bmp_info_t *info) {return -1;};
int jlink_swdp_scan(bmp_info_t *info) {return 0;};
int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc) {return 0;};
const char *jlink_target_voltage(bmp_info_t *info) {return "ERROR";};
void jlink_srst_set_val(bmp_info_t *info, bool assert) {};
bool jlink_srst_get_val(bmp_info_t *info) {return true;};
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
uint32_t jlink_max_frequency_get(bmp_info_t *info) {return 0;};
# pragma GCC diagnostic pop
#else
/** Device capabilities. (from openocd*/
enum jaylink_device_capability {
/** Device supports retrieval of the hardware version. */
JAYLINK_DEV_CAP_GET_HW_VERSION = 1,
/** Device supports adaptive clocking. */
JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING = 3,
/** Device supports reading configuration data. */
JAYLINK_DEV_CAP_READ_CONFIG = 4,
/** Device supports writing configuration data. */
JAYLINK_DEV_CAP_WRITE_CONFIG = 5,
/** Device supports retrieval of target interface speeds. */
JAYLINK_DEV_CAP_GET_SPEEDS = 9,
/** Device supports retrieval of free memory size. */
JAYLINK_DEV_CAP_GET_FREE_MEMORY = 11,
/** Device supports retrieval of hardware information. */
JAYLINK_DEV_CAP_GET_HW_INFO = 12,
/** Device supports the setting of the target power supply. */
JAYLINK_DEV_CAP_SET_TARGET_POWER = 13,
/** Device supports target interface selection. */
JAYLINK_DEV_CAP_SELECT_TIF = 17,
/** Device supports retrieval of counter values. */
JAYLINK_DEV_CAP_GET_COUNTERS = 19,
/** Device supports capturing of SWO trace data. */
JAYLINK_DEV_CAP_SWO = 23,
/** Device supports file I/O operations. */
JAYLINK_DEV_CAP_FILE_IO = 26,
/** Device supports registration of connections. */
JAYLINK_DEV_CAP_REGISTER = 27,
/** Device supports retrieval of extended capabilities. */
JAYLINK_DEV_CAP_GET_EXT_CAPS = 31,
/** Device supports EMUCOM. */
JAYLINK_DEV_CAP_EMUCOM = 33,
/** Device supports ethernet connectivity. */
JAYLINK_DEV_CAP_ETHERNET = 38
};
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);
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
uint32_t jlink_max_frequency_get(bmp_info_t *info);
#endif
#endif

View File

@ -1,327 +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 - 2021 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[19];
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 jlink_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);
/* SWD speed is fixed. Do not set it here*/
return 0;
}
int jlink_swdp_scan(bmp_info_t *info)
{
jlink_swdptap_init(info);
target_list_free();
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;
}
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (!dp) /* calloc failed: heap exhaustion */
return 0;
volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) {
dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0);
}
if (e.type) {
DEBUG_WARN("DP not responding for IDCODE! Reset stuck low?\n");
free(dp);
return 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;
/* It seems, JLINK samples read data at end of previous clock.
* So target data read must start at the 12'th clock, while
* write starts as expected at the 14'th clock (8 cmd, 3 response,
* 2 turn around.
*/
cmd[2] = (RnW) ? 11 : 13;
cmd[3] = 0;
cmd[4] = 0xff; /* 8 bits command OUT */
cmd[5] = 0xf0; /* one IN bit to turn around to read, read 2
(read) or 3 (write) IN bits for response and
and one OUT bit to turn around to write on write*/
cmd[6] = request;
cmd[7] = 0x00;
platform_timeout_set(&timeout, 2000);
do {
send_recv(info.usb_link, cmd, 8, res, 2);
send_recv(info.usb_link, NULL, 0, res + 2 , 1);
if (res[2] != 0)
raise_exception(EXCEPTION_ERROR, "Low access setup failed");
ack = res[1] & 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 %d\n", ack);
line_reset(&info);
return 0;
}
/* Always append 8 idle cycle (SWDIO = 0)!*/
if(RnW) {
memset(cmd + 4, 0, 10);
cmd[2] = 33 + 2; /* 2 idle cycles */
cmd[8] = 0xfe;
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] = 33 + 8; /* 8 idle cycle to move data through SW-DP */
memset(cmd + 4, 0xff, 6);
cmd[10] = ((value >> 0) & 0xff);
cmd[11] = ((value >> 8) & 0xff);
cmd[12] = ((value >> 16) & 0xff);
cmd[13] = ((value >> 24) & 0xff);
int bit_count = __builtin_popcount(value);
cmd[14] = bit_count & 1;
cmd[15] = 0;
send_recv(info.usb_link, cmd, 16, res, 6);
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

@ -1,182 +0,0 @@
/*
* 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 "general.h"
#include <unistd.h>
#include <assert.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

@ -1,129 +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>
*
* 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.
*
*/
#include "general.h"
#include <unistd.h>
#include <assert.h>
#include <ftdi.h>
#include "ftdi_bmp.h"
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_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)
{
if ((active_cable->mpsse_swd_read.set_data_low == MPSSE_DO) &&
(active_cable->mpsse_swd_write.set_data_low == MPSSE_DO)) {
printf("Jtag not possible with resistor SWD!\n");
return -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 = libftdi_jtagtap_tdi_tdo_seq;
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
active_state.data_low |= active_cable->jtag.set_data_low |
MPSSE_CS | MPSSE_DI | MPSSE_DO;
active_state.data_low &= ~(active_cable->jtag.clr_data_low | MPSSE_SK);
active_state.ddr_low |= MPSSE_CS | MPSSE_DO | MPSSE_SK;
active_state.ddr_low &= ~(MPSSE_DI);
active_state.data_high |= active_cable->jtag.set_data_high;
active_state.data_high &= ~(active_cable->jtag.clr_data_high);
uint8_t gab[16];
int garbage = ftdi_read_data(ftdic, gab, sizeof(gab));
if (garbage > 0) {
DEBUG_WARN("FTDI JTAG init got garbage:");
for (int i = 0; i < garbage; i++)
DEBUG_WARN(" %02x", gab[i]);
DEBUG_WARN("\n");
}
uint8_t cmd_write[16] = {
SET_BITS_LOW, active_state.data_low,
active_state.ddr_low,
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_write, 6);
libftdi_buffer_flush();
/* Write out start condition and pull garbage from read buffer.
* FT2232D otherwise misbehaves on runs follwoing the first run.*/
garbage = ftdi_read_data(ftdic, cmd_write, sizeof(cmd_write));
if (garbage > 0) {
DEBUG_WARN("FTDI JTAG end init got garbage:");
for (int i = 0; i < garbage; i++)
DEBUG_WARN(" %02x", cmd_write[i]);
DEBUG_WARN("\n");
}
/* Go to JTAG mode for SWJ-DP */
for (int i = 0; i <= 50; i++)
jtag_proc->jtagtap_next(1, 0); /* Reset SW-DP */
jtag_proc->jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */
jtag_proc->jtagtap_tms_seq(0x1F, 6);
return 0;
}
static void jtagtap_reset(void)
{
jtagtap_soft_reset();
}
static void jtagtap_tms_seq(uint32_t MS, int ticks)
{
uint8_t tmp[3] = {
MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
while(ticks >= 0) {
tmp[1] = ticks<7?ticks-1:6;
tmp[2] = 0x80 | (MS & 0x7F);
libftdi_buffer_write(tmp, 3);
MS >>= 7; ticks -= 7;
}
}
static void jtagtap_tdi_seq(
const uint8_t final_tms, const uint8_t *DI, int ticks)
{
return libftdi_jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
}
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};
tmp[2] = (dTDI?0x80:0) | (dTMS?0x01:0);
libftdi_buffer_write(tmp, 3);
libftdi_buffer_read(&ret, 1);
ret &= 0x80;
return ret;
}

View File

@ -1,413 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright(C) 2018 - 2021 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 "general.h"
#include <assert.h>
#include <ftdi.h>
#include "ftdi_bmp.h"
enum swdio_status{
SWDIO_STATUS_DRIVE = 0,
SWDIO_STATUS_FLOAT,
};
static enum swdio_status olddir;
static bool do_mpsse;
static bool direct_bb_swd;
#define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS)
#define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI)
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
MPSSE_BITMODE | MPSSE_WRITE_NEG)
#define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\
MPSSE_BITMODE | MPSSE_WRITE_NEG)
static void swdptap_turnaround(enum swdio_status dir)
{
if (dir == olddir)
return;
olddir = dir;
DEBUG_PROBE("Turnaround %s\n", (dir == SWDIO_STATUS_FLOAT) ? "float": "drive");
if (do_mpsse) {
if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ {
active_state.data_low |= active_cable->mpsse_swd_read.set_data_low | MPSSE_DO;
active_state.data_low &= ~active_cable->mpsse_swd_read.clr_data_low;
active_state.ddr_low &= ~MPSSE_DO;
active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
active_state.data_high &= ~active_cable->mpsse_swd_read.clr_data_high;
uint8_t cmd_read[6] = {
SET_BITS_LOW, active_state.data_low,
active_state.ddr_low,
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_read, 6);
}
uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */
libftdi_buffer_write(cmd, sizeof(cmd));
if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ {
active_state.data_low |= active_cable->mpsse_swd_write.set_data_low | MPSSE_DO;
active_state.data_low &= ~active_cable->mpsse_swd_write.clr_data_low;
active_state.ddr_low |= MPSSE_DO;
active_state.data_high |= active_cable->mpsse_swd_write.set_data_high;
active_state.data_high &= ~active_cable->mpsse_swd_write.clr_data_high;
uint8_t cmd_write[6] = {
SET_BITS_LOW, active_state.data_low,
active_state.ddr_low,
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_write, 6);
}
} else {
uint8_t cmd[9];
int index = 0;
if(dir == SWDIO_STATUS_FLOAT) { /* SWDIO goes to input */
if (direct_bb_swd) {
active_state.data_low |= MPSSE_CS;
active_state.ddr_low &= ~MPSSE_CS;
} else {
active_state.data_low |= active_cable->bb_swd_read.set_data_low;
active_state.data_low &= ~active_cable->bb_swd_read.clr_data_low;
active_state.data_high |= active_cable->bb_swd_read.set_data_high;
active_state.data_high &= ~active_cable->bb_swd_read.clr_data_high;
}
cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_state.data_low;
cmd[index++] = active_state.ddr_low;
cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_state.data_high;
cmd[index++] = active_state.ddr_high;
}
/* One clock cycle */
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
cmd[index++] = 0;
if (dir == SWDIO_STATUS_DRIVE) {
if (direct_bb_swd) {
active_state.data_low |= MPSSE_CS;
active_state.ddr_low |= MPSSE_CS;
} else {
active_state.data_low |= active_cable->bb_swd_write.set_data_low;
active_state.data_low &= ~active_cable->bb_swd_write.clr_data_low;
active_state.data_high |= active_cable->bb_swd_write.set_data_high;
active_state.data_high &= ~active_cable->bb_swd_write.clr_data_high;
}
cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_state.data_low;
cmd[index++] = active_state.ddr_low;
cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_state.data_high;
cmd[index++] = active_state.ddr_high;
}
libftdi_buffer_write(cmd, index);
}
}
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);
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd)
{
bool swd_read =
active_cable->mpsse_swd_read.set_data_low ||
active_cable->mpsse_swd_read.clr_data_low ||
active_cable->mpsse_swd_read.set_data_high ||
active_cable->mpsse_swd_read.clr_data_high;
bool swd_write =
active_cable->mpsse_swd_write.set_data_low ||
active_cable->mpsse_swd_write.clr_data_low ||
active_cable->mpsse_swd_write.set_data_high ||
active_cable->mpsse_swd_write.clr_data_high;
bool mpsse = swd_read && swd_write;
if (do_mpsse)
*do_mpsse = mpsse;
if (!mpsse) {
bool bb_swd_read =
active_cable->bb_swd_read.set_data_low ||
active_cable->bb_swd_read.clr_data_low ||
active_cable->bb_swd_read.set_data_high ||
active_cable->bb_swd_read.clr_data_high;
bool bb_swd_write =
active_cable->bb_swd_write.set_data_low ||
active_cable->bb_swd_write.clr_data_low ||
active_cable->bb_swd_write.set_data_high ||
active_cable->bb_swd_write.clr_data_high;
bool bb_direct_possible =
active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW &&
active_cable->bb_swdio_in_pin == MPSSE_CS;
if (!bb_swd_read && !bb_swd_write) {
if (!bb_direct_possible)
return false;
}
if (direct_bb_swd)
*direct_bb_swd = true;
}
return true;
}
int libftdi_swdptap_init(ADIv5_DP_t *dp)
{
if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
return -1;
}
active_state.data_low |= MPSSE_CS | MPSSE_DI | MPSSE_DO;
active_state.data_low &= MPSSE_SK;
active_state.ddr_low |= MPSSE_SK;
active_state.ddr_low &= ~(MPSSE_CS | MPSSE_DI | MPSSE_DO);
if (do_mpsse) {
DEBUG_INFO("Using genuine MPSSE for SWD.\n");
active_state.data_low |= active_cable->mpsse_swd_read.set_data_low;
active_state.data_low &= ~(active_cable->mpsse_swd_read.clr_data_low);
active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
active_state.data_high &= ~(active_cable->mpsse_swd_read.clr_data_high);
} else if (direct_bb_swd) {
DEBUG_INFO("Using direct bitbang with SWDIO %cBUS%d.\n",
(active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW) ? 'C' : 'D',
__builtin_ctz(active_cable->bb_swdio_in_pin));
} else {
DEBUG_INFO("Using switched bitbang for SWD.\n");
active_state.data_low |= active_cable->bb_swd_read.set_data_low;
active_state.data_low &= ~(active_cable->bb_swd_read.clr_data_low);
active_state.data_high |= active_cable->bb_swd_read.set_data_high;
active_state.data_high &= ~(active_cable->bb_swd_read.clr_data_high);
active_state.ddr_low |= MPSSE_CS;
if (active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW)
active_state.ddr_low &= ~active_cable->bb_swdio_in_pin;
else if (active_cable->bb_swdio_in_port_cmd == GET_BITS_HIGH)
active_state.ddr_high &= ~active_cable->bb_swdio_in_pin;
}
uint8_t cmd_write[6] = {
SET_BITS_LOW, active_state.data_low,
active_state.ddr_low,
SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
libftdi_buffer_write(cmd_write, 6);
libftdi_buffer_flush();
olddir = SWDIO_STATUS_FLOAT;
dp->seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity;
dp->dp_read = firmware_swdp_read;
dp->error = firmware_swdp_error;
dp->low_access = firmware_swdp_low_access;
dp->abort = firmware_swdp_abort;
return 0;
}
bool swdptap_bit_in(void)
{
swdptap_turnaround(SWDIO_STATUS_FLOAT);
uint8_t cmd[4];
int index = 0;
bool result = false;
if (do_mpsse) {
uint8_t cmd[2] = {MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE, 0};
libftdi_buffer_write(cmd, sizeof(cmd));
uint8_t data[1];
libftdi_buffer_read(data, sizeof(data));
result = (data[0] & 0x80);
} else {
cmd[index++] = active_cable->bb_swdio_in_port_cmd;
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 0;
cmd[index++] = 0;
libftdi_buffer_write(cmd, index);
uint8_t data[1];
libftdi_buffer_read(data, sizeof(data));
result = (data[0] &= active_cable->bb_swdio_in_pin);
}
return result;
}
void swdptap_bit_out(bool val)
{
swdptap_turnaround(SWDIO_STATUS_DRIVE);
if (do_mpsse) {
uint8_t cmd[3] = {MPSSE_TDO_SHIFT, 0, (val)? 1:0};
libftdi_buffer_write(cmd, sizeof(cmd));
} else {
uint8_t cmd[3];
cmd[0] = MPSSE_TMS_SHIFT;
cmd[1] = 0;
cmd[2] = (val)? 1 : 0;
libftdi_buffer_write(cmd, sizeof(cmd));
}
}
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
{
assert(ticks == 32);
swdptap_turnaround(SWDIO_STATUS_FLOAT);
unsigned int parity = 0;
unsigned int result = 0;
if (do_mpsse) {
uint8_t DO[5];
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks + 1);
result = DO[0] + (DO[1] << 8) + (DO[2] << 16) + (DO[3] << 24);
parity = __builtin_parity(result & ((1LL << ticks) - 1)) & 1;
parity ^= DO[4] & 1;
} else {
int index = ticks + 1;
uint8_t cmd[4];
cmd[0] = active_cable->bb_swdio_in_port_cmd;
cmd[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0;
cmd[3] = 0;
while (index--) {
libftdi_buffer_write(cmd, sizeof(cmd));
}
uint8_t data[33];
libftdi_buffer_read(data, ticks + 1);
if (data[ticks] & active_cable->bb_swdio_in_pin)
parity ^= 1;
index = ticks;
while (index--) {
if (data[index] & active_cable->bb_swdio_in_pin) {
parity ^= 1;
result |= (1 << index);
}
}
}
*res = result;
return parity;
}
static uint32_t swdptap_seq_in(int ticks)
{
if (!ticks)
return 0;
uint32_t result = 0;
swdptap_turnaround(SWDIO_STATUS_FLOAT);
if (do_mpsse) {
uint8_t DO[4];
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
int bytes = ticks >> 3;
if (ticks & 7)
bytes++;
for (int i = 0; i < bytes; i++) {
result |= DO[i] << (8 * i);
}
} else {
int index = ticks;
uint8_t cmd[4];
cmd[0] = active_cable->bb_swdio_in_port_cmd;
cmd[1] = MPSSE_TMS_SHIFT;
cmd[2] = 0;
cmd[3] = 0;
while (index--) {
libftdi_buffer_write(cmd, sizeof(cmd));
}
uint8_t data[32];
libftdi_buffer_read(data, ticks);
index = ticks;
while (index--) {
if (data[index] & active_cable->bb_swdio_in_pin)
result |= (1 << index);
}
}
return result;
}
static void swdptap_seq_out(uint32_t MS, int ticks)
{
if (!ticks)
return;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
if (do_mpsse) {
uint8_t DI[4];
DI[0] = (MS >> 0) & 0xff;
DI[1] = (MS >> 8) & 0xff;
DI[2] = (MS >> 16) & 0xff;
DI[3] = (MS >> 24) & 0xff;
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks);
} else {
uint8_t cmd[16];
unsigned int index = 0;
while (ticks) {
cmd[index++] = MPSSE_TMS_SHIFT;
if (ticks >= 7) {
cmd[index++] = 6;
cmd[index++] = MS & 0x7f;
MS >>= 7;
ticks -= 7;
} else {
cmd[index++] = ticks - 1;
cmd[index++] = MS & 0x7f;
ticks = 0;
}
}
libftdi_buffer_write(cmd, index);
}
}
/* ARM Debug Interface Architecture Specification ADIv5.0 to ADIv5.2
* tells to clock the data through SW-DP to either :
* - immediate start a new transaction
* - continue to drive idle cycles
* - or clock at least 8 idle cycles
*
* Implement last option to favour correctness over
* slight speed decrease
*/
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
(void) ticks;
int parity = __builtin_parity(MS) & 1;
unsigned int index = 0;
swdptap_turnaround(SWDIO_STATUS_DRIVE);
if (do_mpsse) {
uint8_t DI[8];
DI[0] = (MS >> 0) & 0xff;
DI[1] = (MS >> 8) & 0xff;
DI[2] = (MS >> 16) & 0xff;
DI[3] = (MS >> 24) & 0xff;
DI[4] = parity;
DI[5] = 0;
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, 32 + 1 + 8);
} else {
uint8_t cmd[32];
int steps = ticks;
while (steps) {
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 6;
if (steps >= 7) {
cmd[index++] = MS & 0x7f;
MS >>= 7;
steps -= 7;
} else {
cmd[index++] = (MS & 0x7f) | (parity << 4);
steps = 0;
}
}
cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 4;
cmd[index++] = 0;
libftdi_buffer_write(cmd, index);
}
}

View File

@ -1,556 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* 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
* 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 "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>
#ifdef ENABLE_RTT
#include "rtt_if.h"
#endif
#include "bmp_remote.h"
#include "bmp_hosted.h"
#include "stlinkv2.h"
#include "ftdi_bmp.h"
#include "jlink.h"
#include "cmsis_dap.h"
#include "cl_utils.h"
bmp_info_t info;
jtag_proc_t jtag_proc;
void gdb_ident(char *p, int count)
{
snprintf(p, count, "%s (%s), %s", info.manufacturer, info.product,
info.version);
}
static void exit_function(void)
{
libusb_exit_function(&info);
switch (info.bmp_type) {
case BMP_TYPE_CMSIS_DAP:
dap_exit_function();
break;
default:
break;
}
#ifdef ENABLE_RTT
rtt_if_exit();
#endif
fflush(stdout);
}
/* SIGTERM handler. */
static void sigterm_handler(int sig)
{
(void)sig;
exit(0);
}
static BMP_CL_OPTIONS_t cl_opts;
void platform_init(int argc, char **argv)
{
cl_init(&cl_opts, argc, argv);
atexit(exit_function);
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
if (cl_opts.opt_device)
info.bmp_type = BMP_TYPE_BMP;
else if (find_debuggers(&cl_opts, &info))
exit(-1);
bmp_ident(&info);
switch (info.bmp_type) {
case BMP_TYPE_BMP:
if (serial_open(&cl_opts, info.serial))
exit(-1);
remote_init();
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:
if (ftdi_bmp_init(&cl_opts, &info))
exit(-1);
break;
case BMP_TYPE_JLINK:
if (jlink_init(&info))
exit(-1);
break;
default:
exit(-1);
}
if (cl_opts.opt_mode != BMP_MODE_DEBUG)
exit(cl_execute(&cl_opts));
else {
gdb_if_init();
#ifdef ENABLE_RTT
rtt_if_init();
#endif
return;
}
}
int platform_adiv5_swdp_scan(uint32_t targetid)
{
info.is_jtag = false;
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
switch (info.bmp_type) {
case BMP_TYPE_BMP:
case BMP_TYPE_LIBFTDI:
case BMP_TYPE_CMSIS_DAP:
return adiv5_swdp_scan(targetid);
break;
case BMP_TYPE_STLINKV2:
{
target_list_free();
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (stlink_enter_debug_swd(&info, dp)) {
free(dp);
} else {
adiv5_dp_init(dp);
if (target_list)
return 1;
}
break;
}
case BMP_TYPE_JLINK:
return jlink_swdp_scan(&info);
default:
return 0;
}
return 0;
}
int swdptap_init(ADIv5_DP_t *dp)
{
switch (info.bmp_type) {
case BMP_TYPE_BMP:
return remote_swdptap_init(dp);
case BMP_TYPE_CMSIS_DAP:
return dap_swdptap_init(dp);
case BMP_TYPE_STLINKV2:
case BMP_TYPE_JLINK:
return 0;
case BMP_TYPE_LIBFTDI:
return libftdi_swdptap_init(dp);
default:
return -1;
}
return -1;
}
void platform_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
{
if (info.bmp_type == BMP_TYPE_BMP)
remote_add_jtag_dev(i, jtag_dev);
}
int platform_jtag_scan(const uint8_t *lrlens)
{
info.is_jtag = true;
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
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)
{
dp->dp_bmp_type = info.bmp_type;
switch (info.bmp_type) {
case BMP_TYPE_BMP:
if (cl_opts.opt_no_hl) {
DEBUG_WARN("Not using HL commands\n");
return;
}
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);
case BMP_TYPE_LIBFTDI:
return libftdi_srst_set_val(assert);
case BMP_TYPE_CMSIS_DAP:
return dap_srst_set_val(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);
case BMP_TYPE_LIBFTDI:
return libftdi_srst_get_val();
default:
break;
}
return false;
}
void platform_max_frequency_set(uint32_t freq)
{
if (!freq)
return;
switch (info.bmp_type) {
case BMP_TYPE_BMP:
remote_max_frequency_set(freq);
break;
case BMP_TYPE_CMSIS_DAP:
dap_swj_clock(freq);
break;
case BMP_TYPE_LIBFTDI:
libftdi_max_frequency_set(freq);
break;
case BMP_TYPE_STLINKV2:
stlink_max_frequency_set(&info, freq);
break;
case BMP_TYPE_JLINK:
jlink_max_frequency_set(&info, freq);
break;
default:
DEBUG_WARN("Setting max SWJ frequency not yet implemented\n");
break;
}
uint32_t max_freq = platform_max_frequency_get();
if (max_freq == FREQ_FIXED)
DEBUG_INFO("Device has fixed frequency for %s\n",
(info.is_jtag) ? "JTAG" : "SWD" );
else
DEBUG_INFO("Speed set to %7.4f MHz for %s\n",
platform_max_frequency_get() / 1000000.0,
(info.is_jtag) ? "JTAG" : "SWD" );
}
uint32_t platform_max_frequency_get(void)
{
switch (info.bmp_type) {
case BMP_TYPE_BMP:
return remote_max_frequency_get();
case BMP_TYPE_CMSIS_DAP:
return dap_swj_clock(0);
break;
case BMP_TYPE_LIBFTDI:
return libftdi_max_frequency_get();
case BMP_TYPE_STLINKV2:
return stlink_max_frequency_get(&info);
case BMP_TYPE_JLINK:
return jlink_max_frequency_get(&info);
default:
DEBUG_WARN("Reading max SWJ frequency not yet implemented\n");
break;
}
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)
{
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 ");
if (addr < 0x100) {
switch(addr) {
case 0x00:
if (RnW)
fprintf(stderr, "DP_DPIDR :");
else
fprintf(stderr, "DP_ABORT :");
break;
case 0x04: fprintf(stderr, "CTRL/STAT:");
break;
case 0x08:
if (RnW)
fprintf(stderr, "RESEND :");
else
fprintf(stderr, "DP_SELECT:");
break;
case 0x0c: fprintf(stderr, "DP_RDBUFF:");
break;
default: fprintf(stderr, "Unknown %02x :", addr);
}
} else {
fprintf(stderr, "AP 0x%02x ", addr >> 8);
switch (addr & 0xff) {
case 0x00: fprintf(stderr, "CSW :");
break;
case 0x04: fprintf(stderr, "TAR :");
break;
case 0x0c: fprintf(stderr, "DRW :");
break;
case 0x10: fprintf(stderr, "DB0 :");
break;
case 0x14: fprintf(stderr, "DB1 :");
break;
case 0x18: fprintf(stderr, "DB2 :");
break;
case 0x1c: fprintf(stderr, "DB3 :");
break;
case 0xf8: fprintf(stderr, "BASE :");
break;
case 0xf4: fprintf(stderr, "CFG :");
break;
case 0xfc: fprintf(stderr, "IDR :");
break;
default: fprintf(stderr, "RSVD%02x:", addr & 0xff);
}
}
}
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

@ -1,43 +0,0 @@
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include "timing.h"
char *platform_ident(void);
void platform_buffer_flush(void);
#define PLATFORM_IDENT "(PC-Hosted) "
#define SET_IDLE_STATE(x)
#define SET_RUN_STATE(x)
#define SYSTICKHZ 1000
#define VENDOR_ID_BMP 0x1d50
#define PRODUCT_ID_BMP_BL 0x6017
#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_NO_MSD 0x3754
#define PRODUCT_ID_STLINKV3_BL 0x374d
#define PRODUCT_ID_STLINKV3 0x374f
#define PRODUCT_ID_STLINKV3E 0x374e
#define VENDOR_ID_SEGGER 0x1366
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;
void gdb_ident(char *p, int count);
#endif

View File

@ -1,187 +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>
* 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 "general.h"
#include <unistd.h>
#include <assert.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);
}
}
/* At least up to v1.7.1-233, remote handles only up to 32 ticks in one
* call. Break up large calls.
*
* FIXME: Provide and test faster call and keep fallback
* for old firmware
*/
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;
if(!ticks || (!DI && !DO))
return;
while (ticks) {
int chunk;
if (ticks < 65)
chunk = ticks;
else {
chunk = 64;
}
ticks -= chunk;
uint64_t di = 0;
int bytes = (chunk + 7) >> 3;
int i = 0;
if (DI) {
for (; i < bytes; i++) {
di |= *DI << (i * 8);
DI++;
}
}
/* PRIx64 differs with system. Use it explicit in the format string*/
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
"!J%c%02x%" PRIx64 "%c",
(!ticks && final_tms) ?
REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS,
chunk, di, REMOTE_EOM);
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 res = remotehston(-1, (char *)&construct[1]);
for (i = bytes; i > 0; i--) {
*DO++ = res & 0xff;
res >>= 8;
}
}
}
}
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

@ -1,139 +0,0 @@
/*
* 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>
* Modified 2020 - 2021 by 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(ADIv5_DP_t *dp)
{
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);
}
dp->seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity;
dp->dp_read = firmware_swdp_read;
dp->error = firmware_swdp_error;
dp->low_access = firmware_swdp_low_access;
dp->abort = firmware_swdp_abort;
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

@ -1,127 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* MIT License
*
* Copyright (c) 2021 Koen De Vleeschauwer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <general.h>
#include <unistd.h>
#include <fcntl.h>
#include <rtt_if.h>
/* maybe rewrite this as tcp server */
#ifndef WIN32
#include <termios.h>
/* linux */
static struct termios saved_ttystate;
static bool tty_saved = false;
/* set up and tear down */
int rtt_if_init()
{
struct termios ttystate;
tcgetattr(STDIN_FILENO, &saved_ttystate);
tty_saved = true;
tcgetattr(STDIN_FILENO, &ttystate);
ttystate.c_lflag &= ~ICANON;
ttystate.c_lflag &= ~ECHO;
ttystate.c_cc[VMIN] = 1;
tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
int flags = fcntl(0, F_GETFL, 0);
fcntl(0, F_SETFL, flags | O_NONBLOCK);
return 0;
}
int rtt_if_exit()
{
if (tty_saved)
tcsetattr(STDIN_FILENO, TCSANOW, &saved_ttystate);
return 0;
}
/* write buffer to terminal */
uint32_t rtt_write(const char *buf, uint32_t len)
{
write(1, buf, len);
return len;
}
/* read character from terminal */
int32_t rtt_getchar()
{
char ch;
int len;
len = read(0, &ch, 1);
if (len == 1) return ch;
return -1;
}
/* true if no characters available */
bool rtt_nodata()
{
return false;
}
#else
/* windows, output only */
int rtt_if_init()
{
return 0;
}
int rtt_if_exit()
{
return 0;
}
/* write buffer to terminal */
uint32_t rtt_write(const char *buf, uint32_t len)
{
write(1, buf, len);
return len;
}
/* read character from terminal */
int32_t rtt_getchar()
{
return -1;
}
/* true if no characters available */
bool rtt_nodata()
{
return false;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +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
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int stlink_init(bmp_info_t *info) {return -1;};
int stlink_hwversion(void) {return -1;};
const char *stlink_target_voltage(bmp_info_t *info) {return "ERROR";};
void stlink_srst_set_val(bmp_info_t *info, bool assert) {};
bool stlink_srst_get_val(void) {return true;};
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp) {return -1;};
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
int stlink_jtag_dp_init(ADIv5_DP_t *dp) {return false;};
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) {return 0;};
void stlink_exit_function(bmp_info_t *info) {};
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
uint32_t stlink_max_frequency_get(bmp_info_t *info) {return 0;};
# pragma GCC diagnostic pop
#else
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);
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);
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
uint32_t stlink_max_frequency_get(bmp_info_t *info);
#endif
#endif

View File

@ -4,10 +4,10 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-DSTM32F4 -I../libopencm3/include \ -DSTM32F4 -DHYDRABUS -I../libopencm3/include \
-Iplatforms/stm32 -DDFU_SERIAL_LENGTH=9 -Iplatforms/stm32
LDFLAGS = -lopencm3_stm32f4 \ LDFLAGS = -lopencm3_stm32f4 -Wl,--defsym,_stack=0x20006000 \
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \ -Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
@ -16,18 +16,17 @@ LDFLAGS = -lopencm3_stm32f4 \
VPATH += platforms/stm32 VPATH += platforms/stm32
SRC += cdcacm.c \ SRC += cdcacm.c \
traceswodecode.c \
traceswo.c \ traceswo.c \
usbuart.c \ usbuart.c \
serialno.c \ serialno.c \
timing.c \ timing.c \
timing_stm32.c \ timing_stm32.c \
all: blackmagic.bin blackmagic.hex all: blackmagic.bin blackmagic.hex blackmagic.dfu
blackmagic.dfu: blackmagic.hex blackmagic.dfu: blackmagic.hex
@echo Creating $@ @echo Creating $@
@python3 ../scripts/dfu-convert.py -i $< $@ @python ../scripts/dfu-convert.py -i $< $@
host_clean: host_clean:
-$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu -$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu

View File

@ -27,7 +27,7 @@ make PROBE_HOST=hydrabus
How to Flash the firmware with Windows How to Flash the firmware with Windows
======================================== ========================================
* After build: * After build:
* 1) Download files from https://github.com/hydrabus/hydrafw/tree/master/utils/windows_dfu_util * 1) Download files from https://github.com/bvernoux/hydrafw/tree/master/update_fw_dfu_usb_hydrafw
* 2) Force the F4 into system bootloader mode by jumpering "BOOT0" to "3V3" and "PB2/BOOT1" to "GND" and reset (RESET button). System bootloader should appear. * 2) Force the F4 into system bootloader mode by jumpering "BOOT0" to "3V3" and "PB2/BOOT1" to "GND" and reset (RESET button). System bootloader should appear.
* 3) Run the command `DfuSeCommand.exe -c --de 0 -d --fn .\src\blackmagic.dfu` * 3) Run the command `DfuSeCommand.exe -c --de 0 -d --fn .\src\blackmagic.dfu`

View File

@ -27,7 +27,7 @@
#include "usbuart.h" #include "usbuart.h"
#include "morse.h" #include "morse.h"
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h> #include <libopencm3/stm32/exti.h>
@ -46,7 +46,7 @@ void platform_init(void)
scb_reset_core(); scb_reset_core();
} }
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]); rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_48MHZ]);
/* Enable peripherals */ /* Enable peripherals */
rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN);
@ -63,9 +63,7 @@ void platform_init(void)
GPIOC_OSPEEDR |= 0xA20; GPIOC_OSPEEDR |= 0xA20;
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
TCK_PIN | TDI_PIN); TMS_PIN | TCK_PIN | TDI_PIN);
gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, TMS_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
@ -85,7 +83,7 @@ bool platform_srst_get_val(void) { return false; }
const char *platform_target_voltage(void) const char *platform_target_voltage(void)
{ {
return NULL; return "ABSENT!";
} }
void platform_request_boot(void) void platform_request_boot(void)

View File

@ -28,11 +28,16 @@
#include "gpio.h" #include "gpio.h"
#include "timing.h" #include "timing.h"
#include "timing_stm32.h" #include "timing_stm32.h"
#include "version.h"
#include <setjmp.h> #include <setjmp.h>
#define PLATFORM_HAS_TRACESWO #define PLATFORM_HAS_TRACESWO
#define PLATFORM_IDENT " (HydraBus))" #define BOARD_IDENT "Black Magic Probe (HydraBus), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for HydraBus, (Firmware " FIRMWARE_VERSION ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (HydraBus)"
#define SCB_RESET() scb_reset_core();
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
@ -90,54 +95,49 @@
#define SWDIO_MODE_DRIVE() \ #define SWDIO_MODE_DRIVE() \
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \ gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN); GPIO_PUPD_NONE, SWDIO_PIN);
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
USBUSART_RX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define USB_DRIVER stm32f107_usb_driver #define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ #define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR(x) otg_fs_isr(x) #define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (1 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (2 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USBUSART_DMA (2 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4)
#define IRQ_PRI_TRACE (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART1 #define USBUSART USART1
#define USBUSART_CR1 USART1_CR1 #define USBUSART_CR1 USART1_CR1
#define USBUSART_DR USART1_DR
#define USBUSART_IRQ NVIC_USART1_IRQ #define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_CLK RCC_USART1 #define USBUSART_CLK RCC_USART1
#define USBUSART_PORT GPIOA #define USBUSART_TX_PORT GPIOA
#define USBUSART_TX_PIN GPIO9 #define USBUSART_TX_PIN GPIO9
#define USBUSART_RX_PIN GPIO10 #define USBUSART_RX_PORT GPIOA
#define USBUSART_ISR(x) usart1_isr(x) #define USBUSART_RX_PIN GPIO10
#define USBUSART_DMA_BUS DMA2 #define USBUSART_ISR usart1_isr
#define USBUSART_DMA_CLK RCC_DMA2 #define USBUSART_TIM TIM4
#define USBUSART_DMA_TX_CHAN DMA_STREAM7 #define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ #define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x) #define USBUSART_TIM_ISR tim4_isr
#define USBUSART_DMA_RX_CHAN DMA_STREAM5
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ #define UART_PIN_SETUP() do { \
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x) gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
/* For STM32F4 DMA trigger source must be specified */ USBUSART_TX_PIN); \
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4 gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3 #define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) #define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
#define TRACE_IRQ NVIC_TIM3_IRQ #define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR(x) tim3_isr(x) #define TRACE_ISR tim3_isr
#define DEBUG(...)
#define gpio_set_val(port, pin, val) do { \ #define gpio_set_val(port, pin, val) do { \
if(val) \ if(val) \
@ -155,37 +155,11 @@ static inline int platform_hwversion(void)
return 0; return 0;
} }
/* /* Use newlib provided integer only stdio functions */
* Use newlib provided integer only stdio functions
*/
/* sscanf */
#ifdef sscanf
#undef sscanf
#define sscanf siscanf #define sscanf siscanf
#else
#define sscanf siscanf
#endif
/* sprintf */
#ifdef sprintf
#undef sprintf
#define sprintf siprintf #define sprintf siprintf
#else
#define sprintf siprintf
#endif
/* vasprintf */
#ifdef vasprintf
#undef vasprintf
#define vasprintf vasiprintf #define vasprintf vasiprintf
#else
#define vasprintf vasiprintf
#endif
/* snprintf */
#ifdef snprintf
#undef snprintf
#define snprintf sniprintf #define snprintf sniprintf
#else
#define snprintf sniprintf
#endif
#endif #endif

View File

@ -1,61 +0,0 @@
CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
OPT_FLAGS := -Os
ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -DDEBUG_ME
CFLAGS += -DENABLE_DEBUG
endif
ifeq ($(CUSTOM_SER), 1)
CFLAGS += -DCUSTOM_SER
endif
ifeq ($(CONSOLE_NO_AUTO_CRLF), 1)
CFLAGS += -DCONSOLE_NO_AUTO_CRLF
endif
ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -g3 -ggdb
endif
CFLAGS += -mthumb -mcpu=cortex-m0plus -DDFU_SERIAL_LENGTH=9 \
-DSAMD -DSAMD21E17 -DBLACKMAGIC -I../libopencm3/include \
-Iplatforms/samd -msoft-float -ffunction-sections -fdata-sections -MD
LINKER_SCRIPT="platforms/samd/samd.ld"
LDFLAGS = -mthumb -mcpu=cortex-m0plus -msoft-float -nostartfiles -lc \
$(CPU_FLAGS) -T$(LINKER_SCRIPT) -Wl,--gc-sections \
-L../libopencm3/lib -lopencm3_samd -lnosys -lm -lgcc
ifeq ($(ENABLE_DEBUG), 1)
LDFLAGS += --specs=rdimon.specs
else
LDFLAGS += --specs=nano.specs
endif
VPATH += platforms/samd
SRC += cdcacm.c \
timing.c \
traceswo.o \
usbuart.c \
all: blackmagic_full.bin blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic_dfu.bin : OBJCOPY_FLAGS := --pad-to 0x00002000 --gap-fill 0xFF -j .text -j .data
blackmagic_dfu.bin : LINKER_SCRIPT := "platforms/samd/samd_boot.ld"
blackmagic_dfu.elf: usbdfu.o
@echo " LD $@"
$(Q)$(CC) $^ -o $@ $(LDFLAGS)
blackmagic_full.bin: blackmagic_dfu.bin blackmagic.bin
@echo " CAT $@"
$(Q)cp blackmagic.bin jeff-$(shell git describe --tags --always --dirty).bin
$(Q)cat $^ > $@
host_clean:
$(Q)$(RM) -f blackmagic.bin blackmagic_full.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex jeff*.bin

View File

@ -1,346 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "gdb_if.h"
#include "cdcacm.h"
#include "usbuart.h"
#include "gdb_packet.h"
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/uart.h>
#include <libopencm3/sam/d/adc.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/sam/d/tc.h>
#include <libopencm3/sam/d/eic.h>
static struct gclk_hw clock = {
.gclk0 = SRC_DFLL48M,
.gclk1 = SRC_OSC8M,
.gclk1_div = 30, /* divide clock for ADC */
.gclk2 = SRC_OSC8M,
.gclk2_div = 100, /* divide clock for TC */
.gclk3 = SRC_DFLL48M,
.gclk4 = SRC_DFLL48M,
.gclk5 = SRC_DFLL48M,
.gclk6 = SRC_DFLL48M,
.gclk7 = SRC_DFLL48M,
};
extern void trace_tick(void);
uint8_t running_status;
static volatile uint32_t time_ms;
uint8_t button_pressed;
uint8_t tpwr_enabled;
void sys_tick_handler(void)
{
if(running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN);
time_ms += 10;
uart_pop();
}
uint32_t platform_time_ms(void)
{
return time_ms;
}
static void usb_setup(void)
{
/* Enable USB */
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
/* enable clocking to usb */
set_periph_clk(GCLK0, GCLK_ID_USB);
periph_clk_en(GCLK_ID_USB, 1);
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
}
static uint32_t timing_init(void)
{
uint32_t cal = 0;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
systick_set_reload(4800); /* Interrupt us at 10 Hz */
systick_interrupt_enable();
systick_counter_enable();
return cal;
}
static void adc_init(void)
{
gpio_config_special(ADC_PORT, ADC_POS_PIN, SOC_GPIO_PERIPH_B); /* +input */
gpio_config_special(ADC_PORT, ADC_REF_PIN, SOC_GPIO_PERIPH_B); /* reference */
set_periph_clk(GCLK1, GCLK_ID_ADC);
periph_clk_en(GCLK_ID_ADC, 1);
adc_enable(ADC_REFCTRL_VREFA,0,ADC_INPUTCTRL_GND,ADC_MUXPOS);
}
static void counter_init(void)
{
/* enable bus and clock */
INSERTBF(PM_APBCMASK_TC3, 1, PM->apbcmask);
set_periph_clk(GCLK2, GCLK_ID_TC3);
periph_clk_en(GCLK_ID_TC3, 1);
/* reset */
tc_reset(3);
/* set CTRLA.PRESCALER and CTRLA.PRESYNC */
tc_config_ctrla(3,1,(7<<8));
/* set CC0 (approx. 5 seconds delay) */
tc_set_cc(3,0,1000);
/* enable MC0 interrupt */
tc_enable_interrupt(3,(1<<4));
nvic_enable_irq(NVIC_TC3_IRQ);
}
static void button_init(void)
{
gpio_config_special(BUTTON_PORT, BUTTON_PIN, SOC_GPIO_PERIPH_A);
/* enable bus and clock */
INSERTBF(PM_APBAMASK_EIC, 1, PM->apbamask);
set_periph_clk(GCLK0, GCLK_ID_EIC);
periph_clk_en(GCLK_ID_EIC, 1);
/* configure r/f edge, enable filtering */
eic_set_config(15, 1, EIC_FALL);
/* enable the IEC */
eic_enable(1);
/* enable interrupts */
eic_enable_interrupt((1<<15));
nvic_enable_irq(NVIC_EIC_IRQ);
}
void platform_init(void)
{
gclk_init(&clock);
usb_setup();
gpio_config_output(LED_PORT, LED_IDLE_RUN, 0);
gpio_config_output(TMS_PORT, TMS_PIN, 0);
gpio_config_output(TCK_PORT, TCK_PIN, 0);
gpio_config_output(TDI_PORT, TDI_PIN, 0);
gpio_config_output(TMS_PORT, TMS_DIR_PIN, 0);
gpio_set(TMS_PORT, TMS_DIR_PIN);
/* enable both input and output with pullup disabled by default */
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN;
PORT_PINCFG(SWDIO_PORT, SWDIO_PIN_NUM) |= GPIO_PINCFG_INEN | GPIO_PINCFG_PULLEN;
gpio_clear(SWDIO_PORT, SWDIO_PIN);
/* configure swclk_pin as output */
gpio_config_output(SWCLK_PORT, SWCLK_PIN, 0);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
gpio_config_input(TDO_PORT, TDO_PIN, 0);
gpio_config_output(SRST_PORT, SRST_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
gpio_clear(SRST_PORT, SRST_PIN);
/* setup uart led, disable by default*/
gpio_config_output(LED_PORT_UART, LED_UART, 0);//GPIO_OUT_FLAG_DEFAULT_HIGH);
gpio_clear(LED_PORT_UART, LED_UART);
/* set up TPWR */
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_config_output(PWR_BR_PORT, PWR_BR_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
timing_init();
usbuart_init();
cdcacm_init();
adc_init();
counter_init();
button_init();
}
uint8_t srst_state;
void platform_srst_set_val(bool assert)
{
volatile int i;
if (!assert) {
gpio_clear(SRST_PORT, SRST_PIN);
for(i = 0; i < 10000; i++) asm("nop");
srst_state = 0;
} else {
gpio_set(SRST_PORT, SRST_PIN);
srst_state = 1;
}
}
bool platform_srst_get_val(void)
{
//return gpio_get(SRST_PORT, SRST_PIN) != 0;
return srst_state;
}
bool platform_target_get_power(void)
{
//return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
return tpwr_enabled;
}
void platform_target_set_power(bool power)
{
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
tpwr_enabled = power;
}
void platform_delay(uint32_t ms)
{
platform_timeout timeout;
platform_timeout_set(&timeout, ms);
while (!platform_timeout_is_expired(&timeout));
}
uint32_t platform_target_voltage_sense(void)
{
uint32_t val;
adc_start();
while (!(1&(ADC->intflag)));
val = ((485*adc_result())>>12); /* 330 without divider, 485 with it */
return val;
}
const char *platform_target_voltage(void)
{
uint32_t voltage;
static char out[] = "0.0V";
adc_start();
voltage = platform_target_voltage_sense();
out[0] = '0' + (char)(voltage/100);
out[2] = '0' + (char)((voltage/10) % 10);
return out;
}
char *serial_no_read(char *s)
{
#ifdef CUSTOM_SER
s[0] = 'J';
s[1] = 'E';
s[2] = 'F';
s[3] = 'F';
return s;
#else
int i;
volatile uint32_t unique_id = *(volatile uint32_t *)0x0080A00C +
*(volatile uint32_t *)0x0080A040 +
*(volatile uint32_t *)0x0080A044 +
*(volatile uint32_t *)0x0080A048;
/* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
}
for(i = 0; i < 8; i++)
if(s[i] > '9')
s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
#endif
}
void print_serial(void)
{
gdb_outf("0x%08X%08X%08X%08X\n", *(volatile uint32_t *)0x0080A048,
*(volatile uint32_t *)0x0080A044,
*(volatile uint32_t *)0x0080A040,
*(volatile uint32_t *)0x0080A00C);
}
void platform_request_boot(void)
{
}
void eic_isr(void)
{
if (!button_pressed){
/* set to rising-edge detection */
eic_set_config(15, 1, EIC_RISE);
/* enable counter */
tc_enable(3,1);
button_pressed = 1;
} else {
/* set to falling-edge detection */
eic_set_config(15, 1, EIC_FALL);
/* disable and reset counter */
tc_enable(3,0);
button_pressed = 0;
}
/* clear the interrupt */
eic_clr_interrupt((1<<15));
}
void tc3_isr(void)
{
if (tc_interrupt_flag(3) & 16)
scb_reset_system();
}
uint32_t swd_delay_cnt = 0;
void platform_max_frequency_set(uint32_t freq)
{
(void)freq;
}
uint32_t platform_max_frequency_get(void)
{
return 0;
}

View File

@ -1,227 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include <libopencm3/sam/d/port.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/sam/d/nvmctrl.h>
#include "timing.h"
#include "version.h"
//#define PLATFORM_HAS_DEBUG
//#define USBUART_DEBUG
#define PLATFORM_HAS_UART_WHEN_SWDP
#define PLATFORM_HAS_POWER_SWITCH
#define PLATFORM_HAS_BOOTLOADER
#define PLATFORM_HAS_PRINTSERIAL
//#define BOARD_IDENT "Black Magic Probe (SAMD), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
//#define DFU_IDENT "Black Magic Firmware Upgrade (SAMD)"
#define DFU_IFACE_STRING "hid"
#define BOARD_IDENT_UPD "Black Magic (DFU Upgrade), SAMD21, (Firmware " FIRMWARE_VERSION ")"
#define UPD_IFACE_STRING "@Internal Flash /0x00000000/1*008Ka,15*8Kg"
#define PLATFORM_IDENT " "
extern uint8_t running_status;
extern uint32_t swd_delay_cnt;
#ifdef DEBUG_ME
#define LED_PORT PORTA
#define LED_IDLE_RUN GPIO11
#define LED_ERROR GPIO10
#define TMS_PORT PORTA
#define TMS_PIN GPIO1
#define TMS_DIR_PIN GPIO5
#define TCK_PORT PORTA
#define TCK_PIN GPIO2
#define TDI_PORT PORTA
#define TDI_PIN GPIO16
#define TDO_PORT PORTA
#define TDO_PIN GPIO19
#define SWO_PORT PORTA
#define SWO_PIN GPIO6
#define SWDIO_PORT PORTA
#define SWDIO_PIN TMS_PIN
#define SWDIO_PIN_NUM 1
#define SWCLK_PORT PORTA
#define SWCLK_PIN TCK_PIN
#define SRST_PORT PORTA
#define SRST_PIN GPIO7
#define LED_PORT_UART PORTA
#define LED_UART GPIO12
#define UART_TX_PIN GPIO8
#define UART_RX_PIN GPIO9
#define UART_PERIPH SOC_GPIO_PERIPH_C
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
#define ADC_PORT PORTA
#define ADC_REF_PIN GPIO3
#define ADC_POS_PIN GPIO4
#define ADC_MUXPOS 4
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#else
/* Hardware definitions... */
#define JTAG_PORT PORTA
#define TDI_PORT JTAG_PORT
#define TMS_DIR_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT JTAG_PORT
#define TMS_DIR_PIN GPIO15
#define TMS_PIN GPIO0
#define TCK_PIN GPIO6
#define TDI_PIN GPIO16
#define TDO_PIN GPIO19
#define SWDIO_DIR_PORT JTAG_PORT
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_DIR_PIN TMS_DIR_PIN
#define SWDIO_PIN TMS_PIN
#define SWDIO_PIN_NUM 0
#define SWCLK_PIN TCK_PIN
#define TRST_PORT PORTA
#define TRST_PIN GPIO27
#define PWR_BR_PORT PORTA
#define PWR_BR_PIN GPIO28
#define SRST_PORT PORTA
#define SRST_PIN GPIO8
#define SRST_SENSE_PORT GPIOA
#define SRST_SENSE_PIN GPIO9
#define TRGT_SENSE GPIO2
#define LED_PORT PORTA
#define LED_PORT_UART PORTA
#define LED_0 GPIO10
#define LED_1 GPIO11
#define LED_2 GPIO14
//#define LED_2 GPIO13
#define LED_UART LED_1 /* Orange */
#define LED_IDLE_RUN LED_0 /* Yellow */
#define LED_ERROR LED_2 /* Red */
#define UART_TX_PIN GPIO4
#define UART_RX_PIN GPIO7
#define UART_PERIPH SOC_GPIO_PERIPH_D
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
#define SWO_PORT JTAG_PORT
#define SWO_PIN SWD_PIN
#define ADC_PORT PORTA
#define ADC_REF_PIN GPIO3
#define ADC_POS_PIN GPIO2
#define ADC_MUXPOS 0
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#endif
#define TMS_SET_MODE() { \
gpio_config_output(TMS_PORT, TMS_PIN, 0); \
gpio_set(TMS_PORT, TMS_DIR_PIN); \
}
#define SWDIO_MODE_FLOAT() do { \
PORT_DIRCLR(SWDIO_PORT) = SWDIO_PIN; \
gpio_set(SWDIO_PORT, SWDIO_PIN); \
gpio_clear(TMS_PORT, TMS_DIR_PIN); \
} while(0)
#define SWDIO_MODE_DRIVE() do { \
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN; \
gpio_set(TMS_PORT, TMS_DIR_PIN); \
} while(0)
/* extern usbd_driver samd21_usb_driver; */
#define USB_DRIVER samd21_usb_driver
#define USB_IRQ NVIC_USB_IRQ
#define USB_ISR usb_isr
#define IRQ_PRI_USB (2 << 4)
#define INLINE_GPIO
#define gpio_set_val(port, pin, val) do { \
if(val) \
_gpio_set((port), (pin)); \
else \
_gpio_clear((port), (pin)); \
} while(0)
#ifdef INLINE_GPIO
static inline void _gpio_set(uint32_t gpioport, uint32_t gpios)
{
PORT_OUTSET(gpioport) = gpios;
}
#define gpio_set _gpio_set
static inline void _gpio_clear(uint32_t gpioport, uint32_t gpios)
{
PORT_OUTCLR(gpioport) = gpios;
}
#define gpio_clear _gpio_clear
static inline uint16_t _gpio_get(uint32_t gpioport, uint32_t gpios)
{
return (uint32_t)PORT_IN(gpioport) & gpios;
}
#define gpio_get _gpio_get
#endif
#define DEBUG(...)
#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);}
static inline int platform_hwversion(void)
{
return 0;
}
void uart_pop(void);
int usbuart_convert_tdio(uint32_t arg);
int usbuart_convert_tdio_enabled(void);
void print_serial(void);
#endif

View File

@ -1,351 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/nvmctrl.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/dfu.h>
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/bitfield.h>
#include <libopencm3/sam/d/usb.h>
//#define APP_ADDRESS 0x08002000
//#define APP_ADDRESS 0x00002000
#define APP_ADDRESS 0x00002000
//#define APP_ADDRESS 0x00004000
/* Commands sent with wBlockNum == 0 as per ST implementation. */
#define CMD_SETADDR 0x21
#define CMD_ERASE 0x41
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#define BUF_SIZE 4096
static struct gclk_hw clock = {
.gclk0 = SRC_DFLL48M,
.gclk1 = SRC_OSC8M,
/* clock 1 has 8 divider, clock should be over 1khz for 1ms timer */
.gclk1_div = 100,
.gclk2 = SRC_DFLL48M,
.gclk3 = SRC_DFLL48M,
.gclk3_div = 1,
.gclk4 = SRC_OSC8M,
.gclk4_div = 1,
.gclk5 = SRC_DFLL48M,
.gclk6 = SRC_DFLL48M,
.gclk7 = SRC_DFLL48M,
};
/* We need a special large control buffer for this device: */
uint8_t usbd_control_buffer[BUF_SIZE];
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
static struct {
uint8_t buf[sizeof(usbd_control_buffer)];
uint16_t len;
uint32_t addr;
uint16_t blocknum;
} prog;
const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.idVendor = 0x1D50,
.idProduct = 0x6017,
.bcdDevice = 0x0200,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1,
};
const struct usb_dfu_descriptor dfu_function = {
.bLength = sizeof(struct usb_dfu_descriptor),
.bDescriptorType = DFU_FUNCTIONAL,
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
.wDetachTimeout = 255,
.wTransferSize = BUF_SIZE,
.bcdDFUVersion = 0x011A,
};
const struct usb_interface_descriptor iface = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 2,
/* The ST Microelectronics DfuSe application needs this string.
* The format isn't documented... */
.iInterface = 4,
.extra = &dfu_function,
.extralen = sizeof(dfu_function),
};
const struct usb_interface ifaces[] = {{
.num_altsetting = 1,
.altsetting = &iface,
}};
const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0xC0,
.bMaxPower = 0x32,
.interface = ifaces,
};
static const char *usb_strings[] = {
"Black Sphere Technologies",
"DFU Demo",
"DEMO",
/* This string is used by ST Microelectronics' DfuSe utility. */
//"@Internal Flash /0x08000000/8*001Ka,56*001Kg",
"@Internal Flash /0x00000000/1*008Ka,15*008Kg",
//"@Internal Flash /0x00000000/1*0016Ka,15*0016Kg",
};
static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout)
{
switch (usbdfu_state) {
case STATE_DFU_DNLOAD_SYNC:
usbdfu_state = STATE_DFU_DNBUSY;
*bwPollTimeout = 100;
return DFU_STATUS_OK;
case STATE_DFU_MANIFEST_SYNC:
/* Device will reset when read is complete. */
usbdfu_state = STATE_DFU_MANIFEST;
return DFU_STATUS_OK;
default:
return DFU_STATUS_OK;
}
}
static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req)
{
int i;
(void)req;
(void)usbd_dev;
switch (usbdfu_state) {
case STATE_DFU_DNBUSY:
//flash_unlock();
if (prog.blocknum == 0) {
switch (prog.buf[0]) {
case CMD_ERASE:
{
uint32_t *dat = (uint32_t *)(prog.buf + 1);
nvmctrl_erase_row(*dat); //flash_erase_page(*dat);
}
break;
case CMD_SETADDR:
{
uint32_t *dat = (uint32_t *)(prog.buf + 1);
prog.addr = *dat;
}
break;
}
} else {
//uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) *
// dfu_function.wTransferSize);
uint32_t baseaddr = prog.addr;
//for (i = 0; i < prog.len; i += 2) {
//uint16_t *dat = (uint16_t *)(prog.buf + i);
//flash_program_half_word(baseaddr + i,
// *dat);
for (i = 0; i < BUF_SIZE; i += 256){
nvmctrl_erase_row(baseaddr+i);
nvmctrl_write_row(baseaddr+i, prog.buf+i);
}
//}
}
//flash_lock();
/* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
usbdfu_state = STATE_DFU_DNLOAD_IDLE;
return;
case STATE_DFU_MANIFEST:
/* reset USB */
INSERTBF(USB_CTRLA_SWRST, 1, USB->ctrla);
/* jump to app */
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address. */
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
SCB_VTOR = APP_ADDRESS;
/* Initialise master stack pointer. */
asm volatile("msr msp, %0"::"g"
(*(volatile uint32_t *)APP_ADDRESS));
/* Jump to application. */
(*(void (**)())(APP_ADDRESS + 4))();
}
//scb_reset_system();
return; /* Will never return. */
default:
return;
}
}
static enum usbd_request_return_codes usbdfu_control_request(usbd_device *dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
if ((req->bmRequestType & 0x7F) != 0x21)
return 0; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
return 1;
}
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
return 1;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
return 1;
case DFU_UPLOAD:
/* Upload not supported for now. */
return 0;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
(*buf)[1] = bwPollTimeout & 0xFF;
(*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
(*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
(*buf)[4] = usbdfu_state;
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
return 1;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
return 1;
}
return 0;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
{
(void)wValue;
usbd_register_control_callback(
usbd_dev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
usbdfu_control_request);
}
static void usb_setup(void)
{
/* Enable USB */
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
/* enable clocking to usb */
set_periph_clk(GCLK0, GCLK_ID_USB);
periph_clk_en(GCLK_ID_USB, 1);
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
}
int main(void)
{
usbd_device *usbd_dev;
gclk_init(&clock);
//rcc_periph_clock_enable(RCC_GPIOA);
//gpio_config_input(BUTTON_PORT,BUTTON_PIN,GPIO_IN_FLAG_PULLUP);
gpio_config_input(BUTTON_PORT,BUTTON_PIN,0);
nvmctrl_init(0,0);
usb_setup();
if (PM->rcause != (1<<6))
if (gpio_get(BUTTON_PORT, BUTTON_PIN)) {
//if (gpio_get(PORTA, GPIO27)) {
/* Boot the application if it's valid. */
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address. */
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
SCB_VTOR = APP_ADDRESS;
/* Initialise master stack pointer. */
asm volatile("msr msp, %0"::"g"
(*(volatile uint32_t *)APP_ADDRESS));
/* Jump to application. */
(*(void (**)())(APP_ADDRESS + 4))();
}
}
usbd_dev = usbd_init(&samd21_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, usbdfu_set_config);
//nvic_enable_irq(NVIC_USB_IRQ);
/* Connect USB cable */
usbd_disconnect(usbd_dev, false);
//gpio_clear(GPIOC, GPIO11);
while (1)
usbd_poll(usbd_dev);
}

View File

@ -1,13 +1,11 @@
CROSS_COMPILE ?= arm-none-eabi- CROSS_COMPILE ?= arm-none-eabi-
SERIAL_NO ?= 1
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
INCLUDES = -I../libopencm3/include INCLUDES = -I../libopencm3/include
CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DSERIAL_NO=$(SERIAL_NO) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM
CFLAGS += -DDFU_SERIAL_LENGTH=9
LINKER_SCRIPT="platforms/tm4c/tm4c.ld" LINKER_SCRIPT="platforms/tm4c/tm4c.ld"
LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \ LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \

View File

@ -25,6 +25,9 @@
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/lm4f/usb.h> #include <libopencm3/lm4f/usb.h>
#define SYSTICKHZ 100
#define SYSTICKMS (1000 / SYSTICKHZ)
#define PLL_DIV_80MHZ 5 #define PLL_DIV_80MHZ 5
#define PLL_DIV_25MHZ 16 #define PLL_DIV_25MHZ 16
@ -34,8 +37,6 @@ volatile platform_timeout * volatile head_timeout;
uint8_t running_status; uint8_t running_status;
static volatile uint32_t time_ms; static volatile uint32_t time_ms;
uint32_t swd_delay_cnt = 0;
void sys_tick_handler(void) void sys_tick_handler(void)
{ {
trace_tick(); trace_tick();
@ -61,7 +62,7 @@ platform_init(void)
gpio_enable_ahb_aperture(); gpio_enable_ahb_aperture();
gpio_mode_setup(TMS_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TMS_PIN); gpio_mode_setup(TMS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TMS_PIN);
gpio_mode_setup(TCK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TCK_PIN); gpio_mode_setup(TCK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TCK_PIN);
gpio_mode_setup(TDI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TDI_PIN); gpio_mode_setup(TDI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, TDI_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TDO_PIN); gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, TDO_PIN);
@ -114,23 +115,23 @@ void platform_delay(uint32_t ms)
const char *platform_target_voltage(void) const char *platform_target_voltage(void)
{ {
return NULL; return "not supported";
} }
char *serial_no_read(char *s) char *serialno_read(char *s)
{ {
/* FIXME: Store a unique serial number somewhere and retreive here */ /* FIXME: Store a unique serial number somewhere and retreive here */
uint32_t unique_id = SERIAL_NO; uint32_t unique_id = 1;
int i; int i;
/* Fetch serial number from chip's unique ID */ /* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0'; s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
} }
for(i = 0; i < DFU_SERIAL_LENGTH - 1; i++) for(i = 0; i < 8; i++)
if(s[i] > '9') if(s[i] > '9')
s[i] += 'A' - '9' - 1; s[i] += 'A' - '9' - 1;
s[DFU_SERIAL_LENGTH - 1] = 0; s[8] = 0;
return s; return s;
} }
@ -139,12 +140,3 @@ void platform_request_boot(void)
{ {
} }
void platform_max_frequency_set(uint32_t freq)
{
(void)freq;
}
uint32_t platform_max_frequency_get(void)
{
return 0;
}

View File

@ -21,11 +21,16 @@
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include "timing.h" #include "timing.h"
#include "version.h"
#define PLATFORM_IDENT "(Launchpad ICDI) " #define BOARD_IDENT "Black Magic Probe (Launchpad ICDI), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (Launchpad)"
#define DFU_IFACE_STRING "lolwut"
#define SCB_RESET() scb_reset_core();
extern uint8_t running_status; extern uint8_t running_status;
extern uint32_t swd_delay_cnt;
#define TMS_PORT GPIOA_BASE #define TMS_PORT GPIOA_BASE
#define TMS_PIN GPIO3 #define TMS_PIN GPIO3
@ -65,7 +70,7 @@ extern uint32_t swd_delay_cnt;
gpio_set_output_config(SWDIO_PORT, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, SWDIO_PIN); \ gpio_set_output_config(SWDIO_PORT, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, SWDIO_PIN); \
} }
extern const usbd_driver lm4f_usb_driver; extern usbd_driver lm4f_usb_driver;
#define USB_DRIVER lm4f_usb_driver #define USB_DRIVER lm4f_usb_driver
#define USB_IRQ NVIC_USB0_IRQ #define USB_IRQ NVIC_USB0_IRQ
#define USB_ISR usb0_isr #define USB_ISR usb0_isr
@ -95,6 +100,8 @@ extern const usbd_driver lm4f_usb_driver;
#define vasprintf vasiprintf #define vasprintf vasiprintf
#define snprintf sniprintf #define snprintf sniprintf
#define DEBUG(...)
#define SET_RUN_STATE(state) {running_status = (state);} #define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {} #define SET_IDLE_STATE(state) {}
#define SET_ERROR_STATE(state) SET_IDLE_STATE(state) #define SET_ERROR_STATE(state) SET_IDLE_STATE(state)

View File

@ -0,0 +1,4 @@
CFLAGS += -DLIBFTDI
LDFLAGS += -lftdi -lusb
SRC += timing.c \

View File

@ -0,0 +1,123 @@
/*
* 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/>.
*/
/* This file implements a transparent channel over which the GDB Remote
* Serial Debugging protocol is implemented. This implementation for Linux
* uses a TCP server on port 2000.
*/
#include <stdio.h>
#ifndef WIN32
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <sys/select.h>
#else
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
#endif
#include <assert.h>
#include "general.h"
#include "gdb_if.h"
static int gdb_if_serv, gdb_if_conn;
int gdb_if_init(void)
{
#ifdef WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
struct sockaddr_in addr;
int opt;
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
assert((gdb_if_serv = socket(PF_INET, SOCK_STREAM, 0)) != -1);
opt = 1;
assert(setsockopt(gdb_if_serv, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) != -1);
assert(setsockopt(gdb_if_serv, IPPROTO_TCP, TCP_NODELAY, (void*)&opt, sizeof(opt)) != -1);
assert(bind(gdb_if_serv, (void*)&addr, sizeof(addr)) != -1);
assert(listen(gdb_if_serv, 1) != -1);
DEBUG("Listening on TCP:2000\n");
return 0;
}
unsigned char gdb_if_getchar(void)
{
unsigned char ret;
int i = 0;
while(i <= 0) {
if(gdb_if_conn <= 0) {
gdb_if_conn = accept(gdb_if_serv, NULL, NULL);
DEBUG("Got connection\n");
}
i = recv(gdb_if_conn, (void*)&ret, 1, 0);
if(i <= 0) {
gdb_if_conn = -1;
DEBUG("Dropped broken connection\n");
/* Return '+' in case we were waiting for an ACK */
return '+';
}
}
return ret;
}
unsigned char gdb_if_getchar_to(int timeout)
{
fd_set fds;
struct timeval tv;
if(gdb_if_conn == -1) return -1;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(gdb_if_conn, &fds);
if(select(gdb_if_conn+1, &fds, NULL, NULL, &tv) > 0)
return gdb_if_getchar();
return -1;
}
void gdb_if_putchar(unsigned char c, int flush)
{
static uint8_t buf[2048];
static int bufsize = 0;
if (gdb_if_conn > 0) {
buf[bufsize++] = c;
if (flush || (bufsize == sizeof(buf))) {
send(gdb_if_conn, buf, bufsize, 0);
bufsize = 0;
}
}
}

Some files were not shown because too many files have changed in this diff Show More