static FLStatus sendXSize(struct Buffer *outBuf, uint32 xSize, const char **error) { FLStatus retVal = FL_SUCCESS; BufferStatus bStatus; bStatus = bufAppendByte(outBuf, XSDRSIZE, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "sendXSize()"); bStatus = bufAppendLongBE(outBuf, xSize, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "sendXSize()"); cleanup: return retVal; }
static FLStatus shiftLeft( struct Buffer *buffer, uint32 numBits, uint32 shiftCount, const char **error) { FLStatus retVal = FL_SUCCESS; uint32 shiftBytes = shiftCount>>3; uint32 shiftBits = shiftCount&7; uint16 accum; const uint8 *p = buffer->data; const uint8 *const end = buffer->data + buffer->length; struct Buffer newBuffer = {0,}; BufferStatus bStatus; if ( shiftBits ) { bStatus = bufInitialise(&newBuffer, 1024, 0x00, error); CHECK_STATUS(bStatus, FL_BUF_INIT_ERR, cleanup, "shiftLeft()"); numBits &= 7; // Now the number of significant bits in first byte. if ( numBits ) { numBits = 8 - numBits; // Now the number of insignificant bits in first byte. } accum = p[0]; if ( p < end ) { accum = (uint16)(accum >> (8-shiftBits)); if ( shiftBits > numBits ) { // We're shifting by more than the number of insignificant bits bStatus = bufAppendByte(&newBuffer, (uint8)(accum&0xFF), error); CHECK_STATUS(bStatus, FL_BUF_APPEND_ERR, cleanup, "shiftLeft()"); } accum = (uint16)((p[0]<<8) + p[1]); p++; while ( p < end ) { accum = (uint16)(accum >> (8-shiftBits)); bStatus = bufAppendByte(&newBuffer, (uint8)(accum&0xFF), error); CHECK_STATUS(bStatus, FL_BUF_APPEND_ERR, cleanup, "shiftLeft()"); accum = (uint16)((p[0]<<8) + p[1]); p++; } } accum &= 0xFF00; accum = (uint16)(accum >> (8-shiftBits)); bStatus = bufAppendByte(&newBuffer, (uint8)(accum&0xFF), error); CHECK_STATUS(bStatus, FL_BUF_APPEND_ERR, cleanup, "shiftLeft()"); bufSwap(&newBuffer, buffer); }
// Parse the XSVF, reversing the byte-ordering of all the bytestreams. // static FLStatus xsvfSwapBytes(XC *xc, struct Buffer *outBuf, uint32 *maxBufSize, const char **error) { FLStatus fStatus, retVal = FL_SUCCESS; uint32 newXSize = 0, curXSize = 0, totOffset = 0; uint32 numBytes; BufferStatus bStatus; uint8 thisByte; uint32 dummy; bool zeroMask = false; if ( !maxBufSize ) { maxBufSize = &dummy; } *maxBufSize = 0; thisByte = getNextByte(xc); while ( thisByte != XCOMPLETE ) { switch ( thisByte ) { case XTDOMASK:{ // Swap the XTDOMASK bytes. uint32 initLength; const uint8 *p; const uint8 *end; if ( newXSize != curXSize ) { curXSize = newXSize; sendXSize(outBuf, curXSize, error); } initLength = (uint32)outBuf->length; numBytes = bitsToBytes(curXSize); bStatus = bufAppendByte(outBuf, XTDOMASK, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, numBytes, outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); p = outBuf->data + initLength + 1; end = outBuf->data + outBuf->length; while ( *p == 0 && p < end ) p++; if ( p == end ) { // All zeros so delete the command outBuf->length = initLength; zeroMask = true; } else { // Keep the command if ( numBytes > *maxBufSize ) { *maxBufSize = numBytes; } zeroMask = false; } break; } case XSDRTDO: // Swap the tdiValue and tdoExpected bytes. if ( newXSize != curXSize ) { curXSize = newXSize; sendXSize(outBuf, curXSize, error); } numBytes = bitsToBytes(curXSize); if ( zeroMask ) { // The last mask was all zeros, so replace this XSDRTDO with an XSDR and throw away // the tdoExpected bytes. bStatus = bufAppendByte(outBuf, XSDR, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, numBytes, outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); while ( numBytes-- ) { getNextByte(xc); } } else { // The last mask was not all zeros, so we must honour the XSDRTDO's tdoExpected bytes. CHECK_STATUS( numBytes > BUF_SIZE, FL_UNSUPPORTED_SIZE_ERR, cleanup, "xsvfSwapBytes(): Previous mask was nonzero, but no room to compare %d bytes", numBytes); if ( numBytes > *maxBufSize ) { *maxBufSize = numBytes; } bStatus = bufAppendByte(outBuf, XSDRTDO, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapAndInterleaveBytes(xc, numBytes, outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); } break; case XREPEAT: // Drop XREPEAT for now. Will probably be needed for CPLDs. getNextByte(xc); break; case XRUNTEST: // Copy the XRUNTEST bytes as-is. bStatus = bufAppendByte(outBuf, XRUNTEST, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); bStatus = bufAppendByte(outBuf, getNextByte(xc), error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); bStatus = bufAppendByte(outBuf, getNextByte(xc), error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); bStatus = bufAppendByte(outBuf, getNextByte(xc), error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); bStatus = bufAppendByte(outBuf, getNextByte(xc), error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); break; case XSIR: // Swap the XSIR bytes. bStatus = bufAppendByte(outBuf, XSIR, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); thisByte = getNextByte(xc); bStatus = bufAppendByte(outBuf, thisByte, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, (uint32)bitsToBytes(thisByte), outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); break; case XSDRSIZE: // Just store it; if it differs from the old one it will be sent when required newXSize = getNextByte(xc); // Get MSB newXSize <<= 8; newXSize |= getNextByte(xc); newXSize <<= 8; newXSize |= getNextByte(xc); newXSize <<= 8; newXSize |= getNextByte(xc); // Get LSB break; case XSDR: // Copy over if ( newXSize != curXSize ) { curXSize = newXSize; sendXSize(outBuf, curXSize, error); } bStatus = bufAppendByte(outBuf, XSDR, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, bitsToBytes(curXSize), outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); break; case XSDRB: // Roll XSDRB, XSDRC*, XSDRE into one XSDR curXSize = newXSize; sendXSize(outBuf, curXSize, error); totOffset = (uint32)outBuf->length - 4; // each subsequent XSDRC & XSDRE updates this XSDRSIZE bStatus = bufAppendByte(outBuf, XSDR, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, bitsToBytes(newXSize), outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); break; case XSDRC: // Just add the XSDRC data to the end of the previous XSDR curXSize += newXSize; bStatus = bufWriteLongBE(outBuf, totOffset, curXSize, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, bitsToBytes(newXSize), outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); break; case XSDRE: // Just add the XSDRE data to the end of the previous XSDR curXSize += newXSize; bStatus = bufWriteLongBE(outBuf, totOffset, curXSize, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); fStatus = swapBytes(xc, bitsToBytes(newXSize), outBuf, error); CHECK_STATUS(fStatus, fStatus, cleanup, "xsvfSwapBytes()"); break; case XSTATE: // There doesn't seem to be much point in these commands, since the other commands have // implied state transitions anyway. Just make sure the TAP is initialised to be at // Run-Test/Idle before playing the CSVF stream. getNextByte(xc); break; case XENDIR: // Only the default XENDIR state (TAPSTATE_RUN_TEST_IDLE) is supported. Fail fast if // there's an attempt to switch the XENDIR state to PAUSE_IR. thisByte = getNextByte(xc); CHECK_STATUS( thisByte, FL_UNSUPPORTED_DATA_ERR, cleanup, "xsvfSwapBytes(): Only XENDIR(TAPSTATE_RUN_TEST_IDLE) is supported!"); break; case XENDDR: // Only the default XENDDR state (TAPSTATE_RUN_TEST_IDLE) is supported. Fail fast if // there's an attempt to switch the XENDDR state to PAUSE_DR. thisByte = getNextByte(xc); CHECK_STATUS( thisByte, FL_UNSUPPORTED_DATA_ERR, cleanup, "xsvfSwapBytes(): Only XENDDR(TAPSTATE_RUN_TEST_IDLE) is supported!"); break; default: // All other commands are unsupported, so fail if they're encountered. CHECK_STATUS( true, FL_UNSUPPORTED_CMD_ERR, cleanup, "xsvfSwapBytes(): Unsupported command 0x%02X!", thisByte); } thisByte = getNextByte(xc); } // Add the XCOMPLETE command bStatus = bufAppendByte(outBuf, XCOMPLETE, error); CHECK_STATUS(bStatus, FL_ALLOC_ERR, cleanup, "xsvfSwapBytes()"); cleanup: return retVal; }
DLLEXPORT(FLStatus) flFlashStandardFirmware( struct FLContext *handle, const char *newVidPid, const char *jtagPort, uint32 eepromSize, const char *xsvfFile, const char **error) { FLStatus flStatus, returnCode; struct Buffer i2cBuf = {0,}; BufferStatus bStatus; FX2Status fxStatus; uint32 fwSize, xsvfSize, initSize; uint16 newVid, newPid, newDid; uint8 port, tdoBit, tdiBit, tmsBit, tckBit; if ( !usbValidateVidPid(newVidPid) ) { errRender(error, "flFlashStandardFirmware(): The supplied new VID:PID \"%s\" is invalid; it should look like 04B4:8613", newVidPid); FAIL(FL_USB_ERR); } newVid = (uint16)strtoul(newVidPid, NULL, 16); newPid = (uint16)strtoul(newVidPid+5, NULL, 16); newDid = (strlen(newVidPid) == 14) ? (uint16)strtoul(newVidPid+10, NULL, 16) : 0x0000; if ( strlen(jtagPort) != 5 ) { errRender(error, "flFlashStandardFirmware(): JTAG port specification must be <C|D><tdoBit><tdiBit><tmsBit><tckBit>"); FAIL(FL_FX2_ERR); } if ( (jtagPort[0] & 0xDF) == 'A' ) { port = 0; } else if ( (jtagPort[0] & 0xDF) == 'C' ) { port = 2; } else if ( (jtagPort[0] & 0xDF) == 'D' ) { port = 3; } else { errRender(error, "flFlashStandardFirmware(): JTAG port specification must be <A|C|D><tdoBit><tdiBit><tmsBit><tckBit>"); FAIL(FL_FX2_ERR); } if (jtagPort[1] < '0' || jtagPort[1] > '7' || jtagPort[2] < '0' || jtagPort[2] > '7' || jtagPort[3] < '0' || jtagPort[3] > '7' || jtagPort[4] < '0' || jtagPort[4] > '7' ) { errRender(error, "flFlashStandardFirmware(): JTAG port specification must be <A|C|D><tdoBit><tdiBit><tmsBit><tckBit>"); FAIL(FL_FX2_ERR); } tdoBit = jtagPort[1] - '0'; tdiBit = jtagPort[2] - '0'; tmsBit = jtagPort[3] - '0'; tckBit = jtagPort[4] - '0'; if ( port == 0 && (isInvalidPortABit(tdoBit) || isInvalidPortABit(tdiBit) || isInvalidPortABit(tmsBit) || isInvalidPortABit(tckBit)) ) { errRender(error, "flFlashStandardFirmware(): Only bits 0, 1, 3 & 7 are available for JTAG use on port A"); FAIL(FL_FX2_ERR); } bStatus = bufInitialise(&i2cBuf, 0x4000, 0x00, error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); if ( xsvfFile ) { flStatus = copyFirmwareAndRewriteIDs( &eepromWithBootFirmware, newVid, newPid, newDid, port, tdoBit, tdiBit, tmsBit, tckBit, &i2cBuf, error); CHECK_STATUS(flStatus, "flFlashStandardFirmware()", flStatus); fwSize = i2cBuf.length; flStatus = convertJtagFileToCsvf(&i2cBuf, xsvfFile, error); CHECK_STATUS(flStatus, "flFlashStandardFirmware()", flStatus); xsvfSize = i2cBuf.length - fwSize; if ( handle->writeBuffer.length ) { // Write a big-endian uint24 length for the init data, then the data itself const uint32 length = handle->writeBuffer.length; if ( length > 0x20000 ) { errRender( error, "flFlashStandardFirmware(): Cannot cope with %lu bytes of init data", length); FAIL(FL_FX2_ERR); } bStatus = bufAppendByte(&i2cBuf, (uint8)((length>>16) & 0xFF), error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); bStatus = bufAppendByte(&i2cBuf, (uint8)((length>>8) & 0xFF), error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); bStatus = bufAppendByte(&i2cBuf, (uint8)(length & 0xFF), error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); bStatus = bufAppendBlock( &i2cBuf, handle->writeBuffer.data, length, error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); initSize = length + 3; } else { // Write a zero uint24 length so the firmware knows there's no init data to follow bStatus = bufAppendByte(&i2cBuf, 0x00, error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); bStatus = bufAppendByte(&i2cBuf, 0x00, error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); bStatus = bufAppendByte(&i2cBuf, 0x00, error); CHECK_STATUS(bStatus, "flFlashStandardFirmware()", FL_ALLOC_ERR); initSize = 3; } } else {