715 lines
18 KiB
C
715 lines
18 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/***************************************************************************
|
|
* Copyright (C) 2011 by Martin Schmoelzer *
|
|
* <martin.schmoelzer@student.tuwien.ac.at> *
|
|
***************************************************************************/
|
|
|
|
#include "jtag.h"
|
|
|
|
#include "io.h"
|
|
#include "msgtypes.h"
|
|
#include "common.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
/** Delay value for SCAN_IN operations with less than maximum TCK frequency */
|
|
uint8_t delay_scan_in;
|
|
|
|
/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */
|
|
uint8_t delay_scan_out;
|
|
|
|
/** Delay value for SCAN_IO operations with less than maximum TCK frequency */
|
|
uint8_t delay_scan_io;
|
|
|
|
/** Delay value for CLOCK_TCK operations with less than maximum frequency */
|
|
uint8_t delay_tck;
|
|
|
|
/** Delay value for CLOCK_TMS operations with less than maximum frequency */
|
|
uint8_t delay_tms;
|
|
|
|
/**
|
|
* Perform JTAG SCAN-IN operation at maximum TCK frequency.
|
|
*
|
|
* Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
|
|
* stored in the EP2 IN buffer.
|
|
*
|
|
* Maximum achievable TCK frequency is 182 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
* @param in_offset
|
|
*/
|
|
void jtag_scan_in(uint8_t out_offset, uint8_t in_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdo_data, i, j;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdo_data = 0;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
OUTB = outb_buffer; /* TCK changes here */
|
|
tdo_data = tdo_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
}
|
|
|
|
tdo_data = 0;
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TCK changes here */
|
|
tdo_data = tdo_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
tdo_data = tdo_data >> (8 - bits_last_byte);
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Perform JTAG SCAN-IN operation at variable TCK frequency.
|
|
*
|
|
* Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
|
|
* stored in the EP2 IN buffer.
|
|
*
|
|
* Maximum achievable TCK frequency is 113 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
* @param in_offset
|
|
*/
|
|
void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdo_data, i, j, k;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdo_data = 0;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
OUTB = outb_buffer; /* TCK changes here */
|
|
for (k = 0; k < delay_scan_in; k++)
|
|
;
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_in; k++)
|
|
;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
}
|
|
|
|
tdo_data = 0;
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TCK changes here */
|
|
for (k = 0; k < delay_scan_in; k++)
|
|
;
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_in; k++)
|
|
;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
tdo_data = tdo_data >> (8 - bits_last_byte);
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Perform JTAG SCAN-OUT operation at maximum TCK frequency.
|
|
*
|
|
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
|
* data is not sampled.
|
|
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
|
*
|
|
* Maximum achievable TCK frequency is 142 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
*/
|
|
void jtag_scan_out(uint8_t out_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdi_data, i, j;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
tdi_data = tdi_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
}
|
|
}
|
|
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
tdi_data = tdi_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
}
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Perform JTAG SCAN-OUT operation at maximum TCK frequency.
|
|
*
|
|
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
|
* data is not sampled.
|
|
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
|
*
|
|
* Maximum achievable TCK frequency is 97 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
*/
|
|
void jtag_slow_scan_out(uint8_t out_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdi_data, i, j, k;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
for (k = 0; k < delay_scan_out; k++)
|
|
;
|
|
tdi_data = tdi_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_out; k++)
|
|
;
|
|
}
|
|
}
|
|
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
for (k = 0; k < delay_scan_out; k++)
|
|
;
|
|
tdi_data = tdi_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_out; k++)
|
|
;
|
|
}
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
|
|
*
|
|
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
|
* data is sampled and stored in the EP2 IN buffer.
|
|
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
|
*
|
|
* Maximum achievable TCK frequency is 100 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
* @param in_offset
|
|
*/
|
|
void jtag_scan_io(uint8_t out_offset, uint8_t in_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdi_data, tdo_data, i, j;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
tdo_data = 0;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
tdi_data = tdi_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
}
|
|
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
tdo_data = 0;
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
tdi_data = tdi_data >> 1;
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
tdo_data = tdo_data >> (8 - bits_last_byte);
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
|
|
*
|
|
* Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
|
|
* data is sampled and stored in the EP2 IN buffer.
|
|
* The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state.
|
|
*
|
|
* Maximum achievable TCK frequency is 78 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param out_offset offset in OUT2BUF where payload data starts
|
|
* @param in_offset
|
|
*/
|
|
void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset)
|
|
{
|
|
uint8_t scan_size_bytes, bits_last_byte;
|
|
uint8_t tms_count_start, tms_count_end;
|
|
uint8_t tms_sequence_start, tms_sequence_end;
|
|
uint8_t tdi_data, tdo_data, i, j, k;
|
|
|
|
uint8_t outb_buffer;
|
|
|
|
/* Get parameters from OUT2BUF */
|
|
scan_size_bytes = OUT2BUF[out_offset];
|
|
bits_last_byte = OUT2BUF[out_offset + 1];
|
|
tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
|
|
tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
|
|
tms_sequence_start = OUT2BUF[out_offset + 3];
|
|
tms_sequence_end = OUT2BUF[out_offset + 4];
|
|
|
|
if (tms_count_start > 0)
|
|
jtag_slow_clock_tms(tms_count_start, tms_sequence_start);
|
|
|
|
outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
|
|
|
|
/* Shift all bytes except the last byte */
|
|
for (i = 0; i < scan_size_bytes - 1; i++) {
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
tdo_data = 0;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
for (k = 0; k < delay_scan_io; k++)
|
|
;
|
|
tdi_data = tdi_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_io; k++)
|
|
;
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
}
|
|
|
|
tdi_data = OUT2BUF[i + out_offset + 5];
|
|
tdo_data = 0;
|
|
|
|
/* Shift the last byte */
|
|
for (j = 0; j < bits_last_byte; j++) {
|
|
if (tdi_data & 0x01)
|
|
outb_buffer |= PIN_TDI;
|
|
else
|
|
outb_buffer &= ~PIN_TDI;
|
|
|
|
/* Assert TMS signal if requested and this is the last bit */
|
|
if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
|
|
outb_buffer |= PIN_TMS;
|
|
tms_count_end--;
|
|
tms_sequence_end = tms_sequence_end >> 1;
|
|
}
|
|
|
|
OUTB = outb_buffer; /* TDI and TCK change here */
|
|
for (k = 0; k < delay_scan_io; k++)
|
|
;
|
|
tdi_data = tdi_data >> 1;
|
|
|
|
OUTB = (outb_buffer | PIN_TCK);
|
|
for (k = 0; k < delay_scan_io; k++)
|
|
;
|
|
tdo_data = tdo_data >> 1;
|
|
|
|
if (GET_TDO())
|
|
tdo_data |= 0x80;
|
|
}
|
|
tdo_data = tdo_data >> (8 - bits_last_byte);
|
|
|
|
/* Copy TDO data to IN2BUF */
|
|
IN2BUF[i + in_offset] = tdo_data;
|
|
|
|
/* Move to correct end state */
|
|
if (tms_count_end > 0)
|
|
jtag_slow_clock_tms(tms_count_end, tms_sequence_end);
|
|
}
|
|
|
|
/**
|
|
* Generate TCK clock cycles.
|
|
*
|
|
* Maximum achievable TCK frequency is 375 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param count number of TCK clock cycles to generate.
|
|
*/
|
|
void jtag_clock_tck(uint16_t count)
|
|
{
|
|
uint16_t i;
|
|
uint8_t outb_buffer = OUTB & ~(PIN_TCK);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
OUTB = outb_buffer;
|
|
OUTB = outb_buffer | PIN_TCK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate TCK clock cycles at variable frequency.
|
|
*
|
|
* Maximum achievable TCK frequency is 166.6 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param count number of TCK clock cycles to generate.
|
|
*/
|
|
void jtag_slow_clock_tck(uint16_t count)
|
|
{
|
|
uint16_t i;
|
|
uint8_t j;
|
|
uint8_t outb_buffer = OUTB & ~(PIN_TCK);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
OUTB = outb_buffer;
|
|
for (j = 0; j < delay_tck; j++)
|
|
;
|
|
OUTB = outb_buffer | PIN_TCK;
|
|
for (j = 0; j < delay_tck; j++)
|
|
;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform TAP FSM state transitions at maximum TCK frequency.
|
|
*
|
|
* Maximum achievable TCK frequency is 176 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param count the number of state transitions to perform.
|
|
* @param sequence the TMS pin levels for each state transition, starting with
|
|
* the least-significant bit.
|
|
*/
|
|
void jtag_clock_tms(uint8_t count, uint8_t sequence)
|
|
{
|
|
uint8_t outb_buffer = OUTB & ~(PIN_TCK);
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
/* Set TMS pin according to sequence parameter */
|
|
if (sequence & 0x1)
|
|
outb_buffer |= PIN_TMS;
|
|
else
|
|
outb_buffer &= ~PIN_TMS;
|
|
|
|
OUTB = outb_buffer;
|
|
sequence = sequence >> 1;
|
|
OUTB = outb_buffer | PIN_TCK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform TAP-FSM state transitions at less than maximum TCK frequency.
|
|
*
|
|
* Maximum achievable TCK frequency is 117 kHz for ULINK clocked at 24 MHz.
|
|
*
|
|
* @param count the number of state transitions to perform.
|
|
* @param sequence the TMS pin levels for each state transition, starting with
|
|
* the least-significant bit.
|
|
*/
|
|
void jtag_slow_clock_tms(uint8_t count, uint8_t sequence)
|
|
{
|
|
uint8_t outb_buffer = OUTB & ~(PIN_TCK);
|
|
uint8_t i, j;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
/* Set TMS pin according to sequence parameter */
|
|
if (sequence & 0x1)
|
|
outb_buffer |= PIN_TMS;
|
|
else
|
|
outb_buffer &= ~PIN_TMS;
|
|
|
|
OUTB = outb_buffer;
|
|
for (j = 0; j < delay_tms; j++)
|
|
;
|
|
sequence = sequence >> 1;
|
|
OUTB = outb_buffer | PIN_TCK;
|
|
for (j = 0; j < delay_tms; j++)
|
|
;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current JTAG signal states.
|
|
*
|
|
* @return a 16-bit integer where the most-significant byte contains the state
|
|
* of the JTAG input signals and the least-significant byte contains the state
|
|
* of the JTAG output signals.
|
|
*/
|
|
uint16_t jtag_get_signals(void)
|
|
{
|
|
uint8_t input_signal_state, output_signal_state;
|
|
|
|
input_signal_state = 0;
|
|
output_signal_state = 0;
|
|
|
|
/* Get states of input pins */
|
|
if (GET_TDO())
|
|
input_signal_state |= SIGNAL_TDO;
|
|
if (GET_BRKOUT())
|
|
input_signal_state |= SIGNAL_BRKOUT;
|
|
if (GET_TRAP())
|
|
input_signal_state |= SIGNAL_TRAP;
|
|
if (GET_RTCK()) {
|
|
/* Using RTCK this way would be extremely slow,
|
|
* implemented only for the sake of completeness */
|
|
input_signal_state |= SIGNAL_RTCK;
|
|
}
|
|
|
|
/* Get states of output pins */
|
|
output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT;
|
|
|
|
return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state);
|
|
}
|
|
|
|
/**
|
|
* Set state of JTAG output signals.
|
|
*
|
|
* @param low signals which should be de-asserted.
|
|
* @param high signals which should be asserted.
|
|
*/
|
|
void jtag_set_signals(uint8_t low, uint8_t high)
|
|
{
|
|
OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT);
|
|
OUTB |= (high & MASK_PORTB_DIRECTION_OUT);
|
|
}
|
|
|
|
/**
|
|
* Configure TCK delay parameters.
|
|
*
|
|
* @param scan_in number of delay cycles in scan_in operations.
|
|
* @param scan_out number of delay cycles in scan_out operations.
|
|
* @param scan_io number of delay cycles in scan_io operations.
|
|
* @param tck number of delay cycles in clock_tck operations.
|
|
* @param tms number of delay cycles in clock_tms operations.
|
|
*/
|
|
void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out,
|
|
uint8_t scan_io, uint8_t tck, uint8_t tms)
|
|
{
|
|
delay_scan_in = scan_in;
|
|
delay_scan_out = scan_out;
|
|
delay_scan_io = scan_io;
|
|
delay_tck = tck;
|
|
delay_tms = tms;
|
|
}
|