From: Tim Newsome Date: Wed, 13 Dec 2017 21:13:22 +0000 (-0800) Subject: Add read buffer to bitbang, improving performance. X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=64f1f7b1c179dcce4e008bef6bf9515c47ae4100;p=openocd Add read buffer to bitbang, improving performance. Previously for every bit scanned OpenOCD would write the bit, wait for that bit to be scanned, and then read the result. This involves at least 2 context switches. Most of the time the next bit scanned does not depend on the last bit we read, so with a buffer we now write a bunch of bits to be scanned all at once, and then we wait for them all to be scanned and have a result. This reduces the time for one testcase where OpenOCD connects to a simulator from 12.30s to 5.35s! Running all our tests went from 13m13s to 3m55s. Change-Id: Ie9fcea043ac1d7877a521125334ed47d4b3e1615 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4312 Tested-by: jenkins Reviewed-by: Freddie Chopin --- diff --git a/src/helper/replacements.h b/src/helper/replacements.h index 1e2fbf20..f43b7e0f 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -199,6 +199,17 @@ static inline int close_socket(int sock) #endif } +static inline void socket_block(int fd) +{ +#ifdef _WIN32 + unsigned long nonblock = 0; + ioctlsocket(fd, FIONBIO, &nonblock); +#else + int oldopts = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, oldopts & ~O_NONBLOCK); +#endif +} + static inline void socket_nonblock(int fd) { #ifdef _WIN32 diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index 8f65413a..0015da06 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -109,9 +109,9 @@ static uint32_t *pio_base; /* low level command set */ -static int at91rm9200_read(void); -static void at91rm9200_write(int tck, int tms, int tdi); -static void at91rm9200_reset(int trst, int srst); +static bb_value_t at91rm9200_read(void); +static int at91rm9200_write(int tck, int tms, int tdi); +static int at91rm9200_reset(int trst, int srst); static int at91rm9200_init(void); static int at91rm9200_quit(void); @@ -123,12 +123,12 @@ static struct bitbang_interface at91rm9200_bitbang = { .blink = 0 }; -static int at91rm9200_read(void) +static bb_value_t at91rm9200_read(void) { - return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) != 0; + return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) ? BB_HIGH : BB_LOW; } -static void at91rm9200_write(int tck, int tms, int tdi) +static int at91rm9200_write(int tck, int tms, int tdi) { if (tck) pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; @@ -144,10 +144,12 @@ static void at91rm9200_write(int tck, int tms, int tdi) pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK; else pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; + + return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ -static void at91rm9200_reset(int trst, int srst) +static int at91rm9200_reset(int trst, int srst) { if (trst == 0) pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; @@ -158,6 +160,8 @@ static void at91rm9200_reset(int trst, int srst) pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; else if (srst == 1) pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK; + + return ERROR_OK; } COMMAND_HANDLER(at91rm9200_handle_device_command) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index a4d0a1c8..38ef163f 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -49,9 +49,9 @@ uint32_t bcm2835_peri_base = 0x20000000; static int dev_mem_fd; static volatile uint32_t *pio_base; -static int bcm2835gpio_read(void); -static void bcm2835gpio_write(int tck, int tms, int tdi); -static void bcm2835gpio_reset(int trst, int srst); +static bb_value_t bcm2835gpio_read(void); +static int bcm2835gpio_write(int tck, int tms, int tdi); +static int bcm2835gpio_reset(int trst, int srst); static int bcm2835_swdio_read(void); static void bcm2835_swdio_drive(bool is_output); @@ -91,12 +91,12 @@ static int speed_coeff = 113714; static int speed_offset = 28; static unsigned int jtag_delay; -static int bcm2835gpio_read(void) +static bb_value_t bcm2835gpio_read(void) { - return !!(GPIO_LEV & 1<> i) & 1; - bitbang_interface->write(0, tms, 0); - bitbang_interface->write(1, tms, 0); + if (bitbang_interface->write(0, tms, 0) != ERROR_OK) + return ERROR_FAIL; + if (bitbang_interface->write(1, tms, 0) != ERROR_OK) + return ERROR_FAIL; } - bitbang_interface->write(CLOCK_IDLE(), tms, 0); + if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) + return ERROR_FAIL; tap_set_state(tap_get_end_state()); + return ERROR_OK; } /** @@ -108,15 +108,18 @@ 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); - bitbang_interface->write(0, tms, 0); - bitbang_interface->write(1, tms, 0); + if (bitbang_interface->write(0, tms, 0) != ERROR_OK) + return ERROR_FAIL; + if (bitbang_interface->write(1, tms, 0) != ERROR_OK) + return ERROR_FAIL; } - bitbang_interface->write(CLOCK_IDLE(), tms, 0); + if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) + return ERROR_FAIL; return ERROR_OK; } -static void bitbang_path_move(struct pathmove_command *cmd) +static int bitbang_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; @@ -135,20 +138,24 @@ static void bitbang_path_move(struct pathmove_command *cmd) exit(-1); } - bitbang_interface->write(0, tms, 0); - bitbang_interface->write(1, tms, 0); + if (bitbang_interface->write(0, tms, 0) != ERROR_OK) + return ERROR_FAIL; + if (bitbang_interface->write(1, tms, 0) != ERROR_OK) + return ERROR_FAIL; tap_set_state(cmd->path[state_count]); state_count++; num_states--; } - bitbang_interface->write(CLOCK_IDLE(), tms, 0); + if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) + return ERROR_FAIL; tap_set_end_state(tap_get_state()); + return ERROR_OK; } -static void bitbang_runtest(int num_cycles) +static int bitbang_runtest(int num_cycles) { int i; @@ -157,38 +164,50 @@ static void bitbang_runtest(int num_cycles) /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { bitbang_end_state(TAP_IDLE); - bitbang_state_move(0); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) { - bitbang_interface->write(0, 0, 0); - bitbang_interface->write(1, 0, 0); + if (bitbang_interface->write(0, 0, 0) != ERROR_OK) + return ERROR_FAIL; + if (bitbang_interface->write(1, 0, 0) != ERROR_OK) + return ERROR_FAIL; } - bitbang_interface->write(CLOCK_IDLE(), 0, 0); + if (bitbang_interface->write(CLOCK_IDLE(), 0, 0) != ERROR_OK) + return ERROR_FAIL; /* finish in end_state */ bitbang_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) - bitbang_state_move(0); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; } -static void bitbang_stableclocks(int num_cycles) +static int bitbang_stableclocks(int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); int i; /* send num_cycles clocks onto the cable */ for (i = 0; i < num_cycles; i++) { - bitbang_interface->write(1, tms, 0); - bitbang_interface->write(0, tms, 0); + if (bitbang_interface->write(1, tms, 0) != ERROR_OK) + return ERROR_FAIL; + if (bitbang_interface->write(0, tms, 0) != ERROR_OK) + return ERROR_FAIL; } + + return ERROR_OK; } -static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) +static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, + unsigned scan_size) { tap_state_t saved_end_state = tap_get_end_state(); - int bit_cnt; + unsigned bit_cnt; if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || @@ -198,12 +217,13 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int else bitbang_end_state(TAP_DRSHIFT); - bitbang_state_move(0); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; bitbang_end_state(saved_end_state); } + size_t buffered = 0; for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { - int val = 0; int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tdi; int bytec = bit_cnt/8; @@ -217,18 +237,47 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int if ((type != SCAN_IN) && (buffer[bytec] & bcval)) tdi = 1; - bitbang_interface->write(0, tms, tdi); - - if (type != SCAN_OUT) - val = bitbang_interface->read(); - - bitbang_interface->write(1, tms, tdi); + if (bitbang_interface->write(0, tms, tdi) != ERROR_OK) + return ERROR_FAIL; if (type != SCAN_OUT) { - if (val) - buffer[bytec] |= bcval; - else - buffer[bytec] &= ~bcval; + if (bitbang_interface->buf_size) { + if (bitbang_interface->sample() != ERROR_OK) + return ERROR_FAIL; + buffered++; + } else { + switch (bitbang_interface->read()) { + case BB_LOW: + buffer[bytec] &= ~bcval; + break; + case BB_HIGH: + buffer[bytec] |= bcval; + break; + default: + return ERROR_FAIL; + } + } + } + + if (bitbang_interface->write(1, tms, tdi) != ERROR_OK) + return ERROR_FAIL; + + if (type != SCAN_OUT && bitbang_interface->buf_size && + (buffered == bitbang_interface->buf_size || + bit_cnt == scan_size - 1)) { + for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) { + switch (bitbang_interface->read_sample()) { + case BB_LOW: + buffer[i/8] &= ~(1 << (i % 8)); + break; + case BB_HIGH: + buffer[i/8] |= 1 << (i % 8); + break; + default: + return ERROR_FAIL; + } + } + buffered = 0; } } @@ -237,8 +286,10 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int * the shift state, so we skip the first state * and move directly to the end state. */ - bitbang_state_move(1); + if (bitbang_state_move(1) != ERROR_OK) + return ERROR_FAIL; } + return ERROR_OK; } int bitbang_execute_queue(void) @@ -259,8 +310,10 @@ int bitbang_execute_queue(void) */ retval = ERROR_OK; - if (bitbang_interface->blink) - bitbang_interface->blink(1); + if (bitbang_interface->blink) { + if (bitbang_interface->blink(1) != ERROR_OK) + return ERROR_FAIL; + } while (cmd) { switch (cmd->type) { @@ -273,7 +326,9 @@ int bitbang_execute_queue(void) if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); - bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + if (bitbang_interface->reset(cmd->cmd.reset->trst, + cmd->cmd.reset->srst) != ERROR_OK) + return ERROR_FAIL; break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ @@ -282,14 +337,16 @@ int bitbang_execute_queue(void) tap_state_name(cmd->cmd.runtest->end_state)); #endif bitbang_end_state(cmd->cmd.runtest->end_state); - bitbang_runtest(cmd->cmd.runtest->num_cycles); + if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) + return ERROR_FAIL; break; case JTAG_STABLECLOCKS: /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ - bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles); + if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) + return ERROR_FAIL; break; case JTAG_TLR_RESET: @@ -298,7 +355,8 @@ int bitbang_execute_queue(void) tap_state_name(cmd->cmd.statemove->end_state)); #endif bitbang_end_state(cmd->cmd.statemove->end_state); - bitbang_state_move(0); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ @@ -306,18 +364,22 @@ int bitbang_execute_queue(void) cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); #endif - bitbang_path_move(cmd->cmd.pathmove); + if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) + return ERROR_FAIL; break; case JTAG_SCAN: + bitbang_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); #ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("%s scan end in %s", + LOG_DEBUG("%s scan %d bits; end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + scan_size, tap_state_name(cmd->cmd.scan->end_state)); #endif - bitbang_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); - bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, + scan_size) != ERROR_OK) + return ERROR_FAIL; if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; if (buffer) @@ -338,8 +400,10 @@ int bitbang_execute_queue(void) } cmd = cmd->next; } - if (bitbang_interface->blink) - bitbang_interface->blink(0); + if (bitbang_interface->blink) { + if (bitbang_interface->blink(0) != ERROR_OK) + return ERROR_FAIL; + } return retval; } diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index c5b44bfd..577717eb 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -24,13 +24,35 @@ #include +typedef enum { + BB_LOW, + BB_HIGH, + BB_ERROR +} bb_value_t; + +/** Low level callbacks (for bitbang). + * + * Either read(), or sample() and read_sample() must be implemented. + * + * The sample functions allow an interface to batch a number of writes and + * sample requests together. Not waiting for a value to come back can greatly + * increase throughput. */ struct bitbang_interface { - /* low level callbacks (for bitbang) - */ - int (*read)(void); - void (*write)(int tck, int tms, int tdi); - void (*reset)(int trst, int srst); - void (*blink)(int on); + /** Sample TDO. */ + bb_value_t (*read)(void); + + /** The number of TDO samples that can be buffered up before the caller has + * to call read_sample. */ + size_t buf_size; + /** Sample TDO and put the result in a buffer. */ + int (*sample)(void); + /** Return the next unread value from the buffer. */ + bb_value_t (*read_sample)(void); + + /** Set TCK, TMS, and TDI to the given values. */ + int (*write)(int tck, int tms, int tdi); + int (*reset)(int trst, int srst); + int (*blink)(int on); int (*swdio_read)(void); void (*swdio_drive)(bool on); }; diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 0f7c12dd..db1ba13a 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -33,14 +33,14 @@ static int clock_count; /* count clocks in any stable state, only stable states static uint32_t dummy_data; -static int dummy_read(void) +static bb_value_t dummy_read(void) { int data = 1 & dummy_data; dummy_data = (dummy_data >> 1) | (1 << 31); - return data; + return data ? BB_HIGH : BB_LOW; } -static void dummy_write(int tck, int tms, int tdi) +static int dummy_write(int tck, int tms, int tdi) { /* TAP standard: "state transitions occur on rising edge of clock" */ if (tck != dummy_clock) { @@ -69,9 +69,10 @@ static void dummy_write(int tck, int tms, int tdi) } dummy_clock = tck; } + return ERROR_OK; } -static void dummy_reset(int trst, int srst) +static int dummy_reset(int trst, int srst) { dummy_clock = 0; @@ -79,10 +80,12 @@ static void dummy_reset(int trst, int srst) dummy_state = TAP_RESET; LOG_DEBUG("reset to: %s", tap_state_name(dummy_state)); + return ERROR_OK; } -static void dummy_led(int on) +static int dummy_led(int on) { + return ERROR_OK; } static struct bitbang_interface dummy_bitbang = { diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index ccd97950..36fc7774 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -41,9 +41,9 @@ static volatile uint8_t *gpio_data_direction_register; /* low level command set */ -static int ep93xx_read(void); -static void ep93xx_write(int tck, int tms, int tdi); -static void ep93xx_reset(int trst, int srst); +static bb_value_t ep93xx_read(void); +static int ep93xx_write(int tck, int tms, int tdi); +static int ep93xx_reset(int trst, int srst); static int ep93xx_init(void); static int ep93xx_quit(void); @@ -67,12 +67,12 @@ static struct bitbang_interface ep93xx_bitbang = { .blink = 0, }; -static int ep93xx_read(void) +static bb_value_t ep93xx_read(void) { - return !!(*gpio_data_register & TDO_BIT); + return (*gpio_data_register & TDO_BIT) ? BB_HIGH : BB_LOW; } -static void ep93xx_write(int tck, int tms, int tdi) +static int ep93xx_write(int tck, int tms, int tdi) { if (tck) output_value |= TCK_BIT; @@ -91,10 +91,12 @@ static void ep93xx_write(int tck, int tms, int tdi) *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); + + return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ -static void ep93xx_reset(int trst, int srst) +static int ep93xx_reset(int trst, int srst) { if (trst == 0) output_value |= TRST_BIT; @@ -108,6 +110,8 @@ static void ep93xx_reset(int trst, int srst) *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); + + return ERROR_OK; } static int set_gonk_mode(void) diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index f33d1097..2a822afe 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -82,9 +82,9 @@ static inline bool gpio_level(int g) return pio_base[g / 32].dr >> (g & 0x1F) & 1; } -static int imx_gpio_read(void); -static void imx_gpio_write(int tck, int tms, int tdi); -static void imx_gpio_reset(int trst, int srst); +static bb_value_t imx_gpio_read(void); +static int imx_gpio_write(int tck, int tms, int tdi); +static int imx_gpio_reset(int trst, int srst); static int imx_gpio_swdio_read(void); static void imx_gpio_swdio_drive(bool is_output); @@ -128,12 +128,12 @@ static int speed_coeff = 50000; static int speed_offset = 100; static unsigned int jtag_delay; -static int imx_gpio_read(void) +static bb_value_t imx_gpio_read(void) { - return gpio_level(tdo_gpio); + return gpio_level(tdo_gpio) ? BB_HIGH : BB_LOW; } -static void imx_gpio_write(int tck, int tms, int tdi) +static int imx_gpio_write(int tck, int tms, int tdi) { tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio); @@ -141,25 +141,31 @@ static void imx_gpio_write(int tck, int tms, int tdi) for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); + + return ERROR_OK; } -static void imx_gpio_swd_write(int tck, int tms, int tdi) +static int imx_gpio_swd_write(int tck, int tms, int tdi) { tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio); tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio); for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); + + return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ -static void imx_gpio_reset(int trst, int srst) +static int imx_gpio_reset(int trst, int srst) { if (trst_gpio != -1) trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio); if (srst_gpio != -1) srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio); + + return ERROR_OK; } static void imx_gpio_swdio_drive(bool is_output) @@ -469,7 +475,7 @@ static int imx_gpio_init(void) LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", - sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); + (unsigned int) 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, MAP_SHARED, dev_mem_fd, imx_gpio_peri_base); diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index c9e33164..14fa9df9 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -116,7 +116,7 @@ static unsigned long dataport; static unsigned long statusport; #endif -static int parport_read(void) +static bb_value_t parport_read(void) { int data = 0; @@ -127,9 +127,9 @@ static int parport_read(void) #endif if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) - return 1; + return BB_HIGH; else - return 0; + return BB_LOW; } static inline void parport_write_data(void) @@ -148,7 +148,7 @@ static inline void parport_write_data(void) #endif } -static void parport_write(int tck, int tms, int tdi) +static int parport_write(int tck, int tms, int tdi) { int i = wait_states + 1; @@ -169,10 +169,12 @@ static void parport_write(int tck, int tms, int tdi) while (i-- > 0) parport_write_data(); + + return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ -static void parport_reset(int trst, int srst) +static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); @@ -187,10 +189,12 @@ static void parport_reset(int trst, int srst) dataport_value &= ~cable->SRST_MASK; parport_write_data(); + + return ERROR_OK; } /* turn LED on parport adapter on (1) or off (0) */ -static void parport_led(int on) +static int parport_led(int on) { if (on) dataport_value |= cable->LED_MASK; @@ -198,6 +202,8 @@ static void parport_led(int on) dataport_value &= ~cable->LED_MASK; parport_write_data(); + + return ERROR_OK; } static int parport_speed(int speed) @@ -365,9 +371,12 @@ static int parport_init(void) #endif /* PARPORT_USE_PPDEV */ - parport_reset(0, 0); - parport_write(0, 0, 0); - parport_led(1); + if (parport_reset(0, 0) != ERROR_OK) + return ERROR_FAIL; + if (parport_write(0, 0, 0) != ERROR_OK) + return ERROR_FAIL; + if (parport_led(1) != ERROR_OK) + return ERROR_FAIL; bitbang_interface = &parport_bitbang; @@ -376,7 +385,8 @@ static int parport_init(void) static int parport_quit(void) { - parport_led(0); + if (parport_led(0) != ERROR_OK) + return ERROR_FAIL; if (parport_exit) { dataport_value = cable->PORT_EXIT; diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index c8d01366..1f8fc1a1 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -30,40 +30,86 @@ /* arbitrary limit on host name length: */ #define REMOTE_BITBANG_HOST_MAX 255 -#define REMOTE_BITBANG_RAISE_ERROR(expr ...) \ - do { \ - LOG_ERROR(expr); \ - LOG_ERROR("Terminating openocd."); \ - exit(-1); \ - } while (0) - static char *remote_bitbang_host; static char *remote_bitbang_port; -FILE *remote_bitbang_in; -FILE *remote_bitbang_out; +static FILE *remote_bitbang_file; +static int remote_bitbang_fd; + +/* Circular buffer. When start == end, the buffer is empty. */ +static char remote_bitbang_buf[64]; +static unsigned remote_bitbang_start; +static unsigned remote_bitbang_end; + +static int remote_bitbang_buf_full(void) +{ + return remote_bitbang_end == + ((remote_bitbang_start + sizeof(remote_bitbang_buf) - 1) % + sizeof(remote_bitbang_buf)); +} -static void remote_bitbang_putc(int c) +/* Read any incoming data, placing it into the buffer. */ +static int remote_bitbang_fill_buf(void) { - if (EOF == fputc(c, remote_bitbang_out)) - REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno)); + socket_nonblock(remote_bitbang_fd); + while (!remote_bitbang_buf_full()) { + unsigned contiguous_available_space; + if (remote_bitbang_end >= remote_bitbang_start) { + contiguous_available_space = sizeof(remote_bitbang_buf) - + remote_bitbang_end; + if (remote_bitbang_start == 0) + contiguous_available_space -= 1; + } else { + contiguous_available_space = remote_bitbang_start - + remote_bitbang_end - 1; + } + ssize_t count = read(remote_bitbang_fd, + remote_bitbang_buf + remote_bitbang_end, + contiguous_available_space); + if (count > 0) { + remote_bitbang_end += count; + if (remote_bitbang_end == sizeof(remote_bitbang_buf)) + remote_bitbang_end = 0; + } else if (count == 0) { + return ERROR_OK; + } else if (count < 0) { + if (errno == EAGAIN) { + return ERROR_OK; + } else { + LOG_ERROR("remote_bitbang_fill_buf: %s (%d)", + strerror(errno), errno); + return ERROR_FAIL; + } + } + } + + return ERROR_OK; +} + +static int remote_bitbang_putc(int c) +{ + if (EOF == fputc(c, remote_bitbang_file)) { + LOG_ERROR("remote_bitbang_putc: %s", strerror(errno)); + return ERROR_FAIL; + } + return ERROR_OK; } static int remote_bitbang_quit(void) { - if (EOF == fputc('Q', remote_bitbang_out)) { + if (EOF == fputc('Q', remote_bitbang_file)) { LOG_ERROR("fputs: %s", strerror(errno)); return ERROR_FAIL; } - if (EOF == fflush(remote_bitbang_out)) { + if (EOF == fflush(remote_bitbang_file)) { LOG_ERROR("fflush: %s", strerror(errno)); return ERROR_FAIL; } /* We only need to close one of the FILE*s, because they both use the same */ /* underlying file descriptor. */ - if (EOF == fclose(remote_bitbang_out)) { + if (EOF == fclose(remote_bitbang_file)) { LOG_ERROR("fclose: %s", strerror(errno)); return ERROR_FAIL; } @@ -75,53 +121,83 @@ static int remote_bitbang_quit(void) return ERROR_OK; } -/* Get the next read response. */ -static int remote_bitbang_rread(void) +static bb_value_t char_to_int(int c) { - if (EOF == fflush(remote_bitbang_out)) { - remote_bitbang_quit(); - REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno)); - } - - int c = fgetc(remote_bitbang_in); switch (c) { case '0': - return 0; + return BB_LOW; case '1': - return 1; + return BB_HIGH; default: remote_bitbang_quit(); - REMOTE_BITBANG_RAISE_ERROR( - "remote_bitbang: invalid read response: %c(%i)", c, c); + LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); + return BB_ERROR; + } +} + +/* Get the next read response. */ +static bb_value_t remote_bitbang_rread(void) +{ + if (EOF == fflush(remote_bitbang_file)) { + remote_bitbang_quit(); + LOG_ERROR("fflush: %s", strerror(errno)); + return BB_ERROR; + } + + /* Enable blocking access. */ + socket_block(remote_bitbang_fd); + char c; + ssize_t count = read(remote_bitbang_fd, &c, 1); + if (count == 1) { + return char_to_int(c); + } else { + remote_bitbang_quit(); + LOG_ERROR("read: count=%d, error=%s", (int) count, strerror(errno)); + return BB_ERROR; } } -static int remote_bitbang_read(void) +static int remote_bitbang_sample(void) { - remote_bitbang_putc('R'); + if (remote_bitbang_fill_buf() != ERROR_OK) + return ERROR_FAIL; + assert(!remote_bitbang_buf_full()); + return remote_bitbang_putc('R'); +} + +static bb_value_t remote_bitbang_read_sample(void) +{ + if (remote_bitbang_start != remote_bitbang_end) { + int c = remote_bitbang_buf[remote_bitbang_start]; + remote_bitbang_start = + (remote_bitbang_start + 1) % sizeof(remote_bitbang_buf); + return char_to_int(c); + } return remote_bitbang_rread(); } -static void remote_bitbang_write(int tck, int tms, int tdi) +static int remote_bitbang_write(int tck, int tms, int tdi) { char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); - remote_bitbang_putc(c); + return remote_bitbang_putc(c); } -static void remote_bitbang_reset(int trst, int srst) +static int remote_bitbang_reset(int trst, int srst) { char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); - remote_bitbang_putc(c); + return remote_bitbang_putc(c); } -static void remote_bitbang_blink(int on) +static int remote_bitbang_blink(int on) { char c = on ? 'B' : 'b'; - remote_bitbang_putc(c); + return remote_bitbang_putc(c); } static struct bitbang_interface remote_bitbang_bitbang = { - .read = &remote_bitbang_read, + .buf_size = sizeof(remote_bitbang_buf) - 1, + .sample = &remote_bitbang_sample, + .read_sample = &remote_bitbang_read_sample, .write = &remote_bitbang_write, .reset = &remote_bitbang_reset, .blink = &remote_bitbang_blink, @@ -131,7 +207,7 @@ static int remote_bitbang_init_tcp(void) { struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; struct addrinfo *result, *rp; - int fd; + int fd = 0; LOG_INFO("Connecting to %s:%s", remote_bitbang_host ? remote_bitbang_host : "localhost", @@ -199,29 +275,24 @@ static int remote_bitbang_init_unix(void) static int remote_bitbang_init(void) { - int fd; bitbang_interface = &remote_bitbang_bitbang; + remote_bitbang_start = 0; + remote_bitbang_end = 0; + LOG_INFO("Initializing remote_bitbang driver"); if (remote_bitbang_port == NULL) - fd = remote_bitbang_init_unix(); + remote_bitbang_fd = remote_bitbang_init_unix(); else - fd = remote_bitbang_init_tcp(); + remote_bitbang_fd = remote_bitbang_init_tcp(); - if (fd < 0) - return fd; - - remote_bitbang_in = fdopen(fd, "r"); - if (remote_bitbang_in == NULL) { - LOG_ERROR("fdopen: failed to open read stream"); - close(fd); - return ERROR_FAIL; - } + if (remote_bitbang_fd < 0) + return remote_bitbang_fd; - remote_bitbang_out = fdopen(fd, "w"); - if (remote_bitbang_out == NULL) { + remote_bitbang_file = fdopen(remote_bitbang_fd, "w+"); + if (remote_bitbang_file == NULL) { LOG_ERROR("fdopen: failed to open write stream"); - fclose(remote_bitbang_in); + close(remote_bitbang_fd); return ERROR_FAIL; } diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index b8acfa2f..5a4651df 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -244,7 +244,7 @@ static void sysfsgpio_swdio_write(int swclk, int swdio) * The sysfs value will read back either '0' or '1'. The trick here is to call * lseek to bypass buffering in the sysfs kernel driver. */ -static int sysfsgpio_read(void) +static bb_value_t sysfsgpio_read(void) { char buf[1]; @@ -257,7 +257,7 @@ static int sysfsgpio_read(void) return 0; } - return buf[0] != '0'; + return buf[0] == '0' ? BB_LOW : BB_HIGH; } /* @@ -266,11 +266,11 @@ static int sysfsgpio_read(void) * 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_write(int tck, int tms, int tdi) +static int sysfsgpio_write(int tck, int tms, int tdi) { if (swd_mode) { sysfsgpio_swdio_write(tck, tdi); - return; + return ERROR_OK; } const char one[] = "1"; @@ -312,6 +312,8 @@ static void sysfsgpio_write(int tck, int tms, int tdi) last_tdi = tdi; last_tms = tms; last_tck = tck; + + return ERROR_OK; } /* @@ -319,7 +321,7 @@ static void sysfsgpio_write(int tck, int tms, int tdi) * * (1) assert or (0) deassert reset lines */ -static void sysfsgpio_reset(int trst, int srst) +static int sysfsgpio_reset(int trst, int srst) { LOG_DEBUG("sysfsgpio_reset"); const char one[] = "1"; @@ -339,6 +341,8 @@ static void sysfsgpio_reset(int trst, int srst) if (bytes_written != 1) LOG_WARNING("writing trst failed"); } + + return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)