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 <tim@sifive.com>
Reviewed-on: http://openocd.zylin.com/4312
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
This commit is contained in:
Tim Newsome 2017-12-13 13:13:22 -08:00 committed by Freddie Chopin
parent 2428722a23
commit 64f1f7b1c1
11 changed files with 371 additions and 166 deletions

View File

@ -199,6 +199,17 @@ static inline int close_socket(int sock)
#endif #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) static inline void socket_nonblock(int fd)
{ {
#ifdef _WIN32 #ifdef _WIN32

View File

@ -109,9 +109,9 @@ static uint32_t *pio_base;
/* low level command set /* low level command set
*/ */
static int at91rm9200_read(void); static bb_value_t at91rm9200_read(void);
static void at91rm9200_write(int tck, int tms, int tdi); static int at91rm9200_write(int tck, int tms, int tdi);
static void at91rm9200_reset(int trst, int srst); static int at91rm9200_reset(int trst, int srst);
static int at91rm9200_init(void); static int at91rm9200_init(void);
static int at91rm9200_quit(void); static int at91rm9200_quit(void);
@ -123,12 +123,12 @@ static struct bitbang_interface at91rm9200_bitbang = {
.blink = 0 .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) if (tck)
pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; 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; pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK;
else else
pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK;
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (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) if (trst == 0)
pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; 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; pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK;
else if (srst == 1) else if (srst == 1)
pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK;
return ERROR_OK;
} }
COMMAND_HANDLER(at91rm9200_handle_device_command) COMMAND_HANDLER(at91rm9200_handle_device_command)

View File

@ -49,9 +49,9 @@ uint32_t bcm2835_peri_base = 0x20000000;
static int dev_mem_fd; static int dev_mem_fd;
static volatile uint32_t *pio_base; static volatile uint32_t *pio_base;
static int bcm2835gpio_read(void); static bb_value_t bcm2835gpio_read(void);
static void bcm2835gpio_write(int tck, int tms, int tdi); static int bcm2835gpio_write(int tck, int tms, int tdi);
static void bcm2835gpio_reset(int trst, int srst); static int bcm2835gpio_reset(int trst, int srst);
static int bcm2835_swdio_read(void); static int bcm2835_swdio_read(void);
static void bcm2835_swdio_drive(bool is_output); static void bcm2835_swdio_drive(bool is_output);
@ -91,12 +91,12 @@ static int speed_coeff = 113714;
static int speed_offset = 28; static int speed_offset = 28;
static unsigned int jtag_delay; 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 set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
uint32_t clear = !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++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); 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 set = tck<<swclk_gpio | tdi<<swdio_gpio;
uint32_t clear = !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++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (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 set = 0;
uint32_t clear = 0; uint32_t clear = 0;
@ -138,6 +142,8 @@ static void bcm2835gpio_reset(int trst, int srst)
GPIO_SET = set; GPIO_SET = set;
GPIO_CLR = clear; GPIO_CLR = clear;
return ERROR_OK;
} }
static void bcm2835_swdio_drive(bool is_output) static void bcm2835_swdio_drive(bool is_output)

View 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 * this function checks the current stable state to decide on the value of TMS
* to use. * 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); 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 */ /* The bitbang driver leaves the TCK 0 when in idle */
static void bitbang_end_state(tap_state_t state) static void bitbang_end_state(tap_state_t state)
{ {
if (tap_is_state_stable(state)) assert(tap_is_state_stable(state));
tap_set_end_state(state); tap_set_end_state(state);
else {
LOG_ERROR("BUG: %i is not a valid end state", state);
exit(-1);
}
} }
static void bitbang_state_move(int skip) static int bitbang_state_move(int skip)
{ {
int i = 0, tms = 0; int i = 0, tms = 0;
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); 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++) { for (i = skip; i < tms_count; i++) {
tms = (tms_scan >> i) & 1; tms = (tms_scan >> i) & 1;
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); 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()); 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; int tms = 0;
for (unsigned i = 0; i < num_bits; i++) { for (unsigned i = 0; i < num_bits; i++) {
tms = ((bits[i/8] >> (i % 8)) & 1); tms = ((bits[i/8] >> (i % 8)) & 1);
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); 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; 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 num_states = cmd->num_states;
int state_count; int state_count;
@ -135,20 +138,24 @@ static void bitbang_path_move(struct pathmove_command *cmd)
exit(-1); exit(-1);
} }
bitbang_interface->write(0, tms, 0); if (bitbang_interface->write(0, tms, 0) != ERROR_OK)
bitbang_interface->write(1, tms, 0); return ERROR_FAIL;
if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
return ERROR_FAIL;
tap_set_state(cmd->path[state_count]); tap_set_state(cmd->path[state_count]);
state_count++; state_count++;
num_states--; 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()); 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; 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 */ /* only do a state_move when we're not already in IDLE */
if (tap_get_state() != TAP_IDLE) { if (tap_get_state() != TAP_IDLE) {
bitbang_end_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 */ /* execute num_cycles */
for (i = 0; i < num_cycles; i++) { for (i = 0; i < num_cycles; i++) {
bitbang_interface->write(0, 0, 0); if (bitbang_interface->write(0, 0, 0) != ERROR_OK)
bitbang_interface->write(1, 0, 0); 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 */ /* finish in end_state */
bitbang_end_state(saved_end_state); bitbang_end_state(saved_end_state);
if (tap_get_state() != tap_get_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 tms = (tap_get_state() == TAP_RESET ? 1 : 0);
int i; int i;
/* send num_cycles clocks onto the cable */ /* send num_cycles clocks onto the cable */
for (i = 0; i < num_cycles; i++) { for (i = 0; i < num_cycles; i++) {
bitbang_interface->write(1, tms, 0); if (bitbang_interface->write(1, tms, 0) != ERROR_OK)
bitbang_interface->write(0, tms, 0); 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(); tap_state_t saved_end_state = tap_get_end_state();
int bit_cnt; unsigned bit_cnt;
if (!((!ir_scan && if (!((!ir_scan &&
(tap_get_state() == TAP_DRSHIFT)) || (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 else
bitbang_end_state(TAP_DRSHIFT); 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); bitbang_end_state(saved_end_state);
} }
size_t buffered = 0;
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {
int val = 0;
int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tms = (bit_cnt == scan_size-1) ? 1 : 0;
int tdi; int tdi;
int bytec = bit_cnt/8; 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)) if ((type != SCAN_IN) && (buffer[bytec] & bcval))
tdi = 1; tdi = 1;
bitbang_interface->write(0, tms, tdi); if (bitbang_interface->write(0, tms, tdi) != ERROR_OK)
return ERROR_FAIL;
if (type != SCAN_OUT)
val = bitbang_interface->read();
bitbang_interface->write(1, tms, tdi);
if (type != SCAN_OUT) { if (type != SCAN_OUT) {
if (val) if (bitbang_interface->buf_size) {
buffer[bytec] |= bcval; if (bitbang_interface->sample() != ERROR_OK)
else return ERROR_FAIL;
buffer[bytec] &= ~bcval; 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 * the shift state, so we skip the first state
* and move directly to the end 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) int bitbang_execute_queue(void)
@ -259,8 +310,10 @@ int bitbang_execute_queue(void)
*/ */
retval = ERROR_OK; retval = ERROR_OK;
if (bitbang_interface->blink) if (bitbang_interface->blink) {
bitbang_interface->blink(1); if (bitbang_interface->blink(1) != ERROR_OK)
return ERROR_FAIL;
}
while (cmd) { while (cmd) {
switch (cmd->type) { switch (cmd->type) {
@ -273,7 +326,9 @@ int bitbang_execute_queue(void)
if ((cmd->cmd.reset->trst == 1) || if ((cmd->cmd.reset->trst == 1) ||
(cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
tap_set_state(TAP_RESET); 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; break;
case JTAG_RUNTEST: case JTAG_RUNTEST:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
@ -282,14 +337,16 @@ int bitbang_execute_queue(void)
tap_state_name(cmd->cmd.runtest->end_state)); tap_state_name(cmd->cmd.runtest->end_state));
#endif #endif
bitbang_end_state(cmd->cmd.runtest->end_state); 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; break;
case JTAG_STABLECLOCKS: case JTAG_STABLECLOCKS:
/* this is only allowed while in a stable state. A check for a stable /* this is only allowed while in a stable state. A check for a stable
* state was done in jtag_add_clocks() * 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; break;
case JTAG_TLR_RESET: case JTAG_TLR_RESET:
@ -298,7 +355,8 @@ int bitbang_execute_queue(void)
tap_state_name(cmd->cmd.statemove->end_state)); tap_state_name(cmd->cmd.statemove->end_state));
#endif #endif
bitbang_end_state(cmd->cmd.statemove->end_state); bitbang_end_state(cmd->cmd.statemove->end_state);
bitbang_state_move(0); if (bitbang_state_move(0) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_PATHMOVE: case JTAG_PATHMOVE:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
@ -306,18 +364,22 @@ int bitbang_execute_queue(void)
cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->num_states,
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
#endif #endif
bitbang_path_move(cmd->cmd.pathmove); if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK)
return ERROR_FAIL;
break; break;
case JTAG_SCAN: case JTAG_SCAN:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("%s scan end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR",
tap_state_name(cmd->cmd.scan->end_state));
#endif
bitbang_end_state(cmd->cmd.scan->end_state); bitbang_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
#ifdef _DEBUG_JTAG_IO_
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
type = jtag_scan_type(cmd->cmd.scan); 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) if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
retval = ERROR_JTAG_QUEUE_FAILED; retval = ERROR_JTAG_QUEUE_FAILED;
if (buffer) if (buffer)
@ -338,8 +400,10 @@ int bitbang_execute_queue(void)
} }
cmd = cmd->next; cmd = cmd->next;
} }
if (bitbang_interface->blink) if (bitbang_interface->blink) {
bitbang_interface->blink(0); if (bitbang_interface->blink(0) != ERROR_OK)
return ERROR_FAIL;
}
return retval; return retval;
} }

View File

@ -24,13 +24,35 @@
#include <jtag/swd.h> #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 { struct bitbang_interface {
/* low level callbacks (for bitbang) /** Sample TDO. */
*/ bb_value_t (*read)(void);
int (*read)(void);
void (*write)(int tck, int tms, int tdi); /** The number of TDO samples that can be buffered up before the caller has
void (*reset)(int trst, int srst); * to call read_sample. */
void (*blink)(int on); 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); int (*swdio_read)(void);
void (*swdio_drive)(bool on); void (*swdio_drive)(bool on);
}; };

View File

@ -33,14 +33,14 @@ static int clock_count; /* count clocks in any stable state, only stable states
static uint32_t dummy_data; static uint32_t dummy_data;
static int dummy_read(void) static bb_value_t dummy_read(void)
{ {
int data = 1 & dummy_data; int data = 1 & dummy_data;
dummy_data = (dummy_data >> 1) | (1 << 31); 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" */ /* TAP standard: "state transitions occur on rising edge of clock" */
if (tck != dummy_clock) { if (tck != dummy_clock) {
@ -69,9 +69,10 @@ static void dummy_write(int tck, int tms, int tdi)
} }
dummy_clock = tck; 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; dummy_clock = 0;
@ -79,10 +80,12 @@ static void dummy_reset(int trst, int srst)
dummy_state = TAP_RESET; dummy_state = TAP_RESET;
LOG_DEBUG("reset to: %s", tap_state_name(dummy_state)); 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 = { static struct bitbang_interface dummy_bitbang = {

View File

@ -41,9 +41,9 @@ static volatile uint8_t *gpio_data_direction_register;
/* low level command set /* low level command set
*/ */
static int ep93xx_read(void); static bb_value_t ep93xx_read(void);
static void ep93xx_write(int tck, int tms, int tdi); static int ep93xx_write(int tck, int tms, int tdi);
static void ep93xx_reset(int trst, int srst); static int ep93xx_reset(int trst, int srst);
static int ep93xx_init(void); static int ep93xx_init(void);
static int ep93xx_quit(void); static int ep93xx_quit(void);
@ -67,12 +67,12 @@ static struct bitbang_interface ep93xx_bitbang = {
.blink = 0, .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) if (tck)
output_value |= TCK_BIT; output_value |= TCK_BIT;
@ -91,10 +91,12 @@ static void ep93xx_write(int tck, int tms, int tdi)
*gpio_data_register = output_value; *gpio_data_register = output_value;
nanosleep(&ep93xx_zzzz, NULL); nanosleep(&ep93xx_zzzz, NULL);
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (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) if (trst == 0)
output_value |= TRST_BIT; output_value |= TRST_BIT;
@ -108,6 +110,8 @@ static void ep93xx_reset(int trst, int srst)
*gpio_data_register = output_value; *gpio_data_register = output_value;
nanosleep(&ep93xx_zzzz, NULL); nanosleep(&ep93xx_zzzz, NULL);
return ERROR_OK;
} }
static int set_gonk_mode(void) static int set_gonk_mode(void)

View File

@ -82,9 +82,9 @@ static inline bool gpio_level(int g)
return pio_base[g / 32].dr >> (g & 0x1F) & 1; return pio_base[g / 32].dr >> (g & 0x1F) & 1;
} }
static int imx_gpio_read(void); static bb_value_t imx_gpio_read(void);
static void imx_gpio_write(int tck, int tms, int tdi); static int imx_gpio_write(int tck, int tms, int tdi);
static void imx_gpio_reset(int trst, int srst); static int imx_gpio_reset(int trst, int srst);
static int imx_gpio_swdio_read(void); static int imx_gpio_swdio_read(void);
static void imx_gpio_swdio_drive(bool is_output); static void imx_gpio_swdio_drive(bool is_output);
@ -128,12 +128,12 @@ static int speed_coeff = 50000;
static int speed_offset = 100; static int speed_offset = 100;
static unsigned int jtag_delay; 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); tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio);
tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_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++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); 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); tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio);
tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio); tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio);
for (unsigned int i = 0; i < jtag_delay; i++) for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile (""); asm volatile ("");
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (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) if (trst_gpio != -1)
trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio); trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio);
if (srst_gpio != -1) if (srst_gpio != -1)
srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio); srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio);
return ERROR_OK;
} }
static void imx_gpio_swdio_drive(bool is_output) 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", 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, pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_SHARED, dev_mem_fd, imx_gpio_peri_base); MAP_SHARED, dev_mem_fd, imx_gpio_peri_base);

View File

@ -116,7 +116,7 @@ static unsigned long dataport;
static unsigned long statusport; static unsigned long statusport;
#endif #endif
static int parport_read(void) static bb_value_t parport_read(void)
{ {
int data = 0; int data = 0;
@ -127,9 +127,9 @@ static int parport_read(void)
#endif #endif
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
return 1; return BB_HIGH;
else else
return 0; return BB_LOW;
} }
static inline void parport_write_data(void) static inline void parport_write_data(void)
@ -148,7 +148,7 @@ static inline void parport_write_data(void)
#endif #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; int i = wait_states + 1;
@ -169,10 +169,12 @@ static void parport_write(int tck, int tms, int tdi)
while (i-- > 0) while (i-- > 0)
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
/* (1) assert or (0) deassert reset lines */ /* (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); 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; dataport_value &= ~cable->SRST_MASK;
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
/* turn LED on parport adapter on (1) or off (0) */ /* turn LED on parport adapter on (1) or off (0) */
static void parport_led(int on) static int parport_led(int on)
{ {
if (on) if (on)
dataport_value |= cable->LED_MASK; dataport_value |= cable->LED_MASK;
@ -198,6 +202,8 @@ static void parport_led(int on)
dataport_value &= ~cable->LED_MASK; dataport_value &= ~cable->LED_MASK;
parport_write_data(); parport_write_data();
return ERROR_OK;
} }
static int parport_speed(int speed) static int parport_speed(int speed)
@ -365,9 +371,12 @@ static int parport_init(void)
#endif /* PARPORT_USE_PPDEV */ #endif /* PARPORT_USE_PPDEV */
parport_reset(0, 0); if (parport_reset(0, 0) != ERROR_OK)
parport_write(0, 0, 0); return ERROR_FAIL;
parport_led(1); if (parport_write(0, 0, 0) != ERROR_OK)
return ERROR_FAIL;
if (parport_led(1) != ERROR_OK)
return ERROR_FAIL;
bitbang_interface = &parport_bitbang; bitbang_interface = &parport_bitbang;
@ -376,7 +385,8 @@ static int parport_init(void)
static int parport_quit(void) static int parport_quit(void)
{ {
parport_led(0); if (parport_led(0) != ERROR_OK)
return ERROR_FAIL;
if (parport_exit) { if (parport_exit) {
dataport_value = cable->PORT_EXIT; dataport_value = cable->PORT_EXIT;

View File

@ -30,40 +30,86 @@
/* arbitrary limit on host name length: */ /* arbitrary limit on host name length: */
#define REMOTE_BITBANG_HOST_MAX 255 #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_host;
static char *remote_bitbang_port; static char *remote_bitbang_port;
FILE *remote_bitbang_in; static FILE *remote_bitbang_file;
FILE *remote_bitbang_out; static int remote_bitbang_fd;
static void remote_bitbang_putc(int c) /* 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)
{ {
if (EOF == fputc(c, remote_bitbang_out)) return remote_bitbang_end ==
REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno)); ((remote_bitbang_start + sizeof(remote_bitbang_buf) - 1) %
sizeof(remote_bitbang_buf));
}
/* Read any incoming data, placing it into the buffer. */
static int remote_bitbang_fill_buf(void)
{
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) 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)); LOG_ERROR("fputs: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
if (EOF == fflush(remote_bitbang_out)) { if (EOF == fflush(remote_bitbang_file)) {
LOG_ERROR("fflush: %s", strerror(errno)); LOG_ERROR("fflush: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
/* We only need to close one of the FILE*s, because they both use the same */ /* We only need to close one of the FILE*s, because they both use the same */
/* underlying file descriptor. */ /* underlying file descriptor. */
if (EOF == fclose(remote_bitbang_out)) { if (EOF == fclose(remote_bitbang_file)) {
LOG_ERROR("fclose: %s", strerror(errno)); LOG_ERROR("fclose: %s", strerror(errno));
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -75,53 +121,83 @@ static int remote_bitbang_quit(void)
return ERROR_OK; return ERROR_OK;
} }
/* Get the next read response. */ static bb_value_t char_to_int(int c)
static int remote_bitbang_rread(void)
{ {
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) { switch (c) {
case '0': case '0':
return 0; return BB_LOW;
case '1': case '1':
return 1; return BB_HIGH;
default: default:
remote_bitbang_quit(); remote_bitbang_quit();
REMOTE_BITBANG_RAISE_ERROR( LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c);
"remote_bitbang: invalid read response: %c(%i)", c, c); return BB_ERROR;
} }
} }
static int remote_bitbang_read(void) /* Get the next read response. */
static bb_value_t remote_bitbang_rread(void)
{ {
remote_bitbang_putc('R'); 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_sample(void)
{
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(); 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)); 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)); 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'; char c = on ? 'B' : 'b';
remote_bitbang_putc(c); return remote_bitbang_putc(c);
} }
static struct bitbang_interface remote_bitbang_bitbang = { 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, .write = &remote_bitbang_write,
.reset = &remote_bitbang_reset, .reset = &remote_bitbang_reset,
.blink = &remote_bitbang_blink, .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 hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM };
struct addrinfo *result, *rp; struct addrinfo *result, *rp;
int fd; int fd = 0;
LOG_INFO("Connecting to %s:%s", LOG_INFO("Connecting to %s:%s",
remote_bitbang_host ? remote_bitbang_host : "localhost", remote_bitbang_host ? remote_bitbang_host : "localhost",
@ -199,29 +275,24 @@ static int remote_bitbang_init_unix(void)
static int remote_bitbang_init(void) static int remote_bitbang_init(void)
{ {
int fd;
bitbang_interface = &remote_bitbang_bitbang; bitbang_interface = &remote_bitbang_bitbang;
remote_bitbang_start = 0;
remote_bitbang_end = 0;
LOG_INFO("Initializing remote_bitbang driver"); LOG_INFO("Initializing remote_bitbang driver");
if (remote_bitbang_port == NULL) if (remote_bitbang_port == NULL)
fd = remote_bitbang_init_unix(); remote_bitbang_fd = remote_bitbang_init_unix();
else else
fd = remote_bitbang_init_tcp(); remote_bitbang_fd = remote_bitbang_init_tcp();
if (fd < 0) if (remote_bitbang_fd < 0)
return fd; return remote_bitbang_fd;
remote_bitbang_in = fdopen(fd, "r"); remote_bitbang_file = fdopen(remote_bitbang_fd, "w+");
if (remote_bitbang_in == NULL) { if (remote_bitbang_file == NULL) {
LOG_ERROR("fdopen: failed to open read stream");
close(fd);
return ERROR_FAIL;
}
remote_bitbang_out = fdopen(fd, "w");
if (remote_bitbang_out == NULL) {
LOG_ERROR("fdopen: failed to open write stream"); LOG_ERROR("fdopen: failed to open write stream");
fclose(remote_bitbang_in); close(remote_bitbang_fd);
return ERROR_FAIL; return ERROR_FAIL;
} }

View 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 * 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. * lseek to bypass buffering in the sysfs kernel driver.
*/ */
static int sysfsgpio_read(void) static bb_value_t sysfsgpio_read(void)
{ {
char buf[1]; char buf[1];
@ -257,7 +257,7 @@ static int sysfsgpio_read(void)
return 0; 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, * Seeing as this is the only function where the outputs are changed,
* we can cache the old value to avoid needlessly writing it. * 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) { if (swd_mode) {
sysfsgpio_swdio_write(tck, tdi); sysfsgpio_swdio_write(tck, tdi);
return; return ERROR_OK;
} }
const char one[] = "1"; const char one[] = "1";
@ -312,6 +312,8 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
last_tdi = tdi; last_tdi = tdi;
last_tms = tms; last_tms = tms;
last_tck = tck; 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 * (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"); LOG_DEBUG("sysfsgpio_reset");
const char one[] = "1"; const char one[] = "1";
@ -339,6 +341,8 @@ static void sysfsgpio_reset(int trst, int srst)
if (bytes_written != 1) if (bytes_written != 1)
LOG_WARNING("writing trst failed"); LOG_WARNING("writing trst failed");
} }
return ERROR_OK;
} }
COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums) COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)