I know that's a lot to ask, but I was stucked in some bugs in my
driver.The driver is very simple, it saves the tms sequences, and send
whenever needed. It's about 500 lines, and it's very easy to be
understanded. My adapter side of code is also simple, it's about 100-200
lines. If you are familar with debugger driver. Please help me out. I'll
be very thankful.I can recognize my arm9ejs chip with my driver. But I
can't halt it. So this bug might be a subtle one.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/log.h>
#include <helper/binarybuffer.h>
#include <helper/command.h>
#include <jtag/interface.h>
#include "usb_common.h"
#define USBMZ_USB_VID 0xffff
#define USBMZ_USB_PID 0xffff
#define USBMZ_USB_BUFSIZE 64
#define USBMZ_USB_TIMEOUT 10000
#define USBMZ_USB_EP_WRITE 0x05
#define USBMZ_USB_EP_READ 0x85
#define USBMZ_CMD_UNKOWN 0x00
#define USBMZ_CMD_INIT 0x01
#define USBMZ_CMD_RESET 0x02
#define USBMZ_CMD_TMS 0x03
#define USBMZ_CMD_IO 0x04
#define USBMZ_CMD_STEP 0x05
#define USBMZ_IO_MODE_W 0x1
#define USBMZ_IO_MODE_R 0x2
#define USBMZ_IO_MODE_L 0x4
#define USBMZ_MAX_TMS_SIZE (USBMZ_USB_BUFSIZE - 3)
#define USBMZ_MAX_IO_SIZE (USBMZ_USB_BUFSIZE - 4)
static const uint16_t usbmz_vid[] = { 0xffff, 0 };
static const uint16_t usbmz_pid[] = { 0xffff, 0 };
struct usbmz_jtag {
struct usb_dev_handle *udev;
uint8_t buffer[USBMZ_USB_BUFSIZE];
int count;
uint8_t tms[USBMZ_MAX_TMS_SIZE];
uint16_t tms_nbits;
};
static struct usbmz_jtag usbmz_ins;
static int usbmz_usb_send(void);
static int usbmz_usb_recv(void);
static void usbmz_print_buf(const void *_buf, uint16_t nbits)
{
const uint8_t *buf = (const uint8_t *)_buf;
for (int i=0; i<nbits; i++)
{
int ibyte = i >> 3;
int ibit = i & 0b111;
int value = (buf[ibyte] >> ibit) & 0x1;
LOG_DEBUG("%d", value);
}
}
static int usbmz_commit_tms(void)
{
LOG_DEBUG("usbmz -> tms commit %d", usbmz_ins.tms_nbits);
// send tms
if (usbmz_ins.tms_nbits == 0)
return ERROR_OK;
usbmz_ins.buffer[0] = USBMZ_CMD_TMS;
usbmz_ins.buffer[1] = (uint8_t)(usbmz_ins.tms_nbits >> 8);
usbmz_ins.buffer[2] = (uint8_t)usbmz_ins.tms_nbits;
int count = DIV_ROUND_UP(usbmz_ins.tms_nbits, 8);
buf_set_buf(usbmz_ins.tms, 0,
usbmz_ins.buffer + 3, 0, usbmz_ins.tms_nbits);
usbmz_print_buf(usbmz_ins.buffer + 3, usbmz_ins.tms_nbits);
usbmz_ins.count = count + 3;
usbmz_ins.tms_nbits = 0;
assert(usbmz_ins.count > 0 ||
usbmz_ins.count <= USBMZ_USB_BUFSIZE);
int ret = usbmz_usb_send();
return ret;
}
static int usbmz_cache_tms(const uint8_t *tms, uint16_t nbits)
{
LOG_DEBUG("usbmz -> tms cache");
usbmz_print_buf(tms, nbits);
int bit_index=0;
while (nbits > 0)
{
uint32_t bsz = MIN(USBMZ_MAX_TMS_SIZE*8 - usbmz_ins.tms_nbits,
nbits);
buf_set_buf(tms, bit_index,
usbmz_ins.tms, usbmz_ins.tms_nbits, bsz);
nbits -= bsz;
bit_index += bsz;
usbmz_ins.tms_nbits += bsz;
if (usbmz_ins.tms_nbits == USBMZ_MAX_TMS_SIZE*8)
{
int ret = usbmz_commit_tms();
if (ret != ERROR_OK)
return ERROR_FAIL;
}
}
return ERROR_OK;
}
static int usbmz_pathmove(tap_state_t *path,
int num_states)
{
LOG_DEBUG("usbmz -> tms pathmove");
int tms = 0;
for (int i=0; i<num_states; i++)
{
if (tap_state_transition(tap_get_state(), 1)
== path[i])
tms |= (1 << i);
else if (tap_state_transition(tap_get_state(), 0)
== path[i])
tms &= ~(1 << i);
else
{
LOG_ERROR("usbmz -> can't transit from %s to %s",
tap_state_name(tap_get_state()),
tap_state_name(path[i]));
}
tap_set_state(path[i]);
}
int ret = usbmz_cache_tms((uint8_t *)&tms, num_states);
if (ret != ERROR_OK)
return ret;
tap_set_end_state(tap_get_state());
return ERROR_OK;
}
static int usbmz_statemove(tap_state_t new_state)
{
tap_set_end_state(new_state);
if (tap_get_end_state() == TAP_RESET)
{
LOG_DEBUG("usbmz -> transit from %s to %s",
tap_state_name(tap_get_state()),
tap_state_name(tap_get_end_state()));
int tms = 0xff;
int len = 7;
int ret = usbmz_cache_tms((uint8_t *)&tms, len);
if (ret != ERROR_OK)
return ret;
tap_set_state(tap_get_end_state());
}
else if (tap_get_state() != tap_get_end_state())
{
LOG_DEBUG("usbmz -> transit from %s to %s",
tap_state_name(tap_get_state()),
tap_state_name(tap_get_end_state()));
int tms = tap_get_tms_path(
tap_get_state(), new_state);
int len = tap_get_tms_path_len(
tap_get_state(), new_state);
int ret = usbmz_cache_tms((uint8_t *)&tms, len);
if (ret != ERROR_OK)
return ret;
tap_set_state(tap_get_end_state());
}
return ERROR_OK;
}
static int usbmz_tms(const uint8_t *tms, int num_bits)
{
int ret = usbmz_cache_tms(tms, num_bits);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
}
static int usbmz_scan(const struct scan_command *cmd)
{
int ret;
uint8_t *buffer;
enum scan_type type = jtag_scan_type(cmd);
int nbits;
bool ir_scan = cmd->ir_scan;
uint8_t mode;
tap_state_t end_state = cmd->end_state;
if (type == SCAN_OUT)
mode = USBMZ_IO_MODE_W;
else if (type == SCAN_IN)
mode = USBMZ_IO_MODE_R;
else if (type == SCAN_IO)
mode = USBMZ_IO_MODE_R | USBMZ_IO_MODE_W;
else
{
LOG_ERROR("usbmz -> wrong scan type");
return ERROR_FAIL;
}
LOG_DEBUG("usbmz -> scan mode %d", mode);
ret = usbmz_statemove(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
if (ret != ERROR_OK)
return ERROR_FAIL;
ret = usbmz_commit_tms();
if (ret != ERROR_OK)
return ERROR_FAIL;
nbits = jtag_build_buffer(cmd, &buffer);
if (buffer == NULL || nbits <= 0)
{
LOG_ERROR("usbmz -> fail to build scan buffer");
return ERROR_FAIL;
}
bool should_transfer = end_state != tap_get_state();
uint32_t bit_index = 0;
while (nbits > 0)
{
uint32_t bsz = MIN(USBMZ_MAX_IO_SIZE * 8, nbits);
usbmz_ins.count = 0;
usbmz_ins.buffer[usbmz_ins.count++] = USBMZ_CMD_IO;
usbmz_ins.buffer[usbmz_ins.count++] = (uint8_t)(bsz >> 8);
usbmz_ins.buffer[usbmz_ins.count++] = (uint8_t)bsz;
usbmz_ins.buffer[usbmz_ins.count++] =
mode | ((should_transfer && nbits == (int)bsz) ? USBMZ_IO_MODE_L : 0);
usbmz_ins.count += DIV_ROUND_UP(bsz, 8);
if (mode & USBMZ_IO_MODE_W)
{
buf_set_buf(buffer, bit_index,
usbmz_ins.buffer+4, 0, bsz);
}
if (usbmz_usb_send() != ERROR_OK)
return ERROR_FAIL;
if (mode & USBMZ_IO_MODE_R)
{
usleep(1);
if (usbmz_usb_recv() != ERROR_OK)
return ERROR_FAIL;
if (usbmz_ins.count != (int)DIV_ROUND_UP(bsz, 8)+4 ||
usbmz_ins.buffer[0] != USBMZ_CMD_IO ||
usbmz_ins.buffer[1] != (uint8_t)(bsz >> 8) ||
usbmz_ins.buffer[2] != (uint8_t)bsz)
{
LOG_ERROR("usbmz -> scan recv packet err");
return ERROR_FAIL;
}
buf_set_buf(usbmz_ins.buffer+4, 0,
buffer, bit_index, bsz);
}
nbits -= bsz;
bit_index += bsz;
}
//uint8_t tms = 0b01;
//ret = usbmz_cache_tms(&tms, 2);
//if (ret != ERROR_OK)
// return ret;
if (should_transfer)
{
if (ir_scan)
tap_set_state(TAP_IRPAUSE);
else
tap_set_state(TAP_DRPAUSE);
ret = usbmz_statemove(end_state);
if (ret != ERROR_OK)
{
free(buffer);
return ERROR_FAIL;
}
}
ret = jtag_read_buffer(buffer, cmd);
free(buffer);
return ret;
}
static int usbmz_stableclocks(int count)
{
if (!tap_is_state_stable(tap_get_state()))
{
LOG_ERROR("usbmz -> not stable current state (%s)",
tap_state_name(tap_get_state()));
return ERROR_FAIL;
}
uint32_t fill = 0;
if (tap_get_state() == TAP_RESET)
fill = ~fill;
while (count > 0)
{
int bsz = MIN(sizeof(uint8_t)*32, count);
int ret = usbmz_cache_tms((uint8_t *)&fill, bsz);
if (ret != ERROR_OK)
return ret;
count -= bsz;
}
return ERROR_OK;
}
static int usbmz_runtest(int num_cycles,
tap_state_t end_state)
{
if (usbmz_statemove(TAP_IDLE) != ERROR_OK)
return ERROR_FAIL;
if (usbmz_stableclocks(num_cycles) != ERROR_OK)
return ERROR_FAIL;
if (usbmz_statemove(end_state) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int usbmz_reset(int srst, int trst)
{
usbmz_commit_tms();
usbmz_ins.count = 0;
usbmz_ins.buffer[usbmz_ins.count++] = USBMZ_CMD_RESET;
usbmz_ins.buffer[usbmz_ins.count++] = srst;
usbmz_ins.buffer[usbmz_ins.count++] = trst;
if (usbmz_usb_send() != ERROR_OK)
return ERROR_FAIL;
if (usbmz_usb_recv() != ERROR_OK)
return ERROR_FAIL;
if (usbmz_ins.count != 3 ||
usbmz_ins.buffer[0] != USBMZ_CMD_RESET ||
usbmz_ins.buffer[1] || usbmz_ins.buffer[2])
return ERROR_FAIL;
return ERROR_OK;
}
static int usbmz_execute_queue(void)
{
struct jtag_command *cmd = jtag_command_queue;
int ret = ERROR_OK;
while (cmd && ret == ERROR_OK)
{
LOG_DEBUG("usbmz -> process (%d)", cmd->type);
switch (cmd->type)
{
case JTAG_SCAN:
ret = usbmz_scan(cmd->cmd.scan);
break;
case JTAG_TLR_RESET:
ret = usbmz_statemove(
cmd->cmd.statemove->end_state);
break;
case JTAG_RUNTEST:
ret = usbmz_runtest(cmd->cmd.runtest->num_cycles,
cmd->cmd.runtest->end_state);
break;
case JTAG_RESET:
ret = usbmz_reset(cmd->cmd.reset->srst,
cmd->cmd.reset->trst);
break;
case JTAG_PATHMOVE:
ret = usbmz_pathmove(cmd->cmd.pathmove->path,
cmd->cmd.pathmove->num_states);
break;
case JTAG_SLEEP:
ret = usbmz_commit_tms();
if (ret == ERROR_OK)
jtag_sleep(cmd->cmd.sleep->us);
break;
case JTAG_STABLECLOCKS:
ret = usbmz_stableclocks(
cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TMS:
ret = usbmz_tms(cmd->cmd.tms->bits,
cmd->cmd.tms->num_bits);
break;
default:
LOG_ERROR("usbmz -> unknown jtag cmd");
break;
}
cmd = cmd->next;
}
if (ret != ERROR_OK)
exit(-1);
ret = usbmz_commit_tms();
if (ret != ERROR_OK)
exit(-1);
return ret;
}
static int usbmz_usb_send(void)
{
int count;
if (usbmz_ins.count <= 0)
return ERROR_OK;
count = usb_bulk_write(usbmz_ins.udev,
USBMZ_USB_EP_WRITE, (char *)usbmz_ins.buffer,
usbmz_ins.count, USBMZ_USB_TIMEOUT);
if (count != usbmz_ins.count)
{
LOG_ERROR("usbmz -> write error");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int usbmz_usb_recv(void)
{
usbmz_ins.count = usb_bulk_read(usbmz_ins.udev,
USBMZ_USB_EP_READ, (char *)usbmz_ins.buffer,
USBMZ_USB_BUFSIZE, USBMZ_USB_TIMEOUT);
if (usbmz_ins.count < 2)
{
LOG_ERROR("usbmz -> read packet error");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int usbmz_init(void)
{
usb_init();
memset(&usbmz_ins, 0, sizeof(usbmz_ins));
if (jtag_usb_open(usbmz_vid, usbmz_pid,
&usbmz_ins.udev) != ERROR_OK)
{
LOG_ERROR("usbmz -> can't open usb dev");
return ERROR_FAIL;
}
usb_set_configuration(usbmz_ins.udev, 0);
usb_claim_interface(usbmz_ins.udev, 4);
usb_set_altinterface(usbmz_ins.udev, 0);
usbmz_ins.count = 0;
usbmz_ins.buffer[usbmz_ins.count++] = USBMZ_CMD_INIT;
if (usbmz_usb_send() != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int usbmz_quit(void)
{
return ERROR_OK;
}
static struct jtag_interface usbmz_interface = {
.execute_queue = usbmz_execute_queue,
};
struct adapter_driver usbmz_adapter_driver = {
.name = "usbmz",
.transports = jtag_only,
.init = usbmz_init,
.quit = usbmz_quit,
.jtag_ops = &usbmz_interface,
};
/*
code in adapter--->
case CMD_RESET:
// n_Srst _usb_buf[1]
if (_usb_buf[2] == 0) // n_Trst
platform_gpio_set(&_trst);
else
platform_gpio_clr(&_trst);
// if _usb_buf[1] set, return false
platform_gpio_clr(&_tck);
LL_mDelay(100);
_usb_buf[2] = 0;
send = 3;
break;
case CMD_TMS:
{
//printf("tms->\n");
uint16_t nbits = ((uint16_t)_usb_buf[1] << 8) +
_usb_buf[2];
platform_gpio_set(&_tdi);
for (int i=0; i<nbits; i++)
{
uint8_t ibyte = i >> 3;
uint8_t ibit = i & 0b111;
bool itms = (_usb_buf[3+ibyte] >> ibit) & 0x1;
//printf("%d", itms);
if (itms)
platform_gpio_set(&_tms);
else
platform_gpio_clr(&_tms);
platform_gpio_set(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
platform_gpio_clr(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
}
//printf("\n");
break;
}
case CMD_IO:
{
//printf("io->\n");
uint16_t nbits = ((uint16_t)_usb_buf[1] << 8) +
_usb_buf[2];
uint8_t mode = _usb_buf[3];
if (mode & CMD_IO_R)
send = len;
//printf("\n\e[1A");
platform_gpio_clr(&_tms);
for (int i=0; i<nbits; i++)
{
uint8_t ibyte = i >> 3;
uint8_t ibit = i & 0b111;
if (mode & CMD_IO_W)
{
bool itdi = (_usb_buf[4+ibyte] >> ibit) & 0x1;
if (itdi)
platform_gpio_set(&_tdi);
else
platform_gpio_clr(&_tdi);
//printf("%d\b", itdi);
}
if (i == nbits - 1 && (mode & CMD_IO_L))
platform_gpio_set(&_tms);
else
platform_gpio_clr(&_tms);
platform_gpio_set(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
if (mode & CMD_IO_R)
{
bool itdo = platform_gpio_get(&_tdo);
if (itdo)
_usb_buf[4+ibyte] |= 1 << ibit;
else
_usb_buf[4+ibyte] &= ~(1 << ibit);
//printf("\e[1B%d\e[1A\b", itdo);
}
//printf("\e[1C");
platform_gpio_clr(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
}
//printf("\n\n");
if (mode & CMD_IO_L)
{
platform_gpio_set(&_tdi);
platform_gpio_clr(&_tms);
platform_gpio_set(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
platform_gpio_clr(&_tck);
for (volatile int k=0; k<JTAG_DELAY; k++)
asm("nop");
}
break;
}
*/