Add read buffer to bitbang, improving performance. 12/4312/9
authorTim Newsome <tim@sifive.com>
Wed, 13 Dec 2017 21:13:22 +0000 (13:13 -0800)
committerFreddie Chopin <freddie.chopin@gmail.com>
Thu, 25 Jan 2018 16:44:06 +0000 (16:44 +0000)
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 <tim@sifive.com>
Reviewed-on: http://openocd.zylin.com/4312
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
src/helper/replacements.h
src/jtag/drivers/at91rm9200.c
src/jtag/drivers/bcm2835gpio.c
src/jtag/drivers/bitbang.c
src/jtag/drivers/bitbang.h
src/jtag/drivers/dummy.c
src/jtag/drivers/ep93xx.c
src/jtag/drivers/imx_gpio.c
src/jtag/drivers/parport.c
src/jtag/drivers/remote_bitbang.c
src/jtag/drivers/sysfsgpio.c

index 1e2fbf2..f43b7e0 100644 (file)
@@ -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
index 8f65413..0015da0 100644 (file)
@@ -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)
index a4d0a1c..38ef163 100644 (file)
@@ -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<<tdo_gpio);
+       return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
 }
 
-static void bcm2835gpio_write(int tck, int tms, int tdi)
+static int bcm2835gpio_write(int tck, int tms, int tdi)
 {
        uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
        uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
@@ -106,9 +106,11 @@ static void bcm2835gpio_write(int tck, int tms, int tdi)
 
        for (unsigned int i = 0; i < jtag_delay; i++)
                asm volatile ("");
+
+       return ERROR_OK;
 }
 
-static void bcm2835gpio_swd_write(int tck, int tms, int tdi)
+static int bcm2835gpio_swd_write(int tck, int tms, int tdi)
 {
        uint32_t set = tck<<swclk_gpio | tdi<<swdio_gpio;
        uint32_t clear = !tck<<swclk_gpio | !tdi<<swdio_gpio;
@@ -118,10 +120,12 @@ static void bcm2835gpio_swd_write(int tck, int tms, int tdi)
 
        for (unsigned int i = 0; i < jtag_delay; i++)
                asm volatile ("");
+
+       return ERROR_OK;
 }
 
 /* (1) assert or (0) deassert reset lines */
-static void bcm2835gpio_reset(int trst, int srst)
+static int bcm2835gpio_reset(int trst, int srst)
 {
        uint32_t set = 0;
        uint32_t clear = 0;
@@ -138,6 +142,8 @@ static void bcm2835gpio_reset(int trst, int srst)
 
        GPIO_SET = set;
        GPIO_CLR = clear;
+
+       return ERROR_OK;
 }
 
 static void bcm2835_swdio_drive(bool is_output)
index c9ec9c9..722a5f2 100644 (file)
@@ -41,7 +41,7 @@ extern struct jtag_interface *jtag_interface;
  * this function checks the current stable state to decide on the value of TMS
  * to use.
  */
-static void bitbang_stableclocks(int num_cycles);
+static int bitbang_stableclocks(int num_cycles);
 
 static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk);
 
@@ -70,15 +70,11 @@ struct bitbang_interface *bitbang_interface;
 /* The bitbang driver leaves the TCK 0 when in idle */
 static void bitbang_end_state(tap_state_t state)
 {
-       if (tap_is_state_stable(state))
-               tap_set_end_state(state);
-       else {
-               LOG_ERROR("BUG: %i is not a valid end state", state);
-               exit(-1);
-       }
+       assert(tap_is_state_stable(state));
+       tap_set_end_state(state);
 }
 
-static void bitbang_state_move(int skip)
+static int bitbang_state_move(int skip)
 {
        int i = 0, tms = 0;
        uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
@@ -86,12 +82,16 @@ static void bitbang_state_move(int skip)
 
        for (i = skip; i < tms_count; i++) {
                tms = (tms_scan >> 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;
 }
index c5b44bf..577717e 100644 (file)
 
 #include <jtag/swd.h>
 
+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);
 };
index 0f7c12d..db1ba13 100644 (file)
@@ -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 = {
index ccd9795..36fc777 100644 (file)
@@ -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)
index f33d109..2a822af 100644 (file)
@@ -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);
index c9e3316..14fa9df 100644 (file)
@@ -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;
index c8d0136..1f8fc1a 100644 (file)
 /* 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;
        }
 
index b8acfa2..5a4651d 100644 (file)
@@ -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)