commit 5dfd44123f837451412c21315dd1a8e8f5ded2da Author: sys64738 Date: Mon Sep 27 00:45:46 2021 +0200 add stuff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e0ff4cc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +# use directory name for project id +set(FAMILY "rp2040" CACHE STRING "Board/MCU family, decides which drivers to use. Set to RP2040 by default.") +set(BOARD "raspberry_pi_pico" CACHE STRING "Board used, determines the pinout. Defaults to the Raspberry Pi Pico.") + +set(PROJECT "430prog") +#set(PROJECT ${BOARD}-${PROJECT}) + +# TOP is absolute path to root directory of TinyUSB git repo + +# Check for -DFAMILY= +if(FAMILY STREQUAL "rp2040") + option(PICO_NO_FLASH "Disable writing the compiled program to flash, and only load it to RAM. Useful for testing, but not much else (OFF by default)." ON) + option(PICO_COPY_TO_RAM "Run all code in RAM, while the program is also stored on flash. On bootup, everything will be copied to RAM (OFF by default)." OFF) + + cmake_minimum_required(VERSION 3.12) + #set(TOP "$ENV{PICO_SDK_PATH}/lib/tinyusb") + #get_filename_component(TOP "${TOP}" REALPATH) + include(cmake/pico_sdk_import.cmake) + + #include(${TOP}/hw/bsp/${FAMILY}/family.cmake) + + #family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + project(${PROJECT}) + #family_initialize_project(PROJECT ${CMAKE_CURRENT_LIST_DIR}) # calls pico_sdk_init() + pico_sdk_init() + + add_executable(${PROJECT}) + + pico_enable_stdio_uart(${PROJECT} 1) + pico_enable_stdio_usb(${PROJECT} 0) + # Example source + target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/pio_sbw.c + ) + + # Example include + target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/ + ) + + # Example defines + target_compile_definitions(${PROJECT} PUBLIC + ) + + target_link_libraries(${PROJECT} pico_stdlib pico_unique_id + hardware_pio hardware_dma hardware_pwm) + + pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/sbw.pio) + + pico_add_extra_outputs(${PROJECT}) +else() + message(FATAL_ERROR "Invalid FAMILY specified") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Werror=maybe-uninitialized") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--cref") + diff --git a/README.md b/README.md new file mode 100644 index 0000000..43a025f --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# 430prog + +Researching MSP430 programming/Spy-Bi-Wire debugging impl on the RP2040. It's +all very WIP. Will probably be integrated into DragonProbe when ready. + diff --git a/cmake/pico_sdk_import.cmake b/cmake/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/cmake/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..61ef661 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +*.bak* diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e93aa3d --- /dev/null +++ b/src/main.c @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include "pio_sbw.h" + +void printbuf(const uint8_t* buf, size_t size) { + for (int i = 0; i < size; ++i) + printf("%02x%c", buf[i], i % 16 == 15 ? '\n' : ' '); +} + +int main() { + stdio_init_all(); + + bool s = sbw_init(); + printf("%s", s ? "inited" : "failure"); + + return 0; +} diff --git a/src/pio_sbw.c b/src/pio_sbw.c new file mode 100644 index 0000000..9ea27a6 --- /dev/null +++ b/src/pio_sbw.c @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "pio_sbw.h" + +#include "sbw.pio.h" + +int sbw_piosm = -1, sbw_offset = -1; + +bool sbw_init(void) { + if (sbw_piosm >= 0 || sbw_offset >= 0) return false; + + if (!pio_can_add_program(PINOUT_SBW_PIO, &sbw_program)) return false; + sbw_offset = pio_add_program(PINOUT_SBW_PIO, &sbw_program); + + sbw_piosm = pio_claim_unused_sm(PINOUT_SBW_PIO, false); + if (sbw_piosm < 0) { + pio_remove_program(PINOUT_SBW_PIO, &sbw_program, sbw_offset); + sbw_offset = -1; + return false; + } + + sbw_pio_init(PINOUT_SBW_PIO, sbw_piosm, sbw_offset, 200e3, + PINOUT_SBW_TCK, PINOUT_SBW_TDIO); + + return true; +} + +void sbw_deinit(void) { + if (sbw_piosm >= 0) { + pio_sm_set_enabled(PINOUT_SBW_PIO, sbw_piosm, false); + pio_sm_unclaim(PINOUT_SBW_PIO, sbw_piosm); + sbw_piosm = -1; + } + + if (sbw_offset >= 0) { + pio_remove_program(PINOUT_SBW_PIO, &sbw_program, sbw_offset); + sbw_offset = -1; + } +} + +void sbw_set_freq(bool tclk, float freq) { + if (tclk) { + sbw_pio_set_tclkfreq(PINOUT_SBW_PIO, sbw_piosm, freq); + } else { + sbw_pio_set_baudrate(PINOUT_SBW_PIO, sbw_piosm, freq); + } +} + +void sbw_sequence(uint32_t ncyc, uint32_t tms, const uint8_t* tdi, uint8_t* tdo) { + static uint64_t last_tdi = ~(uint64_t)0; + static uint64_t devnull = 0; + + uint32_t nbytes = (ncyc + 7) >> 3; + + // fuck this im not doing this rn sorry + // TODO: finish this tomorrow +} + +void sbw_tms_sequence(uint32_t ncyc, uint32_t tdi, const uint8_t* tms) { + +} + +static int last_tclk = 1; + +void sbw_clr_tclk(void) { + +} +void sbw_set_tclk(void) { + +} + +void sbw_tclk_burst(uint32_t ncyc) { + +} + +// Just 8 bit functions provided here. The PIO program supports any frame size +// 1...32, but the software to do the necessary FIFO shuffling is left as an +// exercise for the reader :) +// +// Likewise we only provide MSB-first here. To do LSB-first, you need to +// - Do shifts when reading from the FIFO, for general case n != 8, 16, 32 +// - Do a narrow read at a one halfword or 3 byte offset for n == 16, 8 +// in order to get the read data correctly justified. + +/*void __time_critical_func(pio_spi_write8_blocking)(const pio_spi_inst_t *spi, const uint8_t *src, size_t len) { + size_t tx_remain = len, rx_remain = len; + // Do 8 bit accesses on FIFO, so that write data is byte-replicated. This + // gets us the left-justification for free (for MSB-first shift-out) + io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm]; + io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm]; + while (tx_remain || rx_remain) { + if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) { + *txfifo = *src++; + --tx_remain; + } + if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) { + (void) *rxfifo; + --rx_remain; + } + } +} + +void __time_critical_func(pio_spi_read8_blocking)(const pio_spi_inst_t *spi, uint8_t *dst, size_t len) { + size_t tx_remain = len, rx_remain = len; + io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm]; + io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm]; + while (tx_remain || rx_remain) { + if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) { + *txfifo = 0; + --tx_remain; + } + if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) { + *dst++ = *rxfifo; + --rx_remain; + } + } +} + +void __time_critical_func(pio_spi_write8_read8_blocking)(const pio_spi_inst_t *spi, uint8_t *src, uint8_t *dst, + size_t len) { + size_t tx_remain = len, rx_remain = len; + io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm]; + io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm]; + while (tx_remain || rx_remain) { + if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) { + *txfifo = *src++; + --tx_remain; + } + if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) { + *dst++ = *rxfifo; + --rx_remain; + } + } +}*/ + diff --git a/src/pio_sbw.h b/src/pio_sbw.h new file mode 100644 index 0000000..6a8eaef --- /dev/null +++ b/src/pio_sbw.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _PIO_SPI_H +#define _PIO_SPI_H + +#include +#include +/*#include */ + +#define PINOUT_SBW_PIO pio0 +#define PINOUT_SBW_TCK 8 +#define PINOUT_SBW_TDIO 9 + +extern int sbw_piosm, sbw_offset; + +bool sbw_init(void); +void sbw_deinit(void); + +void sbw_set_freq(bool tclk, float freq); + +void sbw_sequence(uint32_t ncyc, uint32_t tms, const uint8_t* tdi, uint8_t* tdo); +void sbw_tms_sequence(uint32_t ncyc, uint32_t tdi, const uint8_t* tms); + +void sbw_clr_tclk(void); +void sbw_set_tclk(void); + +void sbw_tclk_burst(uint32_t ncyc); + +#endif diff --git a/src/sbw.pio b/src/sbw.pio new file mode 100644 index 0000000..0a4f5ec --- /dev/null +++ b/src/sbw.pio @@ -0,0 +1,192 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program sbw +.side_set 1 + +; Pin assignments: +; - SBWTCK is side-set pin 0 +; - SBWTDIO is OUT/IN pin 0 +; +; Autopush and autopull must be enabled, set to 8 +; SBWTDIO input should not be guarded with sync flipflops, as TDO xfers are synchronous + +PUBLIC start: + ; SBWTCK hi to not lose/reset debug mode + pull side 1 ; clear leftover OSR bits, pull in new data +startloop: + out exec, 16 side 1 ; use for set y, 0/1 ; in x, num ; jmp addr + jmp startloop side 1 + +; "subroutine" "calling convention" +; * set y, 0/1 : initial TMS (sbw_seq) / TDI (sbw_tms_seq) / TCLK (sbw_tclk_burst) value +; * in x, num : number of JTAG cycles (sbw_seq/sbw_tms_seq) / TCLK half-cycles (sbw_tclk_burst) +; * jmp subroutine +; * ^ all 'side 1' + +; y: static TMS value to use +; x: number of JTAG clock cycles minus one +; TDI output gets sourced bit by bit from the TX FIFO +; TDO input gets sent bit by bit to the RX FIFO +PUBLIC sbw_seq: +sbw_seq_iter: + ; tms slot: + set pindirs, 1 side 1 ; SBWTDIO is now output + mov pins, y side 1 ; output static TMS value + nop side 0 [1] ; target reads TMS at falling edge + ; tdi slot: + out pins, 1 side 1 [1] ; output TDI from FIFO + nop side 0 [1] ; target reads TDI at falling edge + ; tdo slot: + set pindirs, 0 side 1 [1] ; we need some clock pulse + nop side 0 ; give target some time to drive IO + in pins, 1 side 0 ; input TDO + + jmp x--, sbw_seq_iter side 1 ; also gives target some time to stop driving IO + + push side 1 ; flush ISR + jmp start side 1 + + +; y: static TDI value to use +; x: number of JTAG clock cycles minus one +; TMS output gets sourced bit by bit from the TX FIFO +PUBLIC sbw_tms_seq: + ; tms slot + set pindirs, 1 side 1 ; SBWTDIO is now output + out pins, 1 side 1 ; output TMS from FIFO + nop side 0 [1] ; target reads TMS at falling edge + ; tdi slot + mov pins, y side 1 [1] ; output static TDI value + nop side 0 [1] ; target reads TDI at falling edge + ; tdo slot + set pindirs, 0 side 1 [1] + jmp x--, sbw_tms_seq side 0 [1] ; ignore returned TDO, go back + + jmp start side 1 + + +; stationary SBWTCK values are: +; jmp +; TMS TDI TDO |TMS TDI TDO +; | | | || | | +; 1100110011001110011001100 ... +; +; a full cycle takes 13 cycles, a single slot 4 +; the SM divider should be sysclk/(4*baudrate) +; baudrate shouldn't exceed 20 MHz (typical value is 1.8 MHz?) +; SBWTCK LOW phases shouldn't exceed 7us, so the baudrate should be at least 72 kHz + +; y: initial/previous TCLK value +; x: number of TCLK *half*-cycles minus one! +; TCLK values get sourced from the TX FIFO. best is to use a DMA with fixed +; source address, with value 0x55/0xaa (depending on y) for strobes, or +; 0x00/0xff (and x=0) for a single set/clear. +; alternatively, one could set the "load-bearing instruction" to a +; "set pins, 0/1 side 1 [12]" for a fixed value useful for single sets/clears +PUBLIC sbw_tclk_burst: + set pindirs, 1 side 1 ; SBWTDIO is now output + ; tms slot: + set pins, 0 side 1 ; stay in run-test/idle TAP state + nop side 0 ; target reads TMS at falling edge + mov pins, y side 0 ; during low phase, prepare TCLK + ; tdi slot: + nop side 1 ; wait a bit + burst_loop: +PUBLIC sbw_tclk_burst_loadbearing_insn: + out pins, 1 side 1 [12] ; in the middle of TDI hiphase: do TCLK + jmp x--, burst_loop side 1 [12] + nop side 0 [1] ; need a low clock edge for TDO + ; tdo slot: + set pindirs, 0 side 1 [1] + nop side 0 [1] + + ;jmp start side 1 ; not needed because of wrapping +; 32 insns -- filling one entire PIO instruction memory + +; TODO: update this paragraph +; a full TCLK cycle in this burst mode takes 24 PIOSM cycles. at a "standard" +; baudrate of 18 MHz, this ends up being 375 kHz, which is in the required +; range when doing eg. flash programming. at the max baudrate (20 MHz), the +; TCLK speed is 417 kHz, which is still ok. max TCLK would be, if PIOSM freq is +; 125 MHz, 2.6 MHz, which is good enough imo +; TODO: determine minimum baudrate for stable TCLK (12 MHz?) + + +% c-sdk { +static inline void sbw_pio_init(PIO pio, uint sm, uint prog_offs, + float freq, uint pin_sbwclk, uint pin_sbwio) { + if (freq < 72e3) freq = 72e3; + if (freq > 20e6) freq = 20e6; + + pio_sm_config c = sbw_program_get_default_config(prog_offs); + sm_config_set_out_pins(&c, pin_sbwio, 1); + sm_config_set_in_pins(&c, pin_sbwio); + sm_config_set_sideset_pins(&c, pin_sbwclk); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_in_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / (4 * freq)); + + // SBWTDIO is low, SBWTCK is high, SBWTDIO is input by default + // MOSI, SCK output are low, MISO is input + pio_sm_set_pins_with_mask(pio, sm, + (1u << pin_sbwclk), (1u << pin_sbwclk) | (1u << pin_sbwio)); + pio_sm_set_pindirs_with_mask(pio, sm, + (1u << pin_sbwclk), (1u << pin_sbwclk) | (1u << pin_sbwio)); + pio_gpio_init(pio, pin_sbwclk); + pio_gpio_init(pio, pin_sbwio ); + + // SBW is mostly synchronous, bypass input synchroniser to reduce delay + hw_set_bits(&pio->input_sync_bypass, 1u << pin_sbwio); + + pio_sm_init(pio, sm, prog_offs, &c); + pio_sm_set_enabled(pio, sm, true); +} + +// meant for sbw_seq/sbw_tms_seq +static inline void sbw_pio_set_baudrate(PIO pio, uint sm, float freq) { + if (freq < 72e3) freq = 72e3; + if (freq > 20e6) freq = 20e6; + + pio_sm_set_clkdiv(pio, sm, (float)clock_get_hz(clk_sys) / (4 * freq)); +} + +// meant for sbw_tclk_burst +static inline void sbw_pio_set_tclkfreq(PIO pio, uint sm, float freq) { + if (freq < 250e3) freq = 250e3; + if (freq > 450e3) freq = 450e3; + + pio_sm_set_clkdiv(pio, sm, (float)clock_get_hz(clk_sys) / (24 * freq)); +} + +static inline uint16_t sbw_pio_gen_sety(uint y) { + return pio_encode_set(pio_y, y) | pio_encode_sideset(1, 1); +} +static inline uint16_t sbw_pio_gen_inx(uint bits) { + return pio_encode_in(pio_x, bits) | pio_encode_sideset(1, 1); +} +// subroutine is one of "sbw_offset_sbw_seq", "sbw_offset_sbw_tms_seq", "sbw_offset_sbw_tclk_burst" +static inline uint16_t sbw_pio_gen_jmp(uint subroutine) { + return pio_encode_jmp(subroutine) | pio_encode_sideset(1, 1); +} +static inline uint16_t sbw_pio_loadbearing_gen_outpins(void) { + return pio_encode_out(pio_pins, 1) | pio_encode_sideset(1, 1) | pio_encode_delay(12); +} +static inline uint16_t sbw_pio_loadbearing_gen_setpins(uint value) { + return pio_encode_set(pio_pins, value) | pio_encode_sideset(1, 1) | pio_encode_delay(12); +} + +static inline void sbw_pio_loadbearing_set_outpins(PIO pio) { + pio->instr_mem[sbw_offset_sbw_tclk_burst_loadbearing_insn] = + sbw_pio_loadbearing_gen_outpins(); +} +static inline void sbw_pio_loadbearing_set_setpins(PIO pio, uint value) { + pio->instr_mem[sbw_offset_sbw_tclk_burst_loadbearing_insn] = + sbw_pio_loadbearing_gen_setpins(value); +} + +%} +