This is an automated email from Gerrit. Philipp Guehring ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4158
-- gerrit commit 3dafb49f23248c944e74ed8079731de5db69dae3 Author: Philipp Guehring <[email protected]> Date: Sat Jun 10 21:48:52 2017 +0200 drivers: Adding toggle support to all bitbang drivers to speed up JTAG This adds a toggle function to all the bitbang drivers which can toggles TCK multiple times. It speeds up e.g. imx_gpio from 8KB/s to 13KB/s Change-Id: Ibb7cbef0899d7b29211a1567f1c43e3c0ec61412 Signed-off-by: Philipp Guehring <[email protected]> diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index 8f65413..e0a49cf 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -111,6 +111,7 @@ static uint32_t *pio_base; */ static int at91rm9200_read(void); static void at91rm9200_write(int tck, int tms, int tdi); +static void at91rm9200_toggle(unsigned int num_cycles, int tms, int tdi); static void at91rm9200_reset(int trst, int srst); static int at91rm9200_init(void); @@ -119,6 +120,7 @@ static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, + .toggle = at91rm9200_toggle, .reset = at91rm9200_reset, .blink = 0 }; @@ -146,6 +148,25 @@ static void at91rm9200_write(int tck, int tms, int tdi) pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; } +static void at91rm9200_toggle(int num_cycles, int tms, int tdi) +{ + if (tms) + pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK; + else + pio_base[device->TMS_PIO + PIO_CODR] = device->TMS_MASK; + + if (tdi) + pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK; + else + pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; + + for (unsigned int i = 0; i < num_cycles ; i++) { + pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK; + pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; + } +} + + /* (1) assert or (0) deassert reset lines */ static void at91rm9200_reset(int trst, int srst) { diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index a41caf0..8a40d85 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -51,6 +51,8 @@ static volatile uint32_t *pio_base; static int bcm2835gpio_read(void); static void bcm2835gpio_write(int tck, int tms, int tdi); +static void bcm2835gpio_toggle(unsigned int num_cycles, int tms, int tdi); + static void bcm2835gpio_reset(int trst, int srst); static int bcm2835_swdio_read(void); @@ -62,6 +64,7 @@ static int bcm2835gpio_quit(void); static struct bitbang_interface bcm2835gpio_bitbang = { .read = bcm2835gpio_read, .write = bcm2835gpio_write, + .toggle = bcm2835gpio_toggle, .reset = bcm2835gpio_reset, .swdio_read = bcm2835_swdio_read, .swdio_drive = bcm2835_swdio_drive, @@ -108,6 +111,26 @@ static void bcm2835gpio_write(int tck, int tms, int tdi) asm volatile (""); } +static void bcm2835gpio_toggle(unsigned int num_cycles, int tms, int tdi) +{ + uint32_t set0 = 0<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio; + uint32_t clear0 = 1<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio; + uint32_t set1 = 1<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio; + uint32_t clear1 = 0<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio; + + for (unsigned int j = 0; j < num_cycles; j++) { + GPIO_SET = set0; + GPIO_CLR = clear0; + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); + GPIO_SET = set0; + GPIO_CLR = clear0; + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); + } +} + + static void bcm2835gpio_swd_write(int tck, int tms, int tdi) { uint32_t set = tck<<swclk_gpio | tdi<<swdio_gpio; diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index c9ec9c9..6abd6e9 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -67,6 +67,8 @@ struct bitbang_interface *bitbang_interface; */ #define CLOCK_IDLE() 0 +#define TOGGLE 1 + /* The bitbang driver leaves the TCK 0 when in idle */ static void bitbang_end_state(tap_state_t state) { @@ -86,8 +88,12 @@ static void bitbang_state_move(int skip) for (i = skip; i < tms_count; i++) { tms = (tms_scan >> i) & 1; +#ifdef TOGGLE + bitbang_interface->toggle(1, tms, 0); +#else bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); +#endif } bitbang_interface->write(CLOCK_IDLE(), tms, 0); @@ -108,8 +114,12 @@ static int bitbang_execute_tms(struct jtag_command *cmd) int tms = 0; for (unsigned i = 0; i < num_bits; i++) { tms = ((bits[i/8] >> (i % 8)) & 1); +#ifdef TOGGLE + bitbang_interface->toggle(1, tms, 0); +#else bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); +#endif } bitbang_interface->write(CLOCK_IDLE(), tms, 0); @@ -134,10 +144,12 @@ static void bitbang_path_move(struct pathmove_command *cmd) tap_state_name(cmd->path[state_count])); exit(-1); } - +#ifdef TOGGLE + bitbang_interface->toggle(1, tms, 0); +#else bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); - +#endif tap_set_state(cmd->path[state_count]); state_count++; num_states--; @@ -150,7 +162,9 @@ static void bitbang_path_move(struct pathmove_command *cmd) static void bitbang_runtest(int num_cycles) { +#ifndef TOGGLE int i; +#endif tap_state_t saved_end_state = tap_get_end_state(); @@ -161,10 +175,15 @@ static void bitbang_runtest(int num_cycles) } /* execute num_cycles */ +#ifdef TOGGLE + bitbang_interface->toggle(num_cycles, 0, 0); +#else for (i = 0; i < num_cycles; i++) { bitbang_interface->write(0, 0, 0); bitbang_interface->write(1, 0, 0); } +#endif + bitbang_interface->write(CLOCK_IDLE(), 0, 0); /* finish in end_state */ @@ -176,13 +195,19 @@ static void bitbang_runtest(int num_cycles) static void bitbang_stableclocks(int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); +#ifndef TOGGLE int i; +#endif /* send num_cycles clocks onto the cable */ +#ifdef TOGGLE + bitbang_interface->write(num_cycles, tms, 0); +#else for (i = 0; i < num_cycles; i++) { bitbang_interface->write(1, tms, 0); bitbang_interface->write(0, tms, 0); } +#endif } static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index c5b44bf..6ddfdb4 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -33,6 +33,7 @@ struct bitbang_interface { void (*blink)(int on); int (*swdio_read)(void); void (*swdio_drive)(bool on); + void (*toggle)(unsigned int num_cycles, int tms, int tdi); }; const struct swd_driver bitbang_swd; diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 0f7c12d..31a6e38 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -71,6 +71,14 @@ static void dummy_write(int tck, int tms, int tdi) } } +static void dummy_toggle(unsigned int num_cycles, int tms, int tdi) +{ + for (unsigned int i = 0; i < num_cycles; i++) { + dummy_write(0, tms, tdi); + dummy_write(1, tms, tdi); + } +} + static void dummy_reset(int trst, int srst) { dummy_clock = 0; @@ -88,6 +96,7 @@ static void dummy_led(int on) static struct bitbang_interface dummy_bitbang = { .read = &dummy_read, .write = &dummy_write, + .toggle = &dummy_toggle, .reset = &dummy_reset, .blink = &dummy_led, }; diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index ccd9795..9b0a4ff 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -34,6 +34,8 @@ #include <sys/mman.h> static uint8_t output_value; +static uint8_t output_value1; + static int dev_mem_fd; static void *gpio_controller; static volatile uint8_t *gpio_data_register; @@ -43,6 +45,7 @@ static volatile uint8_t *gpio_data_direction_register; */ static int ep93xx_read(void); static void ep93xx_write(int tck, int tms, int tdi); +static void ep93xx_toggle(unsigned int num_cycles, int tms, int tdi); static void ep93xx_reset(int trst, int srst); static int ep93xx_init(void); @@ -63,6 +66,7 @@ struct jtag_interface ep93xx_interface = { static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, + .toggle = ep93xx_toggle, .reset = ep93xx_reset, .blink = 0, }; @@ -93,6 +97,37 @@ static void ep93xx_write(int tck, int tms, int tdi) nanosleep(&ep93xx_zzzz, NULL); } +static void ep93xx_toggle(unsigned int num_cycles, int tms, int tdi) +{ + output_value1 = output_value; + output_value1 |= TCK_BIT; + output_value &= ~TCK_BIT; + + if (tms) { + output_value |= TMS_BIT; + output_value1 |= TMS_BIT; + } else { + output_value &= ~TMS_BIT; + output_value1 &= ~TMS_BIT; + } + + if (tdi) { + output_value |= TDI_BIT; + output_value1 |= TDI_BIT; + } else { + output_value &= ~TDI_BIT; + output_value1 &= ~TDI_BIT; + } + + for (unsigned int i = 0; i < num_cycles; i++) { + *gpio_data_register = output_value; + nanosleep(&ep93xx_zzzz, NULL); + *gpio_data_register = output_value1; + nanosleep(&ep93xx_zzzz, NULL); + } +} + + /* (1) assert or (0) deassert reset lines */ static void ep93xx_reset(int trst, int srst) { diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index f33d109..bff51d6 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -84,6 +84,7 @@ static inline bool gpio_level(int g) static int imx_gpio_read(void); static void imx_gpio_write(int tck, int tms, int tdi); +static void imx_gpio_toggle(unsigned int num_cycles, int tms, int tdi); static void imx_gpio_reset(int trst, int srst); static int imx_gpio_swdio_read(void); @@ -96,6 +97,7 @@ static struct bitbang_interface imx_gpio_bitbang = { .read = imx_gpio_read, .write = imx_gpio_write, .reset = imx_gpio_reset, + .toggle = imx_gpio_toggle, .swdio_read = imx_gpio_swdio_read, .swdio_drive = imx_gpio_swdio_drive, .blink = NULL @@ -133,6 +135,29 @@ static int imx_gpio_read(void) return gpio_level(tdo_gpio); } +static void imx_gpio_toggle(unsigned int num_cycles, int tms, int tdi) +{ + tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); + tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio); + + if (jtag_delay) { + for (unsigned int i = 0; i < num_cycles; i++) { + gpio_clear(tck_gpio); + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); + gpio_set(tck_gpio); + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); + } + } else { + for (unsigned int i = 0; i < num_cycles; i++) { + gpio_clear(tck_gpio); + gpio_set(tck_gpio); + } + } +} + + static void imx_gpio_write(int tck, int tms, int tdi) { tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); @@ -468,7 +493,7 @@ static int imx_gpio_init(void) } - LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", + LOG_INFO("imx_gpio mmap: pagesize: %lu, regionsize: %u", sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE, PROT_READ | PROT_WRITE, diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index c9e3316..0cbaf37 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -148,6 +148,7 @@ static inline void parport_write_data(void) #endif } + static void parport_write(int tck, int tms, int tdi) { int i = wait_states + 1; @@ -171,6 +172,15 @@ static void parport_write(int tck, int tms, int tdi) parport_write_data(); } +static void parport_toggle(unsigned int num_cycles, int tms, int tdi) +{ + for (unsigned int i = 0; i < num_cycles; i++) { + parport_write(0, tms, tdi); + parport_write(1, tms, tdi); + } +} + + /* (1) assert or (0) deassert reset lines */ static void parport_reset(int trst, int srst) { @@ -254,6 +264,7 @@ static int parport_get_giveio_access(void) static struct bitbang_interface parport_bitbang = { .read = &parport_read, .write = &parport_write, + .toggle = &parport_toggle, .reset = &parport_reset, .blink = &parport_led, }; diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index c8d0136..ebaf704 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -108,6 +108,17 @@ static void remote_bitbang_write(int tck, int tms, int tdi) remote_bitbang_putc(c); } +static void remote_bitbang_toggle(unsigned int num_cycles, int tms, int tdi) +{ + char c0 = '0' + (0x0 | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); + char c1 = '0' + (0x4 | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); + + for (unsigned int i = 0; i < num_cycles; i++) { + remote_bitbang_putc(c0); + remote_bitbang_putc(c1); + } +} + static void remote_bitbang_reset(int trst, int srst) { char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); @@ -123,6 +134,7 @@ static void remote_bitbang_blink(int on) static struct bitbang_interface remote_bitbang_bitbang = { .read = &remote_bitbang_read, .write = &remote_bitbang_write, + .toggle = &remote_bitbang_toggle, .reset = &remote_bitbang_reset, .blink = &remote_bitbang_blink, }; diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index 77b727c..b607f08 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -260,6 +260,15 @@ static int sysfsgpio_read(void) return buf[0] != '0'; } +/* This cache needs to be global since we have 2 different functions using it: */ +/* We can cache the old value to avoid needlessly writing it. */ + +static int sysfsgpio_first_time; +static int sysfsgpio_last_tck; +static int sysfsgpio_last_tms; +static int sysfsgpio_last_tdi; + + /* * Bitbang interface write of TCK, TMS, TDI * @@ -276,44 +285,94 @@ static void sysfsgpio_write(int tck, int tms, int tdi) const char one[] = "1"; const char zero[] = "0"; - static int last_tck; - static int last_tms; - static int last_tdi; - - static int first_time; size_t bytes_written; - if (!first_time) { - last_tck = !tck; - last_tms = !tms; - last_tdi = !tdi; - first_time = 1; + if (!sysfsgpio_first_time) { + sysfsgpio_last_tck = !tck; + sysfsgpio_last_tms = !tms; + sysfsgpio_last_tdi = !tdi; + sysfsgpio_first_time = 1; } - if (tdi != last_tdi) { + if (tdi != sysfsgpio_last_tdi) { bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tdi failed"); } - if (tms != last_tms) { + if (tms != sysfsgpio_last_tms) { bytes_written = write(tms_fd, tms ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tms failed"); } /* write clk last */ - if (tck != last_tck) { + if (tck != sysfsgpio_last_tck) { bytes_written = write(tck_fd, tck ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tck failed"); } - last_tdi = tdi; - last_tms = tms; - last_tck = tck; + sysfsgpio_last_tdi = tdi; + sysfsgpio_last_tms = tms; + sysfsgpio_last_tck = tck; +} + +/* + * Bitbang interface toggle several times with TMS, TDI + * + * Seeing as this is the only function where the outputs are changed, + * we can cache the old value to avoid needlessly writing it. + */ +static void sysfsgpio_toggle(unsigned int num_cycles, int tms, int tdi) +{ + if (swd_mode) { + for (unsigned int i = 0; i < num_cycles; i++) { + sysfsgpio_swdio_write(0, tdi); + sysfsgpio_swdio_write(1, tdi); + } + return; + } + + const char one[] = "1"; + const char zero[] = "0"; + + size_t bytes_written; + + if (!sysfsgpio_first_time) { + sysfsgpio_last_tms = !tms; + sysfsgpio_last_tdi = !tdi; + sysfsgpio_first_time = 1; + } + + if (tdi != sysfsgpio_last_tdi) { + bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tdi failed"); + } + + if (tms != sysfsgpio_last_tms) { + bytes_written = write(tms_fd, tms ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tms failed"); + } + + /* write clk last */ + for (unsigned int i = 0; i < num_cycles; i++) { + bytes_written = write(tck_fd, &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tck failed"); + bytes_written = write(tck_fd, &one, 1); + if (bytes_written != 1) + LOG_WARNING("writing tck failed"); + } + + sysfsgpio_last_tdi = tdi; + sysfsgpio_last_tms = tms; + sysfsgpio_last_tck = 1; } + /* * Bitbang interface to manipulate reset lines SRST and TRST * @@ -532,6 +591,7 @@ struct jtag_interface sysfsgpio_interface = { static struct bitbang_interface sysfsgpio_bitbang = { .read = sysfsgpio_read, .write = sysfsgpio_write, + .toggle = sysfsgpio_toggle, .reset = sysfsgpio_reset, .swdio_read = sysfsgpio_swdio_read, .swdio_drive = sysfsgpio_swdio_drive, -- ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
