From 03bf92f505b70dde280475f42084aaf968310494 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Sun, 5 Apr 2026 17:00:53 +0200 Subject: [PATCH] refined implementation --- fw/programmer/src/bitbang_rvswdio_pico.h | 141 ++++++++++------------- 1 file changed, 59 insertions(+), 82 deletions(-) diff --git a/fw/programmer/src/bitbang_rvswdio_pico.h b/fw/programmer/src/bitbang_rvswdio_pico.h index e8ffdc8..27b6f2c 100644 --- a/fw/programmer/src/bitbang_rvswdio_pico.h +++ b/fw/programmer/src/bitbang_rvswdio_pico.h @@ -11,13 +11,8 @@ #define PIN_SWCLK 11 -// open drain emulation, the pin is set with output '0' and is switched between input or output -// depending on the wanted value, in the high state the line is pulled high by the pull-up and -// in the low state the line in forced low -#define OD_PULL(pin, value) gpio_set_dir((pin), (value) ? GPIO_IN : GPIO_OUT) - // wait time between line transitions -#define SWD_DELAY() busy_wait_us(1); +#define SWD_DELAY() busy_wait_us(2); // microseconds between each register read/write #define STOP_WAIT 8 @@ -25,16 +20,17 @@ // Single wire debug (SWDIO and SWCLK) static inline void ConfigureIOForRVSWD(void) { - // SWDIO, open drain (emulated) with pull-up + // SWCLK forced, starts at 1 + gpio_init(PIN_SWCLK); + gpio_set_pulls(PIN_SWCLK, false, false); + gpio_put(PIN_SWCLK, 1); + gpio_set_dir(PIN_SWCLK, GPIO_OUT); + + // SWDIO, open drain (emulated) with pull-up gpio_init(PIN_SWDIO); gpio_set_pulls(PIN_SWDIO, true, false); - gpio_put(PIN_SWDIO, 0); + gpio_put(PIN_SWDIO, 1); gpio_set_dir(PIN_SWDIO, GPIO_IN); - - gpio_init(PIN_SWCLK); - gpio_set_pulls(PIN_SWCLK, false, false); - gpio_put(PIN_SWCLK, 0); - gpio_set_dir(PIN_SWCLK, GPIO_OUT); } @@ -45,38 +41,12 @@ static inline void ConfigureIOForRVSWIO(void) } -static inline void rvswd_start(void) -{ - // Start with both lines high - gpio_put(PIN_SWCLK, 1); - OD_PULL(PIN_SWDIO, 1); - //SWD_DELAY(); - - // Pull data low - OD_PULL(PIN_SWDIO, 0); - SWD_DELAY(); -} - - -static inline void rvswd_stop(void) -{ - gpio_put(PIN_SWCLK, 0); - SWD_DELAY(); - - OD_PULL(PIN_SWDIO, 0); - SWD_DELAY(); - - gpio_put(PIN_SWCLK, 1); - SWD_DELAY(); - - OD_PULL(PIN_SWDIO, 1); -} - - void rvswd_write_bit(bool value) { gpio_put(PIN_SWCLK, 0); - OD_PULL(PIN_SWDIO, value); + gpio_put(PIN_SWDIO, value); + gpio_set_dir(PIN_SWDIO, GPIO_OUT); + gpio_set_dir(PIN_SWDIO, GPIO_IN); SWD_DELAY(); gpio_put(PIN_SWCLK, 1); // Data is sampled on rising edge of clock SWD_DELAY(); @@ -85,18 +55,31 @@ void rvswd_write_bit(bool value) bool rvswd_read_bit(void) { - OD_PULL(PIN_SWDIO, 0); + gpio_put(PIN_SWDIO, 1); + gpio_set_dir(PIN_SWDIO, GPIO_IN); gpio_put(PIN_SWCLK, 0); - OD_PULL(PIN_SWDIO, 1); SWD_DELAY(); bool bit = gpio_get(PIN_SWDIO); - gpio_put(PIN_SWCLK, 1); // Data is output on rising edge of clock SWD_DELAY(); return bit; } +static inline void rvswd_stop(void) +{ + gpio_put(PIN_SWCLK, 0); + SWD_DELAY(); + gpio_put(PIN_SWDIO, 0); + gpio_set_dir(PIN_SWDIO, GPIO_OUT); + SWD_DELAY(); + gpio_put(PIN_SWCLK, 1); + SWD_DELAY(); + gpio_put(PIN_SWDIO, 1); + gpio_set_dir(PIN_SWDIO, GPIO_IN); +} + + static void MCFWriteReg32( struct SWIOState * state, uint8_t command, uint32_t value ) { // only supported mode is SWD @@ -106,35 +89,34 @@ static void MCFWriteReg32( struct SWIOState * state, uint8_t command, uint32_t v } noInterrupts(); - rvswd_start(); + + // start transaction + gpio_put(PIN_SWDIO, 0); + gpio_set_dir(PIN_SWDIO, GPIO_OUT); + SWD_DELAY(); // ADDR HOST - bool parity = false; // This time it's odd parity? - for (uint8_t position = 0; position < 7; position++) { - bool bit = (command >> (6 - position)) & 1; + bool parity = true; + for (uint32_t mask = 1<<6; mask; mask >>= 1) { + bool bit = !!(command & mask); + parity ^= bit; rvswd_write_bit(bit); - if (bit) parity = !parity; } - // Operation: write - rvswd_write_bit(1); - parity = !parity; - - // Parity bit (even) + rvswd_write_bit(1); // Operation: write rvswd_write_bit(parity); - rvswd_read_bit(); // ??? rvswd_read_bit(); // Seems only need to be set for first transaction (We are ignoring that though) rvswd_read_bit(); // ??? rvswd_write_bit(0); // 0 for register, 1 for value. rvswd_write_bit(0); // ??? Seems to have something to do with halting. - // Data + // DATA parity = false; // This time it's even parity? - for (uint8_t position = 0; position < 32; position++) { - bool bit = (value >> (31 - position)) & 1; + for (uint32_t mask = 1<<31; mask; mask >>= 1) { + bool bit = !!(value & mask); + parity ^= bit; rvswd_write_bit(bit); - if (bit) parity = !parity; } // Parity bit @@ -160,60 +142,55 @@ static int MCFReadReg32( struct SWIOState * state, uint8_t command, uint32_t * v return -1; } - bool parity; - noInterrupts(); - rvswd_start(); + + // start transaction + gpio_put(PIN_SWDIO, 0); + gpio_set_dir(PIN_SWDIO, GPIO_OUT); + SWD_DELAY(); // ADDR HOST - parity = false; - for (uint8_t position = 0; position < 7; position++) { - bool bit = (command >> (6 - position)) & 1; + bool parity = false; + for (uint8_t mask = 1<<6; mask; mask >>= 1) { + bool bit = !!(command & mask); + parity ^= bit; rvswd_write_bit(bit); - if (bit) parity = !parity; } - // Operation: read - rvswd_write_bit(0); - - // Parity bit (even) + rvswd_write_bit(0); // Operation: read rvswd_write_bit(parity); - rvswd_read_bit(); // ?? rvswd_read_bit(); // ?? rvswd_read_bit(); // ?? - rvswd_write_bit(0); // 0 for register, 1 for value rvswd_write_bit(0); // ??? Seems to have something to do with halting? + // DATA *value = 0; - - // Data parity = false; uint32_t rval = 0; for (uint8_t position = 0; position < 32; position++) { bool bit = rvswd_read_bit(); rval <<= 1; - if (bit) { - rval |= 1; - parity ^= 1; - } + rval |= bit; + parity ^= bit; } *value = rval; // Parity bit bool parity_read = rvswd_read_bit(); + if (parity_read != parity) goto read_end; rvswd_read_bit(); // ?? rvswd_read_bit(); // ?? rvswd_read_bit(); // ?? - - rvswd_write_bit(1); // 1 for data + rvswd_write_bit(1); // 0 for register, 1 for value rvswd_write_bit(0); // ??? Seems to have something to do with halting? rvswd_stop(); - interrupts(); +read_end: + interrupts(); sleep_us(STOP_WAIT); return (parity == parity_read) ? 0 : -1; }