diff options
author | Tim Newsome <tim@sifive.com> | 2017-10-09 11:06:20 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-09 11:06:20 -0700 |
commit | f06aaa9058b6f21ab83affbf5c56214eaa4e9992 (patch) | |
tree | 1bf4e75f2e97cd0c77fac94b58b40017c78bd09f | |
parent | ed415c3cb6d2df3de6650c2fb60160e47d78aeca (diff) | |
parent | 28eb10f43d513770224967fe7a73e98b498aa1a9 (diff) | |
download | riscv-openocd-f06aaa9058b6f21ab83affbf5c56214eaa4e9992.zip riscv-openocd-f06aaa9058b6f21ab83affbf5c56214eaa4e9992.tar.gz riscv-openocd-f06aaa9058b6f21ab83affbf5c56214eaa4e9992.tar.bz2 |
Merge pull request #123 from riscv/fast_rbb
Add read buffer to bitbang, improving performance.
-rw-r--r-- | src/jtag/drivers/bitbang.c | 43 | ||||
-rw-r--r-- | src/jtag/drivers/bitbang.h | 17 | ||||
-rw-r--r-- | src/jtag/drivers/remote_bitbang.c | 120 |
3 files changed, 147 insertions, 33 deletions
diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index c9ec9c9..4fdca79 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -185,10 +185,11 @@ static void bitbang_stableclocks(int num_cycles) } } -static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) +static void 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)) || @@ -202,8 +203,8 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int 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; @@ -219,16 +220,31 @@ static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int bitbang_interface->write(0, tms, tdi); - if (type != SCAN_OUT) - val = bitbang_interface->read(); + if (type != SCAN_OUT) { + if (bitbang_interface->buf_size) { + bitbang_interface->sample(); + buffered++; + } else { + int val = bitbang_interface->read(); + if (val) + buffer[bytec] |= bcval; + else + buffer[bytec] &= ~bcval; + } + } bitbang_interface->write(1, tms, tdi); - if (type != SCAN_OUT) { - if (val) - buffer[bytec] |= bcval; - else - buffer[bytec] &= ~bcval; + 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++) { + if (bitbang_interface->read_sample()) + buffer[i/8] |= 1 << (i % 8); + else + buffer[i/8] &= ~(1 << (i % 8)); + } + buffered = 0; } } @@ -309,13 +325,14 @@ int bitbang_execute_queue(void) bitbang_path_move(cmd->cmd.pathmove); 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 (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index c5b44bf..f0b9263 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -27,7 +27,24 @@ struct bitbang_interface { /* low level callbacks (for bitbang) */ + + /* Either read() or sample()/read_sample() must be implemented. */ + + /* Sample TDO and return 0 or 1. */ int (*read)(void); + + /* 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. */ + /* 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. */ + void (*sample)(void); + /* Return the next unread value from the buffer. */ + int (*read_sample)(void); + + /* Set TCK, TMS, and TDI to the given values. */ void (*write)(int tck, int tms, int tdi); void (*reset)(int trst, int srst); void (*blink)(int on); diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index b898e95..5e78ccb 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -40,8 +40,58 @@ static char *remote_bitbang_host; static char *remote_bitbang_port; -FILE *remote_bitbang_in; -FILE *remote_bitbang_out; +static FILE *remote_bitbang_in; +static FILE *remote_bitbang_out; +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)); +} + +/* Read any incoming data, placing it into the buffer. */ +static void remote_bitbang_fill_buf(void) +{ + fcntl(remote_bitbang_fd, F_SETFL, O_NONBLOCK); + 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; + // TODO: check for overflow. + if (remote_bitbang_end == sizeof(remote_bitbang_buf)) { + remote_bitbang_end = 0; + } + } else if (count == 0) { + return; + } else if (count < 0) { + if (errno == EAGAIN) { + return; + } else { + REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_fill_buf: %s (%d)", + strerror(errno), errno); + } + } + } +} static void remote_bitbang_putc(int c) { @@ -75,15 +125,8 @@ static int remote_bitbang_quit(void) return ERROR_OK; } -/* Get the next read response. */ -static int remote_bitbang_rread(void) +static int 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; @@ -96,9 +139,42 @@ static int remote_bitbang_rread(void) } } -static int remote_bitbang_read(void) +/* Get the next read response. */ +static int remote_bitbang_rread(void) { + if (EOF == fflush(remote_bitbang_out)) { + remote_bitbang_quit(); + REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno)); + } + + /* Enable blocking access. */ + fcntl(remote_bitbang_fd, F_SETFL, 0); + char c; + ssize_t count = read(remote_bitbang_fd, &c, 1); + if (count == 1) { + return char_to_int(c); + } else { + remote_bitbang_quit(); + REMOTE_BITBANG_RAISE_ERROR("read: count=%d, error=%s", (int) count, + strerror(errno)); + } +} + +static void remote_bitbang_sample(void) +{ + remote_bitbang_fill_buf(); + assert(!remote_bitbang_buf_full()); remote_bitbang_putc('R'); +} + +static int 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(); } @@ -121,7 +197,9 @@ static void remote_bitbang_blink(int on) } 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, @@ -199,26 +277,28 @@ 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; + if (remote_bitbang_fd < 0) + return remote_bitbang_fd; - remote_bitbang_in = fdopen(fd, "r"); + remote_bitbang_in = fdopen(remote_bitbang_fd, "r"); if (remote_bitbang_in == NULL) { LOG_ERROR("fdopen: failed to open read stream"); - close(fd); + close(remote_bitbang_fd); return ERROR_FAIL; } - remote_bitbang_out = fdopen(fd, "w"); + remote_bitbang_out = fdopen(remote_bitbang_fd, "w"); if (remote_bitbang_out == NULL) { LOG_ERROR("fdopen: failed to open write stream"); fclose(remote_bitbang_in); |