/* * Copyright (C) 2004-2007 by egnite Software GmbH * Copyright (C) 2008 by egnite GmbH * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * and Xilinx Application Note XAPP058. */ /* * $Log$ * Revision 1.1 2008/10/20 13:10:05 haraldkipp * Checked in. * */ #ifdef _MSC_VER #include #endif #include "xsvf.h" #include "host.h" #include "tapsm.h" #include /*! * \file xsvfexec.c * * \brief Executor main file. */ /*! * \addtogroup xgBitString */ /*@{*/ /*! * \brief Compare two bit string using an optional bit mask. * * \param len Number of bits in the bit strings. * \param op1 Pointer to the first bit string. * \param op2 Pointer to the second bit string. * \param mask Pointer to the mask. Bits are compared only if the corresponding * bit in the mask is set. If this pointer is set to NULL, all * bits will be compared. * * \return 0 if equal, 1 otherwise. */ static int BitStringCmp(int len, uint8_t *op1, uint8_t *op2, uint8_t *mask) { int rc = 0; #if !defined(_WIN32) int i; uint8_t diff; for (i = 0; i < len; i += 8) { diff = *op1++ ^ *op2++; if (mask) { diff &= *mask++; } if (diff) { rc = 1; break; } } #endif return rc; } /*! * \brief Numeric addition of two bit string. * * \param len Number of bits in the bit strings. * \param op1 Pointer to the first bit string, which will also receive * the final result. * \param op2 Pointer to the second bit string. Will be added to the first. */ static void BitStringAdd(int len, uint8_t *op1, uint8_t *op2) { int i; uint16_t sum; uint8_t ovr = 0; i = (int)((len + 7UL) / 8UL); while (i--) { if((sum = (uint16_t)((uint16_t)op1[i] + (uint16_t)op2[i] + ovr)) > (uint16_t)255) { ovr = 1; } else { ovr = 0; } op1[i] = (uint8_t)sum; } } /*! * \brief Count the number of bits set to one in a bit string. * * \param len Number of bits in the bit string. * \param op Pointer to the bit string. * * \return The number of bits set to one. */ static int BitStringOnes(int len, uint8_t *op) { int rc = 0; uint8_t mask; int i = (int)((len + 7UL) / 8UL); while (i--) { for(mask = op[i]; mask; mask >>= 1) { rc += mask & 1; } } return rc; } /*@}*/ /*! * \addtogroup xgXsvfExec */ /*@{*/ /*! * \brief Prepare the next TDI value for iterating XSDR. * * \param len Number of bits in the first TDI value. * \param tdi_val First TDI value, the one which will be updated. * \param len2 Number of bits in the second TDI value. * \param tdi_val2 Second TDI value. * \param data_mask The data mask used for the update. */ static void UpdateTdi(int len, uint8_t *tdi_val, int len2, uint8_t *tdi_val2, uint8_t *data_mask) { uint8_t tdibit; uint8_t mask; int i; uint8_t d = 0; uint8_t m = 0; for (i = len - 1; i >= 0; --i) { mask = data_mask[i]; if (mask) { tdibit = 1; while (mask) { if (mask & 1) { if (m == 0) { d = tdi_val2[--len2]; m = 1; } if (d & m) { tdi_val[i] |= tdibit; } else { tdi_val[i] &= ~tdibit; } m <<= 1; } tdibit <<= 1; mask >>= 1; } } } } /*! * \brief Repeat shifting out a TDI value until an expected TDO value appears. * * \param len Number of bits to shift. * \param tdi_val TDI value to shift out. * \param tdo_exp Expected TDO value. Set to NULL if not available. * \param tdo_msk Used to mask out don't care TDO values. * \param sState TAP state during shift operation, either SHIFT-DR or SHIFT-IR. No * retries are allowed with SHIFT-IR. * \param eState TAP state after shift operation. * \param delay Idle time (in microseconds) after each shift. * \param retries Maximum number of retries. Ignored if expected TDO value is not available. * * \return Zero on success, otherwise an error code is returned. */ static int ReShift(int len, uint8_t *tdi_val, uint8_t *tdo_exp, uint8_t *tdo_msk, uint8_t sState, uint8_t eState, long delay, uint8_t retries) { int rc = 0; uint8_t tdo_val[MAX_BITVEC_BYTES]; if (len == 0) { if (delay) { TapStateChange(RUN_TEST_IDLE); XsvfDelay(delay); } } else { int last_byte = (int)((len + 7UL) / 8UL - 1UL); /* * Retry loop. */ do { uint8_t *tdi = &tdi_val[last_byte]; uint8_t *tdo = &tdo_val[last_byte]; int bitcnt; uint8_t bitmsk; TapStateChange(sState); /* * Byte loop. */ for(bitcnt = len; bitcnt;) { *tdo = 0; /* * Bit loop. LSB is shifted first. */ for (bitmsk = 1; bitmsk && bitcnt; bitmsk <<= 1) { if (sState != eState && bitcnt == 1) { /* Exit Shift state with last bit. */ SET_TMS(); TapStateInc(); } /* Shift TDI in and TDO out. */ if(*tdi & bitmsk) { SET_TDI(); } else { CLR_TDI(); } CLR_TCK(); /* * This is time critical, because TDO may be delayed. * The following decrement of our int value consumes * some CPU cycles. */ bitcnt--; if(GET_TDO()) { *tdo |= bitmsk; } SET_TCK(); } tdi--; tdo--; } /* * Compare captured with expected TDO result. */ if (tdo_exp) { if(BitStringCmp(len, tdo_exp, tdo_val, tdo_msk)) { rc = XE_TDOMISMATCH; } else { rc = 0; } } /* * Update TAP controller state. */ if (sState != eState) { if (rc && delay && retries) { /* The TDO value does not match the expected value. */ TapStateChange(PAUSE_DR); TapStateChange(SHIFT_DR); } else { TapStateChange(eState); } /* * If the XRUNTEST time is non-zero, go to the Run-Test/Idle state * and wait for the specified number of microseconds. */ if (delay) { TapStateChange(RUN_TEST_IDLE); XsvfDelay(delay); /* In case of another retry, increase idle time by 25%. */ delay += (delay >> 2); } } } while (rc && retries--); } return rc; } /*! * \brief Shift next TDI value out and optionally capture TDO value. * * No delays and no retries are performed. * * \param len Number of bits to shift. * \param tdi_val Pointer to TDI value buffer. * \param tdo_exp Pointer to expected TDO value buffer. If NULL, no TDO value will * be read from the XSVF buffer and no comparision will take place. * \param sState TAP state during shift operation, either SHIFT-DR or SHIFT-IR. * \param eState TAP state after shift operation. * * \return Zero on success, otherwise an error code is returned. */ static int Shift(int len, uint8_t *tdi_val, uint8_t *tdo_exp, uint8_t sState, uint8_t eState) { XsvfReadBitString(tdi_val, len); if(tdo_exp) { XsvfReadBitString(tdo_exp, len); } return ReShift(len, tdi_val, tdo_exp, 0, sState, eState, 0, 0); } /*! * \brief TDI value buffer. */ static uint8_t tdiVal[MAX_BITVEC_BYTES]; /*! * \brief TDI value 2 buffer. */ static uint8_t tdiVal2[MAX_BITVEC_BYTES]; /*! * \brief Expected TDO value buffer. */ static uint8_t tdoExp[MAX_BITVEC_BYTES]; /*! * \brief TDO mask buffer. */ static uint8_t tdoMask[MAX_BITVEC_BYTES]; /*! * \brief Data mask buffer. */ static uint8_t dataMask[MAX_BITVEC_BYTES]; /*! * \brief Address mask buffer. */ static uint8_t addrMask[MAX_BITVEC_BYTES]; /*! * \brief Execute an XSVF buffer. * * This routine interprets a compressed SVF command sequence following * the Xilinx application note XAPP503. * * \return Zero on success, otherwise an error code is returned. */ static int Execute(void) { int rc = 0; uint8_t cmd; uint8_t endIr = RUN_TEST_IDLE; uint8_t endDr = RUN_TEST_IDLE; uint8_t retries = DEFAULT_REPEAT; long delay = 0; int drSize = 0; int drSize2 = 0; int irSize; TapStateInit(); /* Process the XSVF commands */ while (rc == 0) { cmd = XsvfGetCmd(); if(cmd == XCOMPLETE) { /* * Normal end of the XSVF buffer reached. */ break; } switch(cmd) { case XTDOMASK: /* * Set the TDO mask. Length has been specified by the last XSDRSIZE command. */ XsvfReadBitString(tdoMask, drSize); break; case XRUNTEST: /* * Set the number of microseconds the device should stay in the Run-Test-Idle * state after each visit to the SDR state. */ delay = XsvfGetLong(); break; case XREPEAT: /* * Set the number of times that TDO is tested against the expected value before * the programming operation is considered a failure. */ retries = XsvfGetByte(); break; case XSDRSIZE: /* * Set the length of the next XSDR/XSDRTDO records that follow. */ drSize = (int)XsvfGetLong(); if ((drSize + 7) / 8 > MAX_BITVEC_BYTES) { rc = XE_DATAOVERFLOW; } break; case XSIR: case XSIR2: /* * Go to the Shift-IR state and shift in the TDI value. XSIR uses * a single byte for the TDI size, while XSIR2 uses two bytes. */ if(cmd == XSIR) { irSize = XsvfGetByte(); } else { irSize = XsvfGetShort(); } XsvfReadBitString(tdiVal, irSize); rc = ReShift(irSize, tdiVal, 0, 0, SHIFT_IR, endIr, delay, 0); break; case XSDRTDO: /* * Go to the Shift-DR state and shift in the TDI value; compare the expected * value against the TDO value that was shifted out. Use the TDO mask which * was generated by the last XTDOMASK command. * * The expected TDO value is re-used in successive XSDR commands. */ XsvfReadBitString(tdiVal, drSize); XsvfReadBitString(tdoExp, drSize); rc = ReShift(drSize, tdiVal, tdoExp, tdoMask, SHIFT_DR, endDr, delay, retries); break; case XSDR: /* * Go to the Shift-DR state and shift in the TDI value; compare the expected * value from the last XSDRTDO command against the TDO value that was * shifted out. Use the TDO mask which was generated by the last XTDOMASK * instruction. */ XsvfReadBitString(tdiVal, drSize); rc = ReShift(drSize, tdiVal, tdoExp, tdoMask, SHIFT_DR, endDr, delay, retries); break; case XSDRB: case XSDRC: /* * Go to the Shift-DR state and shift in the TDI value. No comparison of TDO * value with the last specified expected value is performed. */ rc = Shift(drSize, tdiVal, 0, SHIFT_DR, SHIFT_DR); break; case XSDRE: /* * Continue to stay in Shift-DR state and shift in the TDI value. At the end * of the operation, go to the state specified in the last XENDDR command. No * comparison of TDO value with the last specified expected value is performed. */ rc = Shift(drSize, tdiVal, 0, SHIFT_DR, endDr); break; case XSDRTDOB: case XSDRTDOC: /* * Go to the Shift-DR state and shift in the TDI value. Compare all bits of the * expected value against the TDO value that is shifted out. No retries are * performed. */ rc = Shift(drSize, tdiVal, tdoExp, SHIFT_DR, SHIFT_DR); break; case XSDRTDOE: /* * Continue to stay in Shift-DR state and shift in the TDI value. Compare all * bits of the expected value against the TDO value that is shifted out. At the * end of the operation, go to the state specified in the last XENDDR command. * No retries are performed. */ rc = Shift(drSize, tdiVal, tdoExp, SHIFT_DR, endDr); break; case XSTATE: /* * Immediately set the TAP controller to Test-Logic-Reset (0) or Run-Test_idle (1). */ rc = TapStateChange(XsvfGetState(TEST_LOGIC_RESET, RUN_TEST_IDLE)); break; case XENDIR: /* * Set the XSIR end state to Run-Test-Idle (0) or Pause-IR (1). */ endIr = XsvfGetState(RUN_TEST_IDLE, PAUSE_IR); break; case XENDDR: /* * Set the XSDR/XSDRTDO end state to Run-Test-Idle (0) or Pause-DR (1). */ endDr = XsvfGetState(RUN_TEST_IDLE, PAUSE_DR); break; case XSETSDRMASKS: /* * Set SDR address and data masks for interatin XSDR commands. */ XsvfReadBitString(addrMask, drSize); XsvfReadBitString(dataMask, drSize); drSize2 = BitStringOnes(drSize, dataMask); break; case XSDRINC: /* * Do iterating XSDR commands. */ XsvfReadBitString(tdiVal, drSize); rc = ReShift(drSize, tdiVal, tdoExp, tdoMask, SHIFT_DR, endDr, delay, retries); if (rc == 0) { int num = XsvfGetByte(); while(num-- && rc == 0) { XsvfReadBitString(tdiVal2, drSize2); BitStringAdd(drSize, tdiVal, addrMask); UpdateTdi(drSize, tdiVal, drSize2, tdiVal2, dataMask); rc = ReShift(drSize, tdiVal, tdoExp, tdoMask, SHIFT_DR, endDr, delay, retries); } } break; case XCOMMENT: /* * Skip comment string. */ XsvfSkipComment(); break; default: rc = XE_ILLEGALCMD; break; } /* Check for errors in the platform dependant interface. */ if(rc == 0) { rc = XsvfGetError(); } } return rc; } /*! * \brief XSVF Executor. * * Program entry point. */ int main(void) { int rc; /* Platform dependant initialization. */ rc = XsvfInit(); if(rc == 0) { /* Execute XSVF commands. */ rc = Execute(); } /* Platform dependant clean up. */ XsvfExit(rc); return rc; } /*@}*/