openocd/src/jtag/drivers/dummy.c
Tim Newsome 64f1f7b1c1 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>
2018-01-25 16:44:06 +00:00

164 lines
4.1 KiB
C

/***************************************************************************
* Copyright (C) 2008 by Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <jtag/interface.h>
#include "bitbang.h"
#include "hello.h"
/* my private tap controller state, which tracks state for calling code */
static tap_state_t dummy_state = TAP_RESET;
static int dummy_clock; /* edge detector */
static int clock_count; /* count clocks in any stable state, only stable states */
static uint32_t dummy_data;
static bb_value_t dummy_read(void)
{
int data = 1 & dummy_data;
dummy_data = (dummy_data >> 1) | (1 << 31);
return data ? BB_HIGH : BB_LOW;
}
static int dummy_write(int tck, int tms, int tdi)
{
/* TAP standard: "state transitions occur on rising edge of clock" */
if (tck != dummy_clock) {
if (tck) {
tap_state_t old_state = dummy_state;
dummy_state = tap_state_transition(old_state, tms);
if (old_state != dummy_state) {
if (clock_count) {
LOG_DEBUG("dummy_tap: %d stable clocks", clock_count);
clock_count = 0;
}
LOG_DEBUG("dummy_tap: %s", tap_state_name(dummy_state));
#if defined(DEBUG)
if (dummy_state == TAP_DRCAPTURE)
dummy_data = 0x01255043;
#endif
} else {
/* this is a stable state clock edge, no change of state here,
* simply increment clock_count for subsequent logging
*/
++clock_count;
}
}
dummy_clock = tck;
}
return ERROR_OK;
}
static int dummy_reset(int trst, int srst)
{
dummy_clock = 0;
if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
dummy_state = TAP_RESET;
LOG_DEBUG("reset to: %s", tap_state_name(dummy_state));
return ERROR_OK;
}
static int dummy_led(int on)
{
return ERROR_OK;
}
static struct bitbang_interface dummy_bitbang = {
.read = &dummy_read,
.write = &dummy_write,
.reset = &dummy_reset,
.blink = &dummy_led,
};
static int dummy_khz(int khz, int *jtag_speed)
{
if (khz == 0)
*jtag_speed = 0;
else
*jtag_speed = 64000/khz;
return ERROR_OK;
}
static int dummy_speed_div(int speed, int *khz)
{
if (speed == 0)
*khz = 0;
else
*khz = 64000/speed;
return ERROR_OK;
}
static int dummy_speed(int speed)
{
return ERROR_OK;
}
static int dummy_init(void)
{
bitbang_interface = &dummy_bitbang;
return ERROR_OK;
}
static int dummy_quit(void)
{
return ERROR_OK;
}
static const struct command_registration dummy_command_handlers[] = {
{
.name = "dummy",
.mode = COMMAND_ANY,
.help = "dummy interface driver commands",
.chain = hello_command_handlers,
},
COMMAND_REGISTRATION_DONE,
};
/* The dummy driver is used to easily check the code path
* where the target is unresponsive.
*/
struct jtag_interface dummy_interface = {
.name = "dummy",
.supported = DEBUG_CAP_TMS_SEQ,
.commands = dummy_command_handlers,
.transports = jtag_only,
.execute_queue = &bitbang_execute_queue,
.speed = &dummy_speed,
.khz = &dummy_khz,
.speed_div = &dummy_speed_div,
.init = &dummy_init,
.quit = &dummy_quit,
};