diff --git a/Makefile b/Makefile index 471727bb..f660fd5f 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,23 @@ ifndef NO_LIBOPENCM3 git submodule init ;\ git submodule update ;\ fi - $(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f + $(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d endif $(Q)$(MAKE) $(MFLAGS) -C src +all_platforms: + $(Q)$(MAKE) $(MFLAGS) -C src $@ + clean: ifndef NO_LIBOPENCM3 $(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@ endif $(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 diff --git a/libopencm3 b/libopencm3 index e4e5addf..63573143 160000 --- a/libopencm3 +++ b/libopencm3 @@ -1 +1 @@ -Subproject commit e4e5addf760f53802d0b3bebb70d94fec0304e32 +Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8 diff --git a/src/Makefile b/src/Makefile index 16ee4f66..472b1abc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ Q := @ endif CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \ - -std=gnu99 -g3 -MD -I./target \ + -std=gnu99 -MD -I./target \ -I. -Iinclude -I$(PLATFORM_DIR) ifeq ($(ENABLE_DEBUG), 1) @@ -90,8 +90,28 @@ 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 $@" $(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS) @@ -114,7 +134,7 @@ ifndef PC_HOSTED $(Q)$(OBJCOPY) -O ihex $^ $@ endif -.PHONY: clean host_clean all_platforms FORCE +.PHONY: clean host_clean all_platforms clang-format FORCE clean: host_clean $(Q)echo " CLEAN" @@ -122,16 +142,27 @@ clean: host_clean -$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h 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 ;\ mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\ echo "" >> artifacts/index.html ;\ - cp artifacts/*.bin artifacts/$(shell git describe --always --dirty --tags) + cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags) command.c: include/version.h +GIT_VERSION := $(shell git describe --always --dirty --tags) +VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)" + include/version.h: FORCE - $(Q)echo " GIT include/version.h" - $(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty --tags)\"" > $@ + @# If git isn't found then GIT_VERSION will be an empty string. +ifeq ($(GIT_VERSION),) + @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 diff --git a/src/command.c b/src/command.c index 751721d1..a7a68ea5 100644 --- a/src/command.c +++ b/src/command.c @@ -39,7 +39,9 @@ #endif static bool cmd_version(target *t, int argc, char **argv); +#ifdef PLATFORM_HAS_PRINTSERIAL static bool cmd_serial(target *t, int argc, char **argv); +#endif static bool cmd_help(target *t, int argc, char **argv); static bool cmd_jtag_scan(target *t, int argc, char **argv); diff --git a/src/platforms/samd/rtt_if.c b/src/platforms/samd/rtt_if.c new file mode 100644 index 00000000..b6f4ccc1 --- /dev/null +++ b/src/platforms/samd/rtt_if.c @@ -0,0 +1,134 @@ +/* + * 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 "platform.h" +#include +#include "cdcacm.h" +#include "rtt.h" +#include "rtt_if.h" + +/********************************************************************* +* +* rtt terminal i/o +* +********************************************************************** +*/ + +/* usb uart receive buffer */ +static char recv_buf[RTT_DOWN_BUF_SIZE]; +static uint32_t recv_head = 0; +static uint32_t recv_tail = 0; + +/* data from host to target: number of free bytes in usb receive buffer */ +inline static uint32_t recv_bytes_free() +{ + if (recv_tail <= recv_head) + return sizeof(recv_buf) - recv_head + recv_tail - 1; + else + return recv_tail - recv_head - 1; +} + +/* data from host to target: true if not enough free buffer space and we need to close flow control */ +inline static bool recv_set_nak() +{ + assert(sizeof(recv_buf) > 2 * CDCACM_PACKET_SIZE); + return recv_bytes_free() < 2 * CDCACM_PACKET_SIZE; +} + +/* usbuart_usb_out_cb is called when usb uart has received new data for target. + this routine has to be fast */ + +void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep) +{ + (void)dev; + (void)ep; + char usb_buf[CDCACM_PACKET_SIZE]; + + /* close flow control while processing packet */ + usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 1); + + const uint16_t len = usbd_ep_read_packet(usbdev, CDCACM_UART_ENDPOINT, usb_buf, CDCACM_PACKET_SIZE); + + /* skip flag: drop packet if not enough free buffer space */ + if (rtt_flag_skip && len > recv_bytes_free()) { + usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0); + return; + } + + /* copy data to recv_buf */ + for (int i = 0; i < len; i++) { + uint32_t next_recv_head = (recv_head + 1) % sizeof(recv_buf); + if (next_recv_head == recv_tail) + break; /* overflow */ + recv_buf[recv_head] = usb_buf[i]; + recv_head = next_recv_head; + } + + /* block flag: flow control closed if not enough free buffer space */ + if (!(rtt_flag_block && recv_set_nak())) + usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0); + + return; +} + +/* rtt host to target: read one character */ +int32_t rtt_getchar() +{ + int retval; + + if (recv_head == recv_tail) + return -1; + retval = recv_buf[recv_tail]; + recv_tail = (recv_tail + 1) % sizeof(recv_buf); + + /* open flow control if enough free buffer space */ + if (!recv_set_nak()) + usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0); + + return retval; +} + +/* rtt host to target: true if no characters available for reading */ +bool rtt_nodata() +{ + return recv_head == recv_tail; +} + +/* rtt target to host: write string */ +uint32_t rtt_write(const char *buf, uint32_t len) +{ + if (len != 0 && usbdev && cdcacm_get_config() && cdcacm_get_dtr()) { + for (uint32_t p = 0; p < len; p += CDCACM_PACKET_SIZE) { + uint32_t plen = MIN(CDCACM_PACKET_SIZE, len - p); + while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf + p, plen) <= 0); + } + /* flush 64-byte packet on full-speed */ + if (CDCACM_PACKET_SIZE == 64 && (len % CDCACM_PACKET_SIZE) == 0) + while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, NULL, 0) <= 0); + } + return len; +} diff --git a/src/platforms/samd/usbuart.c b/src/platforms/samd/usbuart.c index 1eb8f5d9..fb03a9cb 100644 --- a/src/platforms/samd/usbuart.c +++ b/src/platforms/samd/usbuart.c @@ -55,6 +55,7 @@ struct { volatile size_t head, tail; } rx, tx; +#ifndef ENABLE_RTT /* non blocking putc function */ static void usart_putc(char c) { @@ -74,6 +75,7 @@ static void usart_putc(char c) /* kick the transmitter to restart interrupts */ usart_enable_tx_interrupt(USART_NUM); } +#endif void usbuart_init(void) { @@ -161,6 +163,7 @@ void usbuart_set_line_coding(struct usb_cdc_line_coding *coding) current_baud = coding->dwDTERate; } +#ifndef ENABLE_RTT void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep) { (void)ep; @@ -175,6 +178,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep) } gpio_clear(LED_PORT_UART, LED_UART); } +#endif /* run by our systick timer */ void uart_pop(void)