[U-Boot] [PATCH 1/3] FPGA: add support for downloading Lattice bitstream

Stefano Babic sbabic at denx.de
Mon Oct 11 15:14:15 CEST 2010


The patch adds support to load a Lattice's bitstream
image (called VME file) into a Lattice FPGA. The code
containing the state machine delivered as part of
Lattice's ispVMtools is integrated.

The FPGA is programmed using the JTAG interface. The
board maintainer must provide accessors to drive the
JTAG signals TCK, TMS, TDI and to get the value of the
input signal TDO.

Signed-off-by: Stefano Babic <sbabic at denx.de>
---
 drivers/fpga/Makefile   |    1 +
 drivers/fpga/fpga.c     |   11 +
 drivers/fpga/ivm_core.c | 3167 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/fpga/lattice.c  |  399 ++++++
 include/fpga.h          |    1 +
 include/lattice.h       |  319 +++++
 6 files changed, 3898 insertions(+), 0 deletions(-)
 create mode 100755 drivers/fpga/ivm_core.c
 create mode 100644 drivers/fpga/lattice.c
 create mode 100755 include/lattice.h

diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 52d8e24..9ecdc5e 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
 COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
 COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
 COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o
+COBJS-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o
 ifdef CONFIG_FPGA_ALTERA
 COBJS-y += altera.o
 COBJS-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index 5659517..e41e728 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -28,6 +28,7 @@
 #include <common.h>             /* core U-Boot definitions */
 #include <xilinx.h>             /* xilinx specific definitions */
 #include <altera.h>             /* altera specific definitions */
+#include <lattice.h>
 
 #if 0
 #define FPGA_DEBUG              /* define FPGA_DEBUG to get debug messages */
@@ -139,6 +140,10 @@ static int fpga_dev_info( int devnum )
 			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
 #endif
 			break;
+		case fpga_lattice:
+			printf("Lattice Device\nDescriptor @ 0x%p\n", desc);
+			ret_val = lattice_info(desc->devdesc);
+			break;
 		default:
 			printf( "%s: Invalid or unsupported device type %d\n",
 					__FUNCTION__, desc->devtype );
@@ -224,6 +229,9 @@ int fpga_load( int devnum, void *buf, size_t bsize )
 			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
 #endif
 			break;
+		case fpga_lattice:
+			ret_val = lattice_load(desc->devdesc, buf, bsize);
+			break;
 		default:
 			printf( "%s: Invalid or unsupported device type %d\n",
 				__FUNCTION__, desc->devtype );
@@ -257,6 +265,9 @@ int fpga_dump( int devnum, void *buf, size_t bsize )
 			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
 #endif
 			break;
+		case fpga_lattice:
+			ret_val = lattice_dump(desc->devdesc, buf, bsize);
+			break;
 		default:
 			printf( "%s: Invalid or unsupported device type %d\n",
 				__FUNCTION__, desc->devtype );
diff --git a/drivers/fpga/ivm_core.c b/drivers/fpga/ivm_core.c
new file mode 100755
index 0000000..2b5a485
--- /dev/null
+++ b/drivers/fpga/ivm_core.c
@@ -0,0 +1,3167 @@
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic at denx.de.
+ *
+ * Lattice ispVME Embedded code to load Lattice's FPGA:
+ *
+ * Copyright 2009 Lattice Semiconductor Corp.
+ *
+ * ispVME Embedded allows programming of Lattice's suite of FPGA
+ * devices on embedded systems through the JTAG port.  The software
+ * is distributed in source code form and is open to re - distribution
+ * and modification where applicable.
+ *
+ * Revision History of ivm_core.c module:
+ * 4/25/06 ht   Change some variables from unsigned short or int
+ *              to long int to make the code compiler independent.
+ * 5/24/06 ht   Support using RESET (TRST) pin as a special purpose
+ *              control pin such as triggering the loading of known
+ *              state exit.
+ * 3/6/07 ht added functions to support output to terminals
+ *
+ * 09/11/07 NN Type cast mismatch variables
+ *		   Moved the sclock() function to hardware.c
+ * 08/28/08 NN Added Calculate checksum support.
+ * 4/1/09 Nguyen replaced the recursive function call codes on
+ *        the ispVMLCOUNT function
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <linux/string.h>
+#include <malloc.h>
+#include <lattice.h>
+
+#define vme_out_char(c)	printf("%c", c)
+#define vme_out_hex(c)	printf("%x", c)
+#define vme_out_string(s) printf("%s", s)
+
+/*
+ *
+ * Global variables used to specify the flow control and data type.
+ *
+ *	g_usFlowControl:	flow control register. Each bit in the
+ *                               register can potentially change the
+ *                               personality of the embedded engine.
+ *	g_usDataType:		holds the data type of the current row.
+ *
+ */
+
+static unsigned short g_usFlowControl;
+unsigned short g_usDataType;
+
+/*
+ *
+ * Global variables used to specify the ENDDR and ENDIR.
+ *
+ *	g_ucEndDR:		the state that the device goes to after SDR.
+ *	g_ucEndIR:		the state that the device goes to after SIR.
+ *
+ */
+
+unsigned char g_ucEndDR = DRPAUSE;
+unsigned char g_ucEndIR = IRPAUSE;
+
+/*
+ *
+ * Global variables used to support header/trailer.
+ *
+ *	g_usHeadDR:		the number of lead devices in bypass.
+ *	g_usHeadIR:		the sum of IR length of lead devices.
+ *	g_usTailDR:		the number of tail devices in bypass.
+ *	g_usTailIR:		the sum of IR length of tail devices.
+ *
+ */
+
+static unsigned short g_usHeadDR;
+static unsigned short g_usHeadIR;
+static unsigned short g_usTailDR;
+static unsigned short g_usTailIR;
+
+/*
+ *
+ * Global variable to store the number of bits of data or instruction
+ * to be shifted into or out from the device.
+ *
+ */
+
+static unsigned short g_usiDataSize;
+
+/*
+ *
+ * Stores the frequency. Default to 1 MHz.
+ *
+ */
+
+static int g_iFrequency = 1000;
+
+/*
+ *
+ * Stores the maximum amount of ram needed to hold a row of data.
+ *
+ */
+
+static unsigned short g_usMaxSize;
+
+/*
+ *
+ * Stores the LSH or RSH value.
+ *
+ */
+
+static unsigned short g_usShiftValue;
+
+/*
+ *
+ * Stores the current repeat loop value.
+ *
+ */
+
+static unsigned short g_usRepeatLoops;
+
+/*
+ *
+ * Stores the current vendor.
+ *
+ */
+
+static signed char g_cVendor = LATTICE;
+
+/*
+ *
+ * Stores the VME file CRC.
+ *
+ */
+
+unsigned short g_usCalculatedCRC;
+
+/*
+ *
+ * Stores the Device Checksum.
+ *
+ */
+/* 08/28/08 NN Added Calculate checksum support. */
+unsigned long g_usChecksum;
+static unsigned int g_uiChecksumIndex;
+
+/*
+ *
+ * Stores the current state of the JTAG state machine.
+ *
+ */
+
+static signed char g_cCurrentJTAGState;
+
+/*
+ *
+ * Global variables used to support looping.
+ *
+ *	g_pucHeapMemory:	holds the entire repeat loop.
+ *	g_iHeapCounter:		points to the current byte in the repeat loop.
+ *	g_iHEAPSize:		the current size of the repeat in bytes.
+ *
+ */
+
+unsigned char *g_pucHeapMemory;
+unsigned short g_iHeapCounter;
+unsigned short g_iHEAPSize;
+static unsigned short previous_size;
+
+/*
+ *
+ * Global variables used to support intelligent programming.
+ *
+ *	g_usIntelDataIndex:     points to the current byte of the
+ *                               intelligent buffer.
+ *	g_usIntelBufferSize:	holds the size of the intelligent
+ *                               buffer.
+ *
+ */
+
+unsigned short g_usIntelDataIndex;
+unsigned short g_usIntelBufferSize;
+
+/*
+ *
+ * Supported VME versions.
+ *
+ */
+
+const char *const g_szSupportedVersions[] = {
+	"__VME2.0", "__VME3.0", "____12.0", "____12.1", 0};
+
+/*
+ *
+ * Holds the maximum size of each respective buffer. These variables are used
+ * to write the HEX files when converting VME to HEX.
+ *
+*/
+
+static unsigned short g_usTDOSize;
+static unsigned short g_usMASKSize;
+static unsigned short g_usTDISize;
+static unsigned short g_usDMASKSize;
+static unsigned short g_usLCOUNTSize;
+static unsigned short g_usHDRSize;
+static unsigned short g_usTDRSize;
+static unsigned short g_usHIRSize;
+static unsigned short g_usTIRSize;
+static unsigned short g_usHeapSize;
+
+/*
+ *
+ * Global variables used to store data.
+ *
+ *	g_pucOutMaskData:	local RAM to hold one row of MASK data.
+ *	g_pucInData:		local RAM to hold one row of TDI data.
+ *	g_pucOutData:		local RAM to hold one row of TDO data.
+ *	g_pucHIRData:		local RAM to hold the current SIR header.
+ *	g_pucTIRData:		local RAM to hold the current SIR trailer.
+ *	g_pucHDRData:		local RAM to hold the current SDR header.
+ *	g_pucTDRData:		local RAM to hold the current SDR trailer.
+ *	g_pucIntelBuffer:	local RAM to hold the current intelligent buffer
+ *	g_pucOutDMaskData:	local RAM to hold one row of DMASK data.
+ *
+ */
+
+unsigned char	*g_pucOutMaskData	= NULL,
+		*g_pucInData		= NULL,
+		*g_pucOutData		= NULL,
+		*g_pucHIRData		= NULL,
+		*g_pucTIRData		= NULL,
+		*g_pucHDRData		= NULL,
+		*g_pucTDRData		= NULL,
+		*g_pucIntelBuffer	= NULL,
+		*g_pucOutDMaskData	= NULL;
+
+/*
+ *
+ * JTAG state machine transition table.
+ *
+ */
+
+struct {
+	 unsigned char  CurState;  /* From this state */
+	 unsigned char  NextState; /* Step to this state */
+	 unsigned char  Pattern;   /* The tragetory of TMS */
+	 unsigned char  Pulses;    /* The number of steps */
+} g_JTAGTransistions[25] = {
+{ RESET,	RESET,		0xFC, 6 },	/* Transitions from RESET */
+{ RESET,	IDLE,		0x00, 1 },
+{ RESET,	DRPAUSE,	0x50, 5 },
+{ RESET,	IRPAUSE,	0x68, 6 },
+{ IDLE,		RESET,		0xE0, 3 },	/* Transitions from IDLE */
+{ IDLE,		DRPAUSE,	0xA0, 4 },
+{ IDLE,		IRPAUSE,	0xD0, 5 },
+{ DRPAUSE,	RESET,		0xF8, 5 },	/* Transitions from DRPAUSE */
+{ DRPAUSE,	IDLE,		0xC0, 3 },
+{ DRPAUSE,	IRPAUSE,	0xF4, 7 },
+{ DRPAUSE,	DRPAUSE,	0xE8, 6 },/* 06/14/06 Support POLL STATUS LOOP*/
+{ IRPAUSE,	RESET,		0xF8, 5 },	/* Transitions from IRPAUSE */
+{ IRPAUSE,	IDLE,		0xC0, 3 },
+{ IRPAUSE,	DRPAUSE,	0xE8, 6 },
+{ DRPAUSE,	SHIFTDR,	0x80, 2 }, /* Extra transitions using SHIFTDR */
+{ IRPAUSE,	SHIFTDR,	0xE0, 5 },
+{ SHIFTDR,	DRPAUSE,	0x80, 2 },
+{ SHIFTDR,	IDLE,		0xC0, 3 },
+{ IRPAUSE,	SHIFTIR,	0x80, 2 },/* Extra transitions using SHIFTIR */
+{ SHIFTIR,	IRPAUSE,	0x80, 2 },
+{ SHIFTIR,	IDLE,		0xC0, 3 },
+{ DRPAUSE,	DRCAPTURE,	0xE0, 4 }, /* 11/15/05 Support DRCAPTURE*/
+{ DRCAPTURE, DRPAUSE,	0x80, 2 },
+{ IDLE,     DRCAPTURE,	0x80, 2 },
+{ IRPAUSE,  DRCAPTURE,  0xE0, 4 }
+};
+
+/*
+ *
+ * List to hold all LVDS pairs.
+ *
+ */
+
+LVDSPair *g_pLVDSList;
+unsigned short g_usLVDSPairCount;
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+static signed char ispVMDataCode(void);
+static long int ispVMDataSize(void);
+static void ispVMData(unsigned char *Data);
+static signed char ispVMShift(signed char Code);
+static signed char ispVMAmble(signed char Code);
+static signed char ispVMLoop(unsigned short a_usLoopCount);
+static signed char ispVMBitShift(signed char mode, unsigned short bits);
+static void ispVMComment(unsigned short a_usCommentSize);
+static void ispVMHeader(unsigned short a_usHeaderSize);
+static signed char ispVMLCOUNT(unsigned short a_usCountSize);
+static void ispVMClocks(unsigned short Clocks);
+static void ispVMBypass(signed char ScanType, unsigned short Bits);
+static void ispVMStateMachine(signed char NextState);
+static signed char ispVMSend(unsigned short int);
+static signed char ispVMRead(unsigned short int);
+static signed char ispVMReadandSave(unsigned short int);
+static signed char ispVMProcessLVDS(unsigned short a_usLVDSCount);
+static void ispVMMemManager(signed char types, unsigned short size);
+
+/*
+ *
+ * External variables and functions in hardware.c module
+ *
+ */
+static signed char g_cCurrentJTAGState;
+
+#ifdef DEBUG
+
+/*
+ *
+ * GetState
+ *
+ * Returns the state as a string based on the opcode. Only used
+ * for debugging purposes.
+ *
+ */
+
+const char *GetState(unsigned char a_ucState)
+{
+	switch (a_ucState) {
+	case RESET:
+		return "RESET";
+	case IDLE:
+		return "IDLE";
+	case IRPAUSE:
+		return "IRPAUSE";
+	case DRPAUSE:
+		return "DRPAUSE";
+	case SHIFTIR:
+		return "SHIFTIR";
+	case SHIFTDR:
+		return "SHIFTDR";
+	case DRCAPTURE:/* 11/15/05 support DRCAPTURE*/
+		return "DRCAPTURE";
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ *
+ * PrintData
+ *
+ * Prints the data. Only used for debugging purposes.
+ *
+ */
+
+void PrintData(unsigned short a_iDataSize, unsigned char *a_pucData)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short usByteSize  = 0;
+	unsigned short usBitIndex  = 0;
+	signed short usByteIndex   = 0;
+	unsigned char ucByte       = 0;
+	unsigned char ucFlipByte   = 0;
+
+	if (a_iDataSize % 8) {
+		/* 09/11/07 NN Type cast mismatch variables */
+		usByteSize = (unsigned short)(a_iDataSize / 8 + 1);
+	} else {
+		/* 09/11/07 NN Type cast mismatch variables */
+		usByteSize = (unsigned short)(a_iDataSize / 8);
+	}
+	puts("(");
+	/* 09/11/07 NN Type cast mismatch variables */
+	for (usByteIndex = (signed short)(usByteSize - 1);
+		usByteIndex >= 0; usByteIndex--) {
+		ucByte = a_pucData[usByteIndex];
+		ucFlipByte = 0x00;
+
+		/*
+		*
+		* Flip each byte.
+		*
+		*/
+
+		for (usBitIndex = 0; usBitIndex < 8; usBitIndex++) {
+			ucFlipByte <<= 1;
+			if (ucByte & 0x1) {
+				ucFlipByte |= 0x1;
+			}
+
+			ucByte >>= 1;
+		}
+
+		/*
+		*
+		* Print the flipped byte.
+		*
+		*/
+
+		printf("%.02X", ucFlipByte);
+		if ((usByteSize - usByteIndex) % 40 == 39) {
+			puts("\n\t\t");
+		}
+		if (usByteIndex < 0)
+			break;
+	}
+	puts(")");
+}
+#endif /* DEBUG */
+
+void ispVMMemManager(signed char cTarget, unsigned short usSize)
+{
+	switch (cTarget) {
+	case XTDI:
+	case TDI:
+		if (g_pucInData != NULL) {
+			if (previous_size == usSize) {/*memory exist*/
+				break;
+			} else {
+				free(g_pucInData);
+				g_pucInData = NULL;
+			}
+		}
+		g_pucInData = (unsigned char *) malloc(usSize / 8 + 2);
+		previous_size = usSize;
+	case XTDO:
+	case TDO:
+		if (g_pucOutData != NULL) {
+			if (previous_size == usSize) { /*already exist*/
+				break;
+			} else {
+				free(g_pucOutData);
+				g_pucOutData = NULL;
+			}
+		}
+		g_pucOutData = (unsigned char *) malloc(usSize / 8 + 2);
+		previous_size = usSize;
+		break;
+	case MASK:
+		if (g_pucOutMaskData != NULL) {
+			if (previous_size == usSize) {/*already allocated*/
+				break;
+			} else {
+				free(g_pucOutMaskData);
+				g_pucOutMaskData = NULL;
+			}
+		}
+		g_pucOutMaskData = (unsigned char *) malloc(usSize / 8 + 2);
+		previous_size = usSize;
+		break;
+	case HIR:
+		if (g_pucHIRData != NULL) {
+			free(g_pucHIRData);
+			g_pucHIRData = NULL;
+		}
+		g_pucHIRData = (unsigned char *) malloc(usSize / 8 + 2);
+		break;
+	case TIR:
+		if (g_pucTIRData != NULL) {
+			free(g_pucTIRData);
+			g_pucTIRData = NULL;
+		}
+		g_pucTIRData = (unsigned char *) malloc(usSize / 8 + 2);
+		break;
+	case HDR:
+		if (g_pucHDRData != NULL) {
+			free(g_pucHDRData);
+			g_pucHDRData = NULL;
+		}
+		g_pucHDRData = (unsigned char *) malloc(usSize / 8 + 2);
+		break;
+	case TDR:
+		if (g_pucTDRData != NULL) {
+			free(g_pucTDRData);
+			g_pucTDRData = NULL;
+		}
+		g_pucTDRData = (unsigned char *) malloc(usSize / 8 + 2);
+		break;
+	case HEAP:
+		if (g_pucHeapMemory != NULL) {
+			free(g_pucHeapMemory);
+			g_pucHeapMemory = NULL;
+		}
+		g_pucHeapMemory = (unsigned char *) malloc(usSize + 2);
+		break;
+	case DMASK:
+		if (g_pucOutDMaskData != NULL) {
+			if (previous_size == usSize) { /*already allocated*/
+				break;
+			} else {
+				free(g_pucOutDMaskData);
+				g_pucOutDMaskData = NULL;
+			}
+		}
+		g_pucOutDMaskData = (unsigned char *) malloc(usSize / 8 + 2);
+		previous_size = usSize;
+		break;
+	case LHEAP:
+		if (g_pucIntelBuffer != NULL) {
+			free(g_pucIntelBuffer);
+			g_pucIntelBuffer = NULL;
+		}
+		g_pucIntelBuffer = (unsigned char *) malloc(usSize + 2);
+		break;
+	case LVDS:
+		if (g_pLVDSList != NULL) {
+			free(g_pLVDSList);
+			g_pLVDSList = NULL;
+		}
+		g_pLVDSList = (LVDSPair *) malloc(usSize * sizeof(LVDSPair));
+		if (g_pLVDSList)
+			memset(g_pLVDSList, 0, usSize * sizeof(LVDSPair));
+		break;
+	default:
+		return;
+    }
+}
+
+void ispVMFreeMem(void)
+{
+	if (g_pucHeapMemory != NULL) {
+		free(g_pucHeapMemory);
+		g_pucHeapMemory = NULL;
+	}
+
+	if (g_pucOutMaskData != NULL) {
+		free(g_pucOutMaskData);
+		g_pucOutMaskData = NULL;
+	}
+
+	if (g_pucInData != NULL) {
+		free(g_pucInData);
+		g_pucInData = NULL;
+	}
+
+	if (g_pucOutData != NULL) {
+		free(g_pucOutData);
+		g_pucOutData = NULL;
+	}
+
+	if (g_pucHIRData != NULL) {
+		free(g_pucHIRData);
+		g_pucHIRData = NULL;
+	}
+
+	if (g_pucTIRData != NULL) {
+		free(g_pucTIRData);
+		g_pucTIRData = NULL;
+	}
+
+	if (g_pucHDRData != NULL) {
+		free(g_pucHDRData);
+		g_pucHDRData = NULL;
+	}
+
+	if (g_pucTDRData != NULL) {
+		free(g_pucTDRData);
+		g_pucTDRData = NULL;
+	}
+
+	if (g_pucOutDMaskData != NULL) {
+		free(g_pucOutDMaskData);
+		g_pucOutDMaskData = NULL;
+	}
+
+	if (g_pucIntelBuffer != NULL) {
+		free(g_pucIntelBuffer);
+		g_pucIntelBuffer = NULL;
+	}
+
+	if (g_pLVDSList != NULL) {
+		free(g_pLVDSList);
+		g_pLVDSList = NULL;
+	}
+}
+
+
+/*
+ *
+ * ispVMDataSize
+ *
+ * Returns a VME-encoded number, usually used to indicate the
+ * bit length of an SIR/SDR command.
+ *
+ */
+
+long int ispVMDataSize()
+{
+	/* 09/11/07 NN added local variables initialization */
+	long int iSize           = 0;
+	signed char cCurrentByte = 0;
+	signed char cIndex       = 0;
+	cIndex = 0;
+	while ((cCurrentByte = GetByte()) & 0x80) {
+		iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex;
+		cIndex += 7;
+	}
+	iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex;
+	return iSize;
+}
+
+/*
+ *
+ * ispVMCode
+ *
+ * This is the heart of the embedded engine. All the high-level opcodes
+ * are extracted here. Once they have been identified, then it
+ * will call other functions to handle the processing.
+ *
+ */
+
+signed char ispVMCode()
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short iRepeatSize = 0;
+	signed char cOpcode	   = 0;
+	signed char cRetCode       = 0;
+	unsigned char ucState      = 0;
+	unsigned short usDelay     = 0;
+	unsigned short usToggle    = 0;
+	unsigned char usByte       = 0;
+
+	/*
+	*
+	* Check the compression flag only if this is the first time
+	* this function is entered. Do not check the compression flag if
+	* it is being called recursively from other functions within
+	* the embedded engine.
+	*
+	*/
+
+	if (!(g_usDataType & LHEAP_IN) && !(g_usDataType & HEAP_IN)) {
+		usByte = GetByte();
+		if (usByte == 0xf1) {
+			g_usDataType |= COMPRESS;
+		} else if (usByte == 0xf2) {
+			g_usDataType &= ~COMPRESS;
+		} else {
+			return VME_INVALID_FILE;
+		}
+	}
+
+	/*
+	*
+	* Begin looping through all the VME opcodes.
+	*
+	*/
+
+	while ((cOpcode = GetByte()) >= 0) {
+
+		switch (cOpcode) {
+		case STATE:
+
+			/*
+			 * Step the JTAG state machine.
+			 */
+
+			ucState = GetByte();
+
+			/*
+			 * Step the JTAG state machine to DRCAPTURE
+			 * to support Looping.
+			 */
+
+			if ((g_usDataType & LHEAP_IN) &&
+				 (ucState == DRPAUSE) &&
+				 (g_cCurrentJTAGState == ucState)) {
+				ispVMStateMachine(DRCAPTURE);
+			}
+
+			ispVMStateMachine(ucState);
+
+#ifdef DEBUG
+			if (g_usDataType & LHEAP_IN) {
+				debug("LDELAY %s ", GetState(ucState));
+			} else {
+				debug("STATE %s;\n", GetState(ucState));
+			}
+#endif /* DEBUG */
+			break;
+		case SIR:
+		case SDR:
+		case XSDR:
+
+#ifdef DEBUG
+			switch (cOpcode) {
+			case SIR:
+				puts("SIR ");
+				break;
+			case SDR:
+			case XSDR:
+				if (g_usDataType & LHEAP_IN) {
+					puts("LSDR ");
+				} else {
+					puts("SDR ");
+				}
+				break;
+			}
+#endif /* DEBUG */
+			/*
+			*
+			* Shift in data into the device.
+			*
+			*/
+
+			cRetCode = ispVMShift(cOpcode);
+			if (cRetCode != 0) {
+				return cRetCode;
+			}
+			break;
+		case WAIT:
+
+			/*
+			*
+			* Observe delay.
+			*
+			*/
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			usDelay = (unsigned short) ispVMDataSize();
+			ispVMDelay(usDelay);
+
+#ifdef DEBUG
+			if (usDelay & 0x8000) {
+
+				/*
+				 * Since MSB is set, the delay time must be
+				 * decoded to millisecond. The SVF2VME encodes
+				 * the MSB to represent millisecond.
+				 */
+
+				usDelay &= ~0x8000;
+				if (g_usDataType & LHEAP_IN) {
+					printf("%.2E SEC;\n",
+						(float) usDelay / 1000);
+				} else {
+					printf("RUNTEST %.2E SEC;\n",
+						(float) usDelay / 1000);
+				}
+			} else {
+				/*
+				 * Since MSB is not set, the delay time
+				 * is given as microseconds.
+				 */
+
+				if (g_usDataType & LHEAP_IN) {
+					printf("%.2E SEC;\n",
+						(float) usDelay / 1000000);
+				} else {
+					printf("RUNTEST %.2E SEC;\n",
+						(float) usDelay / 1000000);
+				}
+			}
+#endif /* DEBUG */
+			break;
+		case TCK:
+
+			/*
+			 * Issue clock toggles.
+			*/
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			usToggle = (unsigned short) ispVMDataSize();
+			ispVMClocks(usToggle);
+
+#ifdef DEBUG
+			printf("RUNTEST %d TCK;\n", usToggle);
+#endif /* DEBUG */
+			break;
+		case ENDDR:
+
+			/*
+			*
+			* Set the ENDDR.
+			*
+			*/
+
+			g_ucEndDR = GetByte();
+
+#ifdef DEBUG
+			printf("ENDDR %s;\n", GetState(g_ucEndDR));
+#endif /* DEBUG */
+			break;
+		case ENDIR:
+
+			/*
+			*
+			* Set the ENDIR.
+			*
+			*/
+
+			g_ucEndIR = GetByte();
+
+#ifdef DEBUG
+			printf("ENDIR %s;\n", GetState(g_ucEndIR));
+#endif /* DEBUG */
+			break;
+		case HIR:
+		case TIR:
+		case HDR:
+		case TDR:
+
+#ifdef DEBUG
+			switch (cOpcode) {
+			case HIR:
+				puts("HIR ");
+				break;
+			case TIR:
+				puts("TIR ");
+				break;
+			case HDR:
+				puts("HDR ");
+				break;
+			case TDR:
+				puts("TDR ");
+				break;
+			}
+#endif /* DEBUG */
+			/*
+			 * Set the header/trailer of the device in order
+			 * to bypass
+			 * successfully.
+			 */
+
+			cRetCode = ispVMAmble(cOpcode);
+			if (cRetCode != 0) {
+				return cRetCode;
+			}
+
+#ifdef DEBUG
+			puts(";\n");
+#endif /* DEBUG */
+			break;
+		case MEM:
+
+			/*
+			 * The maximum RAM required to support
+			 * processing one row of the VME file.
+			 */
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_usMaxSize = (unsigned short) ispVMDataSize();
+
+#ifdef DEBUG
+			printf("// MEMSIZE %d\n", g_usMaxSize);
+#endif /* DEBUG */
+			break;
+		case VENDOR:
+
+			/*
+			*
+			* Set the VENDOR type.
+			*
+			*/
+
+			cOpcode = GetByte();
+			switch (cOpcode) {
+			case LATTICE:
+#ifdef DEBUG
+				puts("// VENDOR LATTICE\n");
+#endif /* DEBUG */
+				g_cVendor = LATTICE;
+				break;
+			case ALTERA:
+#ifdef DEBUG
+				puts("// VENDOR ALTERA\n");
+#endif /* DEBUG */
+				g_cVendor = ALTERA;
+				break;
+			case XILINX:
+#ifdef DEBUG
+				puts("// VENDOR XILINX\n");
+#endif /* DEBUG */
+				g_cVendor = XILINX;
+				break;
+			default:
+				break;
+			}
+			break;
+		case SETFLOW:
+
+			/*
+			 * Set the flow control. Flow control determines
+			 * the personality of the embedded engine.
+			 */
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_usFlowControl |= (unsigned short) ispVMDataSize();
+			break;
+		case RESETFLOW:
+
+			/*
+			*
+			* Unset the flow control.
+			*
+			*/
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_usFlowControl &= (unsigned short) ~(ispVMDataSize());
+			break;
+		case HEAP:
+
+			/*
+			*
+			* Allocate heap size to store loops.
+			*
+			*/
+
+			cRetCode = GetByte();
+			if (cRetCode != SECUREHEAP) {
+				return VME_INVALID_FILE;
+			}
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_iHEAPSize = (unsigned short) ispVMDataSize();
+
+			/*
+			 * Store the maximum size of the HEAP buffer.
+			 * Used to convert VME to HEX.
+			 */
+
+			if (g_iHEAPSize > g_usHeapSize) {
+				g_usHeapSize = g_iHEAPSize;
+			}
+
+			ispVMMemManager(HEAP, (unsigned short) g_iHEAPSize);
+			break;
+		case REPEAT:
+
+			/*
+			*
+			* Execute loops.
+			*
+			*/
+
+			g_usRepeatLoops = 0;
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			iRepeatSize = (unsigned short) ispVMDataSize();
+
+			cRetCode = ispVMLoop((unsigned short) iRepeatSize);
+			if (cRetCode != 0) {
+				return cRetCode;
+			}
+			break;
+		case ENDLOOP:
+
+			/*
+			*
+			* Exit point from processing loops.
+			*
+			*/
+
+			return cRetCode;
+		case ENDVME:
+
+			/*
+			 * The only valid exit point that indicates
+			 * end of programming.
+			 */
+
+			return cRetCode;
+		case SHR:
+
+			/*
+			*
+			* Right-shift address.
+			*
+			*/
+
+			g_usFlowControl |= SHIFTRIGHT;
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_usShiftValue = (unsigned short) (g_usRepeatLoops *
+				(unsigned short)GetByte());
+			break;
+		case SHL:
+
+			/*
+			 * Left-shift address.
+			 */
+
+			g_usFlowControl |= SHIFTLEFT;
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_usShiftValue = (unsigned short) (g_usRepeatLoops *
+				(unsigned short)GetByte());
+			break;
+		case FREQUENCY:
+
+			/*
+			*
+			* Set the frequency.
+			*
+			*/
+
+			/* 09/11/07 NN Type cast mismatch variables */
+			g_iFrequency = (int) (ispVMDataSize() / 1000);
+			if (g_iFrequency == 1)
+				g_iFrequency = 1000;
+
+#ifdef DEBUG
+			printf("FREQUENCY %.2E HZ;\n",
+				(float) g_iFrequency * 1000);
+#endif /* DEBUG */
+			break;
+		case LCOUNT:
+
+			/*
+			*
+			* Process LCOUNT command.
+			*
+			*/
+
+			cRetCode = ispVMLCOUNT((unsigned short)ispVMDataSize());
+			if (cRetCode != 0) {
+				return cRetCode;
+			}
+			break;
+		case VUES:
+
+			/*
+			*
+			* Set the flow control to verify USERCODE.
+			*
+			*/
+
+			g_usFlowControl |= VERIFYUES;
+			break;
+		case COMMENT:
+
+			/*
+			*
+			* Display comment.
+			*
+			*/
+
+			ispVMComment((unsigned short) ispVMDataSize());
+			break;
+		case LVDS:
+
+			/*
+			*
+			* Process LVDS command.
+			*
+			*/
+
+			ispVMProcessLVDS((unsigned short) ispVMDataSize());
+			break;
+		case HEADER:
+
+			/*
+			*
+			* Discard header.
+			*
+			*/
+
+			ispVMHeader((unsigned short) ispVMDataSize());
+			break;
+		/* 03/14/06 Support Toggle ispENABLE signal*/
+		case ispEN:
+			ucState = GetByte();
+			if ((ucState == ON) || (ucState == 0x01))
+				writePort(g_ucPinENABLE, 0x01);
+			else
+				writePort(g_ucPinENABLE, 0x00);
+			ispVMDelay(1);
+			break;
+		/* 05/24/06 support Toggle TRST pin*/
+		case TRST:
+			ucState = GetByte();
+			if (ucState == 0x01)
+				writePort(g_ucPinTRST, 0x01);
+			else
+				writePort(g_ucPinTRST, 0x00);
+			ispVMDelay(1);
+			break;
+		default:
+
+			/*
+			*
+			* Invalid opcode encountered.
+			*
+			*/
+
+#ifdef DEBUG
+			printf("\nINVALID OPCODE: 0x%.2X\n", cOpcode);
+#endif /* DEBUG */
+
+			return VME_INVALID_FILE;
+		}
+	}
+
+	/*
+	*
+	* Invalid exit point. Processing the token 'ENDVME' is the only
+	* valid way to exit the embedded engine.
+	*
+	*/
+
+	return VME_INVALID_FILE;
+}
+
+/*
+ *
+ * ispVMDataCode
+ *
+ * Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command.
+ *
+ */
+
+signed char ispVMDataCode()
+{
+	/* 09/11/07 NN added local variables initialization */
+	signed char cDataByte    = 0;
+	signed char siDataSource = 0;  /*source of data from file by default*/
+
+	if (g_usDataType & HEAP_IN) {
+		siDataSource = 1;  /*the source of data from memory*/
+	}
+
+	/*
+	*
+	* Clear the data type register.
+	*
+	**/
+
+	g_usDataType &= ~(MASK_DATA + TDI_DATA +
+		TDO_DATA + DMASK_DATA + CMASK_DATA);
+
+	/*
+	 * Iterate through SIR/SDR command and look for TDI,
+	 * TDO, MASK, etc.
+	 */
+
+	while ((cDataByte = GetByte()) >= 0) {
+			ispVMMemManager(cDataByte, g_usMaxSize);
+			switch (cDataByte) {
+			case TDI:
+
+				/*
+				 * Store the maximum size of the TDI buffer.
+				 * Used to convert VME to HEX.
+				 */
+
+				if (g_usiDataSize > g_usTDISize) {
+					g_usTDISize = g_usiDataSize;
+				}
+				/*
+				 * Updated data type register to indicate that
+				 * TDI data is currently being used. Process the
+				 * data in the VME file into the TDI buffer.
+				 */
+
+				g_usDataType |= TDI_DATA;
+				ispVMData(g_pucInData);
+				break;
+			case XTDO:
+
+				/*
+				 * Store the maximum size of the TDO buffer.
+				 * Used to convert VME to HEX.
+				 */
+
+				if (g_usiDataSize > g_usTDOSize) {
+					g_usTDOSize = g_usiDataSize;
+				}
+
+				/*
+				 * Updated data type register to indicate that
+				 * TDO data is currently being used.
+				 */
+
+				g_usDataType |= TDO_DATA;
+				break;
+			case TDO:
+
+				/*
+				 * Store the maximum size of the TDO buffer.
+				 * Used to convert VME to HEX.
+				 */
+
+				if (g_usiDataSize > g_usTDOSize) {
+					g_usTDOSize = g_usiDataSize;
+				}
+
+				/*
+				 * Updated data type register to indicate
+				 * that TDO data is currently being used.
+				 * Process the data in the VME file into the
+				 * TDO buffer.
+				 */
+
+				g_usDataType |= TDO_DATA;
+				ispVMData(g_pucOutData);
+				break;
+			case MASK:
+
+				/*
+				 * Store the maximum size of the MASK buffer.
+				 * Used to convert VME to HEX.
+				 */
+
+				if (g_usiDataSize > g_usMASKSize) {
+					g_usMASKSize = g_usiDataSize;
+				}
+
+				/*
+				 * Updated data type register to indicate that
+				 * MASK data is currently being used. Process
+				 * the data in the VME file into the MASK buffer
+				 */
+
+				g_usDataType |= MASK_DATA;
+				ispVMData(g_pucOutMaskData);
+				break;
+			case DMASK:
+
+				/*
+				 * Store the maximum size of the DMASK buffer.
+				 * Used to convert VME to HEX.
+				 */
+
+				if (g_usiDataSize > g_usDMASKSize) {
+					g_usDMASKSize = g_usiDataSize;
+				}
+
+				/*
+				 * Updated data type register to indicate that
+				 * DMASK data is currently being used. Process
+				 * the data in the VME file into the DMASK
+				 * buffer.
+				 */
+
+				g_usDataType |= DMASK_DATA;
+				ispVMData(g_pucOutDMaskData);
+				break;
+			case CMASK:
+
+				/*
+				 * Updated data type register to indicate that
+				 * MASK data is currently being used. Process
+				 * the data in the VME file into the MASK buffer
+				 */
+
+				g_usDataType |= CMASK_DATA;
+				ispVMData(g_pucOutMaskData);
+				break;
+			case CONTINUE:
+				return 0;
+			default:
+				/*
+				 * Encountered invalid opcode.
+				 */
+				return VME_INVALID_FILE;
+			}
+
+			switch (cDataByte) {
+			case TDI:
+
+				/*
+				 * Left bit shift. Used when performing
+				 * algorithm looping.
+				 */
+
+				if (g_usFlowControl & SHIFTLEFT) {
+					ispVMBitShift(SHL, g_usShiftValue);
+					g_usFlowControl &= ~SHIFTLEFT;
+				}
+
+				/*
+				 * Right bit shift. Used when performing
+				 * algorithm looping.
+				 */
+
+				if (g_usFlowControl & SHIFTRIGHT) {
+					ispVMBitShift(SHR, g_usShiftValue);
+					g_usFlowControl &= ~SHIFTRIGHT;
+				}
+			default:
+				break;
+			}
+
+			if (siDataSource) {
+				g_usDataType |= HEAP_IN; /*restore from memory*/
+			}
+	}
+
+	if (siDataSource) {  /*fetch data from heap memory upon return*/
+		g_usDataType |= HEAP_IN;
+	}
+
+	if (cDataByte < 0) {
+
+		/*
+		 * Encountered invalid opcode.
+		 */
+
+		return VME_INVALID_FILE;
+	} else {
+		return 0;
+	}
+}
+
+/*
+ *
+ * ispVMData
+ * Extract one row of data operand from the current data type opcode. Perform
+ * the decompression if necessary. Extra RAM is not required for the
+ * decompression process. The decompression scheme employed in this module
+ * is on row by row basis. The format of the data stream:
+ * [compression code][compressed data stream]
+ * 0x00    --No compression
+ * 0x01    --Compress by 0x00.
+ *           Example:
+ *           Original stream:   0x000000000000000000000001
+ *           Compressed stream: 0x01000901
+ *           Detail:            0x01 is the code, 0x00 is the key,
+ *                              0x09 is the count of 0x00 bytes,
+ *                              0x01 is the uncompressed byte.
+ * 0x02    --Compress by 0xFF.
+ *           Example:
+ *           Original stream:   0xFFFFFFFFFFFFFFFFFFFFFF01
+ *           Compressed stream: 0x02FF0901
+ *           Detail:            0x02 is the code, 0xFF is the key,
+ *                              0x09 is the count of 0xFF bytes,
+ *                              0x01 is the uncompressed byte.
+ * 0x03
+ * : :
+ * 0xFE   -- Compress by nibble blocks.
+ *           Example:
+ *           Original stream:   0x84210842108421084210
+ *           Compressed stream: 0x0584210
+ *           Detail:            0x05 is the code, means 5 nibbles block.
+ *                              0x84210 is the 5 nibble blocks.
+ *                              The whole row is 80 bits given by g_usiDataSize.
+ *                              The number of times the block repeat itself
+ *                              is found by g_usiDataSize/(4*0x05) which is 4.
+ * 0xFF   -- Compress by the most frequently happen byte.
+ *           Example:
+ *           Original stream:   0x04020401030904040404
+ *           Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0)
+ *                          or: 0xFF044090181C240
+ *           Detail:            0xFF is the code, 0x04 is the key.
+ *                              a bit of 0 represent the key shall be put into
+ *                              the current bit position and a bit of 1
+ *                              represent copying the next of 8 bits of data
+ *                              in.
+ *
+ */
+
+void ispVMData(unsigned char *ByteData)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short size               = 0;
+	unsigned short i, j, m, getData   = 0;
+	unsigned char cDataByte           = 0;
+	unsigned char compress            = 0;
+	unsigned short FFcount            = 0;
+	unsigned char compr_char          = 0xFF;
+	unsigned short index              = 0;
+	signed char compression           = 0;
+
+	/*convert number in bits to bytes*/
+	if (g_usiDataSize % 8 > 0) {
+		/* 09/11/07 NN Type cast mismatch variables */
+		size = (unsigned short)(g_usiDataSize / 8 + 1);
+	} else {
+		/* 09/11/07 NN Type cast mismatch variables */
+		size = (unsigned short)(g_usiDataSize / 8);
+	}
+
+	/*
+	 * If there is compression, then check if compress by key
+	 * of 0x00 or 0xFF or by other keys or by nibble blocks
+	 */
+
+	if (g_usDataType & COMPRESS) {
+		compression = 1;
+		compress = GetByte();
+		if ((compress  == VAR) && (g_usDataType & HEAP_IN)) {
+			getData = 1;
+			g_usDataType &= ~(HEAP_IN);
+			compress = GetByte();
+		}
+
+		switch (compress) {
+		case 0x00:
+			/* No compression */
+			compression = 0;
+			break;
+		case 0x01:
+			/* Compress by byte 0x00 */
+			compr_char = 0x00;
+			break;
+		case 0x02:
+			/* Compress by byte 0xFF */
+			compr_char = 0xFF;
+			break;
+		case 0xFF:
+			/* Huffman encoding */
+			compr_char = GetByte();
+			i = 8;
+			for (index = 0; index < size; index++) {
+				ByteData[index] = 0x00;
+				if (i > 7) {
+					cDataByte = GetByte();
+					i = 0;
+				}
+				if ((cDataByte << i++) & 0x80)
+					m = 8;
+				else {
+					ByteData[index] = compr_char;
+					m = 0;
+				}
+
+				for (j = 0; j < m; j++) {
+					if (i > 7) {
+						cDataByte = GetByte();
+						i = 0;
+					}
+					ByteData[index] |=
+					((cDataByte << i++) & 0x80) >> j;
+				}
+			}
+			size = 0;
+			break;
+		default:
+			for (index = 0; index < size; index++)
+				ByteData[index] = 0x00;
+			for (index = 0; index < compress; index++) {
+				if (index % 2 == 0)
+					cDataByte = GetByte();
+				for (i = 0; i < size * 2 / compress; i++) {
+					j = (unsigned short)(index +
+						(i * (unsigned short)compress));
+					/*clear the nibble to zero first*/
+					if (j%2) {
+						if (index % 2)
+							ByteData[j/2] |=
+								cDataByte & 0xF;
+						else
+							ByteData[j/2] |=
+								cDataByte >> 4;
+					} else {
+						if (index % 2)
+							ByteData[j/2] |=
+								cDataByte << 4;
+						else
+							ByteData[j/2] |=
+							cDataByte & 0xF0;
+					}
+				}
+			}
+			size = 0;
+			break;
+		}
+	}
+
+	FFcount = 0;
+
+	/* Decompress by byte 0x00 or 0xFF */
+	for (index = 0; index < size; index++) {
+		if (FFcount <= 0) {
+			cDataByte = GetByte();
+			if ((cDataByte == VAR) && (g_usDataType&HEAP_IN) &&
+				!getData && !(g_usDataType&COMPRESS)) {
+				getData = 1;
+				g_usDataType &= ~(HEAP_IN);
+				cDataByte = GetByte();
+			}
+			ByteData[index] = cDataByte;
+			if ((compression) && (cDataByte == compr_char))
+				/* 09/11/07 NN Type cast mismatch variables */
+				FFcount = (unsigned short) ispVMDataSize();
+				/*The number of 0xFF or 0x00 bytes*/
+		} else {
+			FFcount--; /*Use up the 0xFF chain first*/
+			ByteData[index] = compr_char;
+		}
+	}
+
+	if (getData) {
+		g_usDataType |= HEAP_IN;
+		getData = 0;
+	}
+}
+
+/*
+ *
+ * ispVMShift
+ *
+ * Processes the SDR/XSDR/SIR commands.
+ *
+ */
+
+signed char ispVMShift(signed char a_cCode)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short iDataIndex  = 0;
+	unsigned short iReadLoop   = 0;
+	signed char cRetCode       = 0;
+
+	cRetCode = 0;
+	/* 09/11/07 NN Type cast mismatch variables */
+	g_usiDataSize = (unsigned short) ispVMDataSize();
+
+	/*clear the flags first*/
+	g_usDataType &= ~(SIR_DATA + EXPRESS + SDR_DATA);
+	switch (a_cCode) {
+	case SIR:
+		g_usDataType |= SIR_DATA;
+		/*
+		 * 1/15/04 If performing cascading, then go directly to SHIFTIR.
+		 *  Else, go to IRPAUSE before going to SHIFTIR
+		 */
+		if (g_usFlowControl & CASCADE) {
+			ispVMStateMachine(SHIFTIR);
+		} else {
+			ispVMStateMachine(IRPAUSE);
+			ispVMStateMachine(SHIFTIR);
+			if (g_usHeadIR > 0) {
+				ispVMBypass(HIR, g_usHeadIR);
+				sclock();
+			}
+		}
+		break;
+	case XSDR:
+		g_usDataType |= EXPRESS; /*mark simultaneous in and out*/
+	case SDR:
+		g_usDataType |= SDR_DATA;
+		/*
+		 * 1/15/04 If already in SHIFTDR, then do not move state or
+		 * shift in header.  This would imply that the previously
+		 * shifted frame was a cascaded frame.
+		 */
+		if (g_cCurrentJTAGState != SHIFTDR) {
+			/*
+			 * 1/15/04 If performing cascading, then go directly
+			 * to SHIFTDR.  Else, go to DRPAUSE before going
+			 * to SHIFTDR
+			 */
+			if (g_usFlowControl & CASCADE) {
+				if (g_cCurrentJTAGState == DRPAUSE) {
+					ispVMStateMachine(SHIFTDR);
+					/*
+					 * 1/15/04 If cascade flag has been seat
+					 * and the current state is DRPAUSE,
+					 * this implies that the first cascaded
+					 * frame is about to be shifted in.  The
+					 * header must be shifted prior to
+					 * shifting the first cascaded frame.
+					 */
+					if (g_usHeadDR > 0) {
+						ispVMBypass(HDR, g_usHeadDR);
+						sclock();
+					}
+				} else {
+					ispVMStateMachine(SHIFTDR);
+				}
+			} else {
+				ispVMStateMachine(DRPAUSE);
+				ispVMStateMachine(SHIFTDR);
+				if (g_usHeadDR > 0) {
+					ispVMBypass(HDR, g_usHeadDR);
+					sclock();
+				}
+			}
+		}
+		break;
+	default:
+		return VME_INVALID_FILE;
+	}
+
+	cRetCode = ispVMDataCode();
+
+	if (cRetCode != 0) {
+		return VME_INVALID_FILE;
+	}
+
+#ifdef DEBUG
+	printf("%d ", g_usiDataSize);
+
+	if (g_usDataType & TDI_DATA) {
+		puts("TDI ");
+		PrintData(g_usiDataSize, g_pucInData);
+	}
+
+	if (g_usDataType & TDO_DATA) {
+		puts("\n\t\tTDO ");
+		PrintData(g_usiDataSize, g_pucOutData);
+	}
+
+	if (g_usDataType & MASK_DATA) {
+		puts("\n\t\tMASK ");
+		PrintData(g_usiDataSize, g_pucOutMaskData);
+	}
+
+	if (g_usDataType & DMASK_DATA) {
+		puts("\n\t\tDMASK ");
+		PrintData(g_usiDataSize, g_pucOutDMaskData);
+	}
+
+	puts(";\n");
+#endif /* DEBUG */
+
+	if (g_usDataType & TDO_DATA || g_usDataType & DMASK_DATA) {
+		if (g_usDataType & DMASK_DATA) {
+			cRetCode = ispVMReadandSave(g_usiDataSize);
+			if (!cRetCode) {
+				if (g_usTailDR > 0) {
+					sclock();
+					ispVMBypass(TDR, g_usTailDR);
+				}
+				ispVMStateMachine(DRPAUSE);
+				ispVMStateMachine(SHIFTDR);
+				if (g_usHeadDR > 0) {
+					ispVMBypass(HDR, g_usHeadDR);
+					sclock();
+				}
+				for (iDataIndex = 0;
+					iDataIndex < g_usiDataSize / 8 + 1;
+					iDataIndex++)
+					g_pucInData[iDataIndex] =
+						g_pucOutData[iDataIndex];
+				g_usDataType &= ~(TDO_DATA + DMASK_DATA);
+				cRetCode = ispVMSend(g_usiDataSize);
+			}
+		} else {
+			cRetCode = ispVMRead(g_usiDataSize);
+			if (cRetCode == -1 && g_cVendor == XILINX) {
+				for (iReadLoop = 0; iReadLoop < 30;
+					iReadLoop++) {
+					cRetCode = ispVMRead(g_usiDataSize);
+					if (!cRetCode) {
+						break;
+					} else {
+						/* Always DRPAUSE */
+						ispVMStateMachine(DRPAUSE);
+						/*
+						 * Bypass other devices
+						 * when appropriate
+						 */
+						ispVMBypass(TDR, g_usTailDR);
+						ispVMStateMachine(g_ucEndDR);
+						ispVMStateMachine(IDLE);
+						ispVMDelay(1000);
+					}
+				}
+			}
+		}
+	} else { /*TDI only*/
+		cRetCode = ispVMSend(g_usiDataSize);
+	}
+
+	/*transfer the input data to the output buffer for the next verify*/
+	if ((g_usDataType & EXPRESS) || (a_cCode == SDR)) {
+		if (g_pucOutData) {
+			for (iDataIndex = 0; iDataIndex < g_usiDataSize / 8 + 1;
+				iDataIndex++)
+				g_pucOutData[iDataIndex] =
+					g_pucInData[iDataIndex];
+		}
+	}
+
+	switch (a_cCode) {
+	case SIR:
+		/* 1/15/04 If not performing cascading, then shift ENDIR */
+		if (!(g_usFlowControl & CASCADE)) {
+			if (g_usTailIR > 0) {
+				sclock();
+				ispVMBypass(TIR, g_usTailIR);
+			}
+			ispVMStateMachine(g_ucEndIR);
+		}
+		break;
+	case XSDR:
+	case SDR:
+		/* 1/15/04 If not performing cascading, then shift ENDDR */
+		if (!(g_usFlowControl & CASCADE)) {
+			if (g_usTailDR > 0) {
+				sclock();
+				ispVMBypass(TDR, g_usTailDR);
+			}
+			ispVMStateMachine(g_ucEndDR);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return cRetCode;
+}
+
+/*
+ *
+ * ispVMAmble
+ *
+ * This routine is to extract Header and Trailer parameter for SIR and
+ * SDR operations.
+ *
+ * The Header and Trailer parameter are the pre-amble and post-amble bit
+ * stream need to be shifted into TDI or out of TDO of the devices. Mostly
+ * is for the purpose of bypassing the leading or trailing devices. ispVM
+ * supports only shifting data into TDI to bypass the devices.
+ *
+ * For a single device, the header and trailer parameters are all set to 0
+ * as default by ispVM. If it is for multiple devices, the header and trailer
+ * value will change as specified by the VME file.
+ *
+ */
+
+signed char ispVMAmble(signed char Code)
+{
+	signed char compress = 0;
+	/* 09/11/07 NN Type cast mismatch variables */
+	g_usiDataSize = (unsigned short)ispVMDataSize();
+
+#ifdef DEBUG
+	printf("%d", g_usiDataSize);
+#endif /* DEBUG */
+
+	if (g_usiDataSize) {
+
+		/*
+		 * Discard the TDI byte and set the compression bit in the data
+		 * type register to false if compression is set because TDI data
+		 * after HIR/HDR/TIR/TDR is not compressed.
+		 */
+
+		GetByte();
+		if (g_usDataType & COMPRESS) {
+			g_usDataType &= ~(COMPRESS);
+			compress = 1;
+		}
+	}
+
+	switch (Code) {
+	case HIR:
+
+		/*
+		 * Store the maximum size of the HIR buffer.
+		 * Used to convert VME to HEX.
+		 */
+
+		if (g_usiDataSize > g_usHIRSize) {
+			g_usHIRSize = g_usiDataSize;
+		}
+
+		/*
+		 * Assign the HIR value and allocate memory.
+		 */
+
+		g_usHeadIR = g_usiDataSize;
+		if (g_usHeadIR) {
+			ispVMMemManager(HIR, g_usHeadIR);
+			ispVMData(g_pucHIRData);
+
+#ifdef DEBUG
+			puts(" TDI ");
+			PrintData(g_usHeadIR, g_pucHIRData);
+#endif /* DEBUG */
+		}
+		break;
+	case TIR:
+
+		/*
+		 * Store the maximum size of the TIR buffer.
+		 * Used to convert VME to HEX.
+		 */
+
+		if (g_usiDataSize > g_usTIRSize) {
+			g_usTIRSize = g_usiDataSize;
+		}
+
+		/*
+		 * Assign the TIR value and allocate memory.
+		 */
+
+		g_usTailIR = g_usiDataSize;
+		if (g_usTailIR) {
+			ispVMMemManager(TIR, g_usTailIR);
+			ispVMData(g_pucTIRData);
+
+#ifdef DEBUG
+			puts(" TDI ");
+			PrintData(g_usTailIR, g_pucTIRData);
+#endif /* DEBUG */
+		}
+		break;
+	case HDR:
+
+		/*
+		 * Store the maximum size of the HDR buffer.
+		 * Used to convert VME to HEX.
+		 */
+
+		if (g_usiDataSize > g_usHDRSize) {
+			g_usHDRSize = g_usiDataSize;
+		}
+
+		/*
+		 * Assign the HDR value and allocate memory.
+		 *
+		 */
+
+		g_usHeadDR = g_usiDataSize;
+		if (g_usHeadDR) {
+			ispVMMemManager(HDR, g_usHeadDR);
+			ispVMData(g_pucHDRData);
+
+#ifdef DEBUG
+			puts(" TDI ");
+			PrintData(g_usHeadDR, g_pucHDRData);
+#endif /* DEBUG */
+		}
+		break;
+	case TDR:
+
+		/*
+		 * Store the maximum size of the TDR buffer.
+		 * Used to convert VME to HEX.
+		 */
+
+		if (g_usiDataSize > g_usTDRSize) {
+			g_usTDRSize = g_usiDataSize;
+		}
+
+		/*
+		 * Assign the TDR value and allocate memory.
+		 *
+		 */
+
+		g_usTailDR = g_usiDataSize;
+		if (g_usTailDR) {
+			ispVMMemManager(TDR, g_usTailDR);
+			ispVMData(g_pucTDRData);
+
+#ifdef DEBUG
+			puts(" TDI ");
+			PrintData(g_usTailDR, g_pucTDRData);
+#endif /* DEBUG */
+		}
+		break;
+	default:
+		break;
+	}
+
+	/*
+	*
+	* Re-enable compression if it was previously set.
+	*
+	**/
+
+	if (compress) {
+		g_usDataType |= COMPRESS;
+	}
+
+	if (g_usiDataSize) {
+		Code = GetByte();
+		if (Code == CONTINUE) {
+			return 0;
+		} else {
+
+			/*
+			 * Encountered invalid opcode.
+			 */
+
+			return VME_INVALID_FILE;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ *
+ * ispVMLoop
+ *
+ * Perform the function call upon by the REPEAT opcode.
+ * Memory is to be allocated to store the entire loop from REPEAT to ENDLOOP.
+ * After the loop is stored then execution begin. The REPEATLOOP flag is set
+ * on the g_usFlowControl register to indicate the repeat loop is in session
+ * and therefore fetch opcode from the memory instead of from the file.
+ *
+ */
+
+signed char ispVMLoop(unsigned short a_usLoopCount)
+{
+	/* 09/11/07 NN added local variables initialization */
+	signed char cRetCode      = 0;
+	unsigned short iHeapIndex = 0;
+	unsigned short iLoopIndex = 0;
+
+	g_usShiftValue = 0;
+	for (iHeapIndex = 0; iHeapIndex < g_iHEAPSize; iHeapIndex++) {
+		g_pucHeapMemory[iHeapIndex] = GetByte();
+	}
+
+	if (g_pucHeapMemory[iHeapIndex - 1] != ENDLOOP) {
+		return VME_INVALID_FILE;
+	}
+
+	g_usFlowControl |= REPEATLOOP;
+	g_usDataType |= HEAP_IN;
+
+	for (iLoopIndex = 0; iLoopIndex < a_usLoopCount; iLoopIndex++) {
+		g_iHeapCounter = 0;
+		cRetCode = ispVMCode();
+		g_usRepeatLoops++;
+		if (cRetCode < 0) {
+			break;
+		}
+	}
+
+	g_usDataType &= ~(HEAP_IN);
+	g_usFlowControl &= ~(REPEATLOOP);
+	return cRetCode;
+}
+
+/*
+ *
+ * ispVMBitShift
+ *
+ * Shift the TDI stream left or right by the number of bits. The data in
+ * *g_pucInData is of the VME format, so the actual shifting is the reverse of
+ * IEEE 1532 or SVF format.
+ *
+ */
+
+signed char ispVMBitShift(signed char mode, unsigned short bits)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short i       = 0;
+	unsigned short size    = 0;
+	unsigned short tmpbits = 0;
+
+	if (g_usiDataSize % 8 > 0) {
+		/* 09/11/07 NN Type cast mismatch variables */
+		size = (unsigned short)(g_usiDataSize / 8 + 1);
+	} else {
+		/* 09/11/07 NN Type cast mismatch variables */
+		size = (unsigned short)(g_usiDataSize / 8);
+	}
+
+	switch (mode) {
+	case SHR:
+		for (i = 0; i < size; i++) {
+			if (g_pucInData[i] != 0) {
+				tmpbits = bits;
+				while (tmpbits > 0) {
+					g_pucInData[i] <<= 1;
+					if (g_pucInData[i] == 0) {
+						i--;
+						g_pucInData[i] = 1;
+					}
+					tmpbits--;
+				}
+			}
+		}
+		break;
+	case SHL:
+		for (i = 0; i < size; i++) {
+			if (g_pucInData[i] != 0) {
+				tmpbits = bits;
+				while (tmpbits > 0) {
+					g_pucInData[i] >>= 1;
+					if (g_pucInData[i] == 0) {
+						i--;
+						g_pucInData[i] = 8;
+					}
+					tmpbits--;
+				}
+			}
+		}
+		break;
+	default:
+		return VME_INVALID_FILE;
+	}
+
+	return 0;
+}
+
+/*
+ *
+ * ispVMComment
+ *
+ * Displays the SVF comments.
+ *
+ */
+
+void ispVMComment(unsigned short a_usCommentSize)
+{
+	char cCurByte = 0;
+	for (; a_usCommentSize > 0; a_usCommentSize--) {
+		/*
+		*
+		* Print character to the terminal.
+		*
+		**/
+		cCurByte = GetByte();
+		vme_out_char(cCurByte);
+	}
+	cCurByte = '\n';
+	vme_out_char(cCurByte);
+}
+
+/*
+ *
+ * ispVMHeader
+ *
+ * Iterate the length of the header and discard it.
+ *
+ */
+
+void ispVMHeader(unsigned short a_usHeaderSize)
+{
+	for (; a_usHeaderSize > 0; a_usHeaderSize--) {
+		GetByte();
+	}
+}
+
+/*
+ *
+ * ispVMCalculateCRC32
+ *
+ * Calculate the 32-bit CRC.
+ *
+ */
+
+void ispVMCalculateCRC32(unsigned char a_ucData)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned char ucIndex          = 0;
+	unsigned char ucFlipData       = 0;
+	unsigned short usCRCTableEntry = 0;
+	unsigned int crc_table[16] = {
+		0x0000, 0xCC01, 0xD801,
+		0x1400, 0xF001, 0x3C00,
+		0x2800, 0xE401, 0xA001,
+		0x6C00, 0x7800, 0xB401,
+		0x5000, 0x9C01, 0x8801,
+		0x4400
+	};
+
+	for (ucIndex = 0; ucIndex < 8; ucIndex++) {
+		ucFlipData <<= 1;
+		if (a_ucData & 0x01) {
+			ucFlipData |= 0x01;
+		}
+		a_ucData >>= 1;
+	}
+
+	/* 09/11/07 NN Type cast mismatch variables */
+	usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]);
+	g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF);
+	g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^
+			usCRCTableEntry ^ crc_table[ucFlipData & 0xF]);
+	usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]);
+	g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF);
+	g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^
+		usCRCTableEntry ^ crc_table[(ucFlipData >> 4) & 0xF]);
+}
+
+/*
+ *
+ * ispVMLCOUNT
+ *
+ * Process the intelligent programming loops.
+ *
+ */
+
+signed char ispVMLCOUNT(unsigned short a_usCountSize)
+{
+	unsigned short usContinue	  = 1;
+	unsigned short usIntelBufferIndex = 0;
+	unsigned short usCountIndex       = 0;
+	signed char cRetCode              = 0;
+	signed char cRepeatHeap           = 0;
+	signed char cOpcode               = 0;
+	unsigned char ucState             = 0;
+	unsigned short usDelay            = 0;
+	unsigned short usToggle           = 0;
+	unsigned char usByte              = 0;
+
+	g_usIntelBufferSize = (unsigned short)ispVMDataSize();
+
+	/*
+	 * Allocate memory for intel buffer.
+	 *
+	 */
+
+	ispVMMemManager(LHEAP, g_usIntelBufferSize);
+
+	/*
+	 * Store the maximum size of the intelligent buffer.
+	 * Used to convert VME to HEX.
+	 */
+
+	if (g_usIntelBufferSize > g_usLCOUNTSize) {
+		g_usLCOUNTSize = g_usIntelBufferSize;
+	}
+
+	/*
+	 * Copy intel data to the buffer.
+	 */
+
+	for (usIntelBufferIndex = 0; usIntelBufferIndex < g_usIntelBufferSize;
+		usIntelBufferIndex++) {
+		g_pucIntelBuffer[usIntelBufferIndex] = GetByte();
+	}
+
+	/*
+	 * Set the data type register to get data from the intelligent
+	 * data buffer.
+	 */
+
+	g_usDataType |= LHEAP_IN;
+
+	/*
+	*
+	* If the HEAP_IN flag is set, temporarily unset the flag so data will be
+	* retrieved from the status buffer.
+	*
+	**/
+
+	if (g_usDataType & HEAP_IN) {
+		g_usDataType &= ~HEAP_IN;
+		cRepeatHeap = 1;
+	}
+
+#ifdef DEBUG
+	printf("LCOUNT %d;\n", a_usCountSize);
+#endif /* DEBUG */
+
+	/*
+	 * Iterate through the intelligent programming command.
+	*/
+
+	for (usCountIndex = 0; usCountIndex < a_usCountSize; usCountIndex++) {
+
+		/*
+		*
+		* Initialize the intel data index to 0 before each iteration.
+		*
+		**/
+
+		g_usIntelDataIndex = 0;
+		cOpcode            = 0;
+		ucState            = 0;
+		usDelay            = 0;
+		usToggle           = 0;
+		usByte             = 0;
+		usContinue		   = 1;
+
+		/*
+		*
+		* Begin looping through all the VME opcodes.
+		*
+		*/
+		/*
+		* 4/1/09 Nguyen replaced the recursive function call codes on
+		*        the ispVMLCOUNT function
+		*
+		*/
+		while (usContinue) {
+			cOpcode = GetByte();
+			switch (cOpcode) {
+			case HIR:
+			case TIR:
+			case HDR:
+			case TDR:
+				/*
+				 * Set the header/trailer of the device in order
+				 * to bypass successfully.
+				 */
+
+				ispVMAmble(cOpcode);
+			break;
+			case STATE:
+
+				/*
+				 * Step the JTAG state machine.
+				 */
+
+				ucState = GetByte();
+				/*
+				 * Step the JTAG state machine to DRCAPTURE
+				 * to support Looping.
+				 */
+
+				if ((g_usDataType & LHEAP_IN) &&
+					 (ucState == DRPAUSE) &&
+					 (g_cCurrentJTAGState == ucState)) {
+					ispVMStateMachine(DRCAPTURE);
+				}
+				ispVMStateMachine(ucState);
+#ifdef DEBUG
+				printf("LDELAY %s ", GetState(ucState));
+#endif /* DEBUG */
+				break;
+			case SIR:
+#ifdef DEBUG
+				printf("SIR ");
+#endif /* DEBUG */
+				/*
+				 * Shift in data into the device.
+				 */
+
+				cRetCode = ispVMShift(cOpcode);
+				break;
+			case SDR:
+
+#ifdef DEBUG
+				printf("LSDR ");
+#endif /* DEBUG */
+				/*
+				 * Shift in data into the device.
+				 */
+
+				cRetCode = ispVMShift(cOpcode);
+				break;
+			case WAIT:
+
+				/*
+				*
+				* Observe delay.
+				*
+				*/
+
+				usDelay = (unsigned short)ispVMDataSize();
+				ispVMDelay(usDelay);
+
+#ifdef DEBUG
+				if (usDelay & 0x8000) {
+
+					/*
+					 * Since MSB is set, the delay time must
+					 * be decoded to millisecond. The
+					 * SVF2VME encodes the MSB to represent
+					 * millisecond.
+					 */
+
+					usDelay &= ~0x8000;
+					printf("%.2E SEC;\n",
+						(float) usDelay / 1000);
+				} else {
+					/*
+					 * Since MSB is not set, the delay time
+					 * is given as microseconds.
+					 */
+
+					printf("%.2E SEC;\n",
+						(float) usDelay / 1000000);
+				}
+#endif /* DEBUG */
+				break;
+			case TCK:
+
+				/*
+				 * Issue clock toggles.
+				 */
+
+				usToggle = (unsigned short)ispVMDataSize();
+				ispVMClocks(usToggle);
+
+#ifdef DEBUG
+				printf("RUNTEST %d TCK;\n", usToggle);
+#endif /* DEBUG */
+				break;
+			case ENDLOOP:
+
+				/*
+				 * Exit point from processing loops.
+				 */
+				usContinue = 0;
+				break;
+
+			case COMMENT:
+
+				/*
+				 * Display comment.
+				 */
+
+				ispVMComment((unsigned short) ispVMDataSize());
+				break;
+			case ispEN:
+				ucState = GetByte();
+				if ((ucState == ON) || (ucState == 0x01))
+					writePort(g_ucPinENABLE, 0x01);
+				else
+					writePort(g_ucPinENABLE, 0x00);
+				ispVMDelay(1);
+				break;
+			case TRST:
+				if (GetByte() == 0x01)
+					writePort(g_ucPinTRST, 0x01);
+				else
+					writePort(g_ucPinTRST, 0x00);
+				ispVMDelay(1);
+				break;
+			default:
+
+				/*
+				 * Invalid opcode encountered.
+				 */
+
+				debug("\nINVALID OPCODE: 0x%.2X\n", cOpcode);
+
+				return VME_INVALID_FILE;
+			}
+		}
+		if (cRetCode >= 0) {
+			/*
+			 * Break if intelligent programming is successful.
+			 */
+
+			break;
+		}
+
+	}
+	/*
+	 * If HEAP_IN flag was temporarily disabled,
+	 * re-enable it before exiting
+	 */
+
+	if (cRepeatHeap) {
+		g_usDataType |= HEAP_IN;
+	}
+
+	/*
+	 * Set the data type register to not get data from the
+	 * intelligent data buffer.
+	 */
+
+	g_usDataType &= ~LHEAP_IN;
+	return cRetCode;
+}
+/*
+ *
+ * ispVMClocks
+ *
+ * Applies the specified number of pulses to TCK.
+ *
+ */
+
+void ispVMClocks(unsigned short Clocks)
+{
+	unsigned short iClockIndex = 0;
+	for (iClockIndex = 0; iClockIndex < Clocks; iClockIndex++) {
+		sclock();
+	}
+}
+
+/*
+ *
+ * ispVMBypass
+ *
+ * This procedure takes care of the HIR, HDR, TIR, TDR for the
+ * purpose of putting the other devices into Bypass mode. The
+ * current state is checked to find out if it is at DRPAUSE or
+ * IRPAUSE. If it is at DRPAUSE, perform bypass register scan.
+ * If it is at IRPAUSE, scan into instruction registers the bypass
+ * instruction.
+ *
+ */
+
+void ispVMBypass(signed char ScanType, unsigned short Bits)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short iIndex       = 0;
+	unsigned short iSourceIndex = 0;
+	unsigned char cBitState     = 0;
+	unsigned char cCurByte      = 0;
+	unsigned char *pcSource    = NULL;
+
+	if (Bits <= 0) {
+		return;
+	}
+
+	switch (ScanType) {
+	case HIR:
+		pcSource = g_pucHIRData;
+		break;
+	case TIR:
+		pcSource = g_pucTIRData;
+		break;
+	case HDR:
+		pcSource = g_pucHDRData;
+		break;
+	case TDR:
+		pcSource = g_pucTDRData;
+		break;
+	default:
+		break;
+	}
+
+	iSourceIndex = 0;
+	cBitState = 0;
+	for (iIndex = 0; iIndex < Bits - 1; iIndex++) {
+		/* Scan instruction or bypass register */
+		if (iIndex % 8 == 0) {
+			cCurByte = pcSource[iSourceIndex++];
+		}
+		cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+			? 0x01 : 0x00);
+		writePort(g_ucPinTDI, cBitState);
+		sclock();
+	}
+
+	if (iIndex % 8 == 0)  {
+		cCurByte = pcSource[iSourceIndex++];
+	}
+
+	cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+		? 0x01 : 0x00);
+	writePort(g_ucPinTDI, cBitState);
+}
+
+/*
+ *
+ * ispVMStateMachine
+ *
+ * This procedure steps all devices in the daisy chain from a given
+ * JTAG state to the next desirable state. If the next state is TLR,
+ * the JTAG state machine is brute forced into TLR by driving TMS
+ * high and pulse TCK 6 times.
+ *
+ */
+
+void ispVMStateMachine(signed char cNextJTAGState)
+{
+	/* 09/11/07 NN added local variables initialization */
+	signed char cPathIndex  = 0;
+	signed char cStateIndex = 0;
+
+	if ((g_cCurrentJTAGState == cNextJTAGState) &&
+		(cNextJTAGState != RESET)) {
+		return;
+	}
+
+	for (cStateIndex = 0; cStateIndex < 25; cStateIndex++) {
+		if ((g_cCurrentJTAGState ==
+			 g_JTAGTransistions[cStateIndex].CurState) &&
+			(cNextJTAGState ==
+				 g_JTAGTransistions[cStateIndex].NextState)) {
+			break;
+		}
+	}
+
+	g_cCurrentJTAGState = cNextJTAGState;
+	for (cPathIndex = 0;
+		cPathIndex < g_JTAGTransistions[cStateIndex].Pulses;
+		cPathIndex++) {
+		if ((g_JTAGTransistions[cStateIndex].Pattern << cPathIndex)
+			& 0x80) {
+			writePort(g_ucPinTMS, (unsigned char) 0x01);
+		} else {
+			writePort(g_ucPinTMS, (unsigned char) 0x00);
+		}
+		sclock();
+	}
+
+	writePort(g_ucPinTDI, 0x00);
+	writePort(g_ucPinTMS, 0x00);
+}
+
+/*
+ *
+ * ispVMStart
+ *
+ * Enable the port to the device and set the state to RESET (TLR).
+ *
+ */
+
+void ispVMStart()
+{
+#ifdef DEBUG
+	printf("// ISPVM EMBEDDED ADDED\n");
+	printf("STATE RESET;\n");
+#endif
+	g_usFlowControl	= 0;
+	g_usDataType = g_uiChecksumIndex = g_cCurrentJTAGState = 0;
+	g_usHeadDR = g_usHeadIR = g_usTailDR = g_usTailIR = 0;
+	g_usMaxSize = g_usShiftValue = g_usRepeatLoops = 0;
+	g_usTDOSize =  g_usMASKSize = g_usTDISize = 0;
+	g_usDMASKSize = g_usLCOUNTSize = g_usHDRSize = 0;
+	g_usTDRSize = g_usHIRSize = g_usTIRSize =  g_usHeapSize	= 0;
+	g_pLVDSList = NULL;
+	g_usLVDSPairCount = 0;
+	previous_size = 0;
+
+	ispVMStateMachine(RESET);    /*step devices to RESET state*/
+}
+
+/*
+ *
+ * ispVMEnd
+ *
+ * Set the state of devices to RESET to enable the devices and disable
+ * the port.
+ *
+ */
+
+void ispVMEnd()
+{
+#ifdef DEBUG
+	printf("// ISPVM EMBEDDED ADDED\n");
+	printf("STATE RESET;\n");
+	printf("RUNTEST 1.00E-001 SEC;\n");
+#endif
+
+	ispVMStateMachine(RESET);   /*step devices to RESET state */
+	ispVMDelay(1000);              /*wake up devices*/
+}
+
+/*
+ *
+ * ispVMSend
+ *
+ * Send the TDI data stream to devices. The data stream can be
+ * instructions or data.
+ *
+ */
+
+signed char ispVMSend(unsigned short a_usiDataSize)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short iIndex       = 0;
+	unsigned short iInDataIndex = 0;
+	unsigned char cCurByte      = 0;
+	unsigned char cBitState     = 0;
+
+	for (iIndex = 0; iIndex < a_usiDataSize - 1; iIndex++) {
+		if (iIndex % 8 == 0) {
+			cCurByte = g_pucInData[iInDataIndex++];
+		}
+		cBitState = (unsigned char)(((cCurByte << iIndex % 8) & 0x80)
+			? 0x01 : 0x00);
+		writePort(g_ucPinTDI, cBitState);
+		sclock();
+	}
+
+	if (iIndex % 8 == 0) {
+		/* Take care of the last bit */
+		cCurByte = g_pucInData[iInDataIndex];
+	}
+
+	cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+		? 0x01 : 0x00);
+
+	writePort(g_ucPinTDI, cBitState);
+	if (g_usFlowControl & CASCADE) {
+		/*1/15/04 Clock in last bit for the first n-1 cascaded frames */
+		sclock();
+	}
+
+	return 0;
+}
+
+/*
+ *
+ * ispVMRead
+ *
+ * Read the data stream from devices and verify.
+ *
+ */
+
+signed char ispVMRead(unsigned short a_usiDataSize)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short usDataSizeIndex    = 0;
+	unsigned short usErrorCount       = 0;
+	unsigned short usLastBitIndex     = 0;
+	unsigned char cDataByte           = 0;
+	unsigned char cMaskByte           = 0;
+	unsigned char cInDataByte         = 0;
+	unsigned char cCurBit             = 0;
+	unsigned char cByteIndex          = 0;
+	unsigned short usBufferIndex      = 0;
+	unsigned char ucDisplayByte       = 0x00;
+	unsigned char ucDisplayFlag       = 0x01;
+	char StrChecksum[256]            = {0};
+	unsigned char g_usCalculateChecksum = 0x00;
+
+	/* 09/11/07 NN Type cast mismatch variables */
+	usLastBitIndex = (unsigned short)(a_usiDataSize - 1);
+
+#ifndef DEBUG
+	/*
+	 * If mask is not all zeros, then set the display flag to 0x00,
+	 * otherwise it shall be set to 0x01 to indicate that data read
+	 * from the device shall be displayed. If DEBUG is defined,
+	 * always display data.
+	 */
+
+	for (usDataSizeIndex = 0; usDataSizeIndex < (a_usiDataSize + 7) / 8;
+		usDataSizeIndex++) {
+		if (g_usDataType & MASK_DATA) {
+			if (g_pucOutMaskData[usDataSizeIndex] != 0x00) {
+				ucDisplayFlag = 0x00;
+				break;
+			}
+		} else if (g_usDataType & CMASK_DATA) {
+			g_usCalculateChecksum = 0x01;
+			ucDisplayFlag = 0x00;
+			break;
+		} else {
+			ucDisplayFlag = 0x00;
+			break;
+		}
+	}
+#endif /* DEBUG */
+
+	/*
+	*
+	* Begin shifting data in and out of the device.
+	*
+	**/
+
+	for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize;
+		usDataSizeIndex++) {
+		if (cByteIndex == 0) {
+
+			/*
+			 * Grab byte from TDO buffer.
+			 */
+
+			if (g_usDataType & TDO_DATA) {
+				cDataByte = g_pucOutData[usBufferIndex];
+			}
+
+			/*
+			 * Grab byte from MASK buffer.
+			 */
+
+			if (g_usDataType & MASK_DATA) {
+				cMaskByte = g_pucOutMaskData[usBufferIndex];
+			} else {
+				cMaskByte = 0xFF;
+			}
+
+			/*
+			 * Grab byte from CMASK buffer.
+			 */
+
+			if (g_usDataType & CMASK_DATA) {
+				cMaskByte = 0x00;
+				g_usCalculateChecksum = 0x01;
+			}
+
+			/*
+			 * Grab byte from TDI buffer.
+			 */
+
+			if (g_usDataType & TDI_DATA) {
+				cInDataByte = g_pucInData[usBufferIndex];
+			}
+
+			usBufferIndex++;
+		}
+
+		cCurBit = readPort();
+
+		if (ucDisplayFlag) {
+			ucDisplayByte <<= 1;
+			ucDisplayByte |= cCurBit;
+		}
+
+		/*
+		 * Check if data read from port matches with expected TDO.
+		 */
+
+		if (g_usDataType & TDO_DATA) {
+			/* 08/28/08 NN Added Calculate checksum support. */
+			if (g_usCalculateChecksum) {
+				if (cCurBit == 0x01)
+					g_usChecksum +=
+						(1 << (g_uiChecksumIndex % 8));
+				g_uiChecksumIndex++;
+			} else {
+				if ((((cMaskByte << cByteIndex) & 0x80)
+					? 0x01 : 0x00)) {
+					if (cCurBit != (unsigned char)
+					(((cDataByte << cByteIndex) & 0x80)
+						? 0x01 : 0x00)) {
+						usErrorCount++;
+					}
+				}
+			}
+		}
+
+		/*
+		 * Write TDI data to the port.
+		 */
+
+		writePort(g_ucPinTDI,
+			(unsigned char)(((cInDataByte << cByteIndex) & 0x80)
+				? 0x01 : 0x00));
+
+		if (usDataSizeIndex < usLastBitIndex) {
+
+			/*
+			 * Clock data out from the data shift register.
+			 */
+
+			sclock();
+		} else if (g_usFlowControl & CASCADE) {
+
+			/*
+			 * Clock in last bit for the first N - 1 cascaded frames
+			 */
+
+			sclock();
+		}
+
+		/*
+		 * Increment the byte index. If it exceeds 7, then reset it back
+		 * to zero.
+		 */
+
+		cByteIndex++;
+		if (cByteIndex >= 8) {
+			if (ucDisplayFlag) {
+
+			/*
+			 * Store displayed data in the TDO buffer. By reusing
+			 * the TDO buffer to store displayed data, there is no
+			 * need to allocate a buffer simply to hold display
+			 * data. This will not cause any false verification
+			 * errors because the true TDO byte has already
+			 * been consumed.
+			 */
+
+				g_pucOutData[usBufferIndex - 1] = ucDisplayByte;
+				ucDisplayByte = 0;
+			}
+
+			cByteIndex = 0;
+		}
+		/* 09/12/07 Nguyen changed to display the 1 bit expected data */
+		else if (a_usiDataSize == 1) {
+			if (ucDisplayFlag) {
+
+				/*
+				 * Store displayed data in the TDO buffer.
+				 * By reusing the TDO buffer to store displayed
+				 * data, there is no need to allocate
+				 * a buffer simply to hold display data. This
+				 * will not cause any false verification errors
+				 * because the true TDO byte has already
+				 * been consumed.
+				 */
+
+				/*
+				 * Flip ucDisplayByte and store it in cDataByte.
+				 */
+				cDataByte = 0x00;
+				for (usBufferIndex = 0; usBufferIndex < 8;
+					usBufferIndex++) {
+					cDataByte <<= 1;
+					if (ucDisplayByte & 0x01) {
+						cDataByte |= 0x01;
+					}
+					ucDisplayByte >>= 1;
+				}
+				g_pucOutData[0] = cDataByte;
+				ucDisplayByte = 0;
+			}
+
+			cByteIndex = 0;
+		}
+	}
+
+	if (ucDisplayFlag) {
+
+#ifdef DEBUG
+		debug("RECEIVED TDO (");
+#else
+		vme_out_string("Display Data: 0x");
+#endif /* DEBUG */
+
+		/* 09/11/07 NN Type cast mismatch variables */
+		for (usDataSizeIndex = (unsigned short)
+				((a_usiDataSize + 7) / 8);
+			usDataSizeIndex > 0 ; usDataSizeIndex--) {
+			cMaskByte = g_pucOutData[usDataSizeIndex - 1];
+			cDataByte = 0x00;
+
+			/*
+			 * Flip cMaskByte and store it in cDataByte.
+			 */
+
+			for (usBufferIndex = 0; usBufferIndex < 8;
+				usBufferIndex++) {
+				cDataByte <<= 1;
+				if (cMaskByte & 0x01) {
+					cDataByte |= 0x01;
+				}
+				cMaskByte >>= 1;
+			}
+#ifdef DEBUG
+			printf("%.2X", cDataByte);
+			if ((((a_usiDataSize + 7) / 8) - usDataSizeIndex)
+				% 40 == 39) {
+				printf("\n\t\t");
+			}
+#else
+			vme_out_hex(cDataByte);
+#endif /* DEBUG */
+		}
+
+#ifdef DEBUG
+		printf(")\n\n");
+#else
+		vme_out_string("\n\n");
+#endif /* DEBUG */
+		/* 09/02/08 Nguyen changed to display the data Checksum */
+		if (g_usChecksum != 0) {
+			g_usChecksum &= 0xFFFF;
+			sprintf(StrChecksum, "Data Checksum: %.4lX\n\n",
+				g_usChecksum);
+			vme_out_string(StrChecksum);
+			g_usChecksum = 0;
+		}
+	}
+
+	if (usErrorCount > 0) {
+		if (g_usFlowControl & VERIFYUES) {
+			vme_out_string(
+				"USERCODE verification failed.   "
+				"Continue programming......\n\n");
+			g_usFlowControl &= ~(VERIFYUES);
+			return 0;
+		} else {
+
+#ifdef DEBUG
+			printf("TOTAL ERRORS: %d\n", usErrorCount);
+#endif /* DEBUG */
+
+			return VME_VERIFICATION_FAILURE;
+		}
+	} else {
+		if (g_usFlowControl & VERIFYUES) {
+			vme_out_string("USERCODE verification passed.    "
+				"Programming aborted.\n\n");
+			g_usFlowControl &= ~(VERIFYUES);
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+}
+
+/*
+ *
+ * ispVMReadandSave
+ *
+ * Support dynamic I/O.
+ *
+ */
+
+signed char ispVMReadandSave(unsigned short int a_usiDataSize)
+{
+	/* 09/11/07 NN added local variables initialization */
+	unsigned short int usDataSizeIndex = 0;
+	unsigned short int usLastBitIndex  = 0;
+	unsigned short int usBufferIndex   = 0;
+	unsigned short int usOutBitIndex   = 0;
+	unsigned short int usLVDSIndex     = 0;
+	unsigned char cDataByte            = 0;
+	unsigned char cDMASKByte           = 0;
+	unsigned char cInDataByte          = 0;
+	unsigned char cCurBit              = 0;
+	unsigned char cByteIndex           = 0;
+	signed char cLVDSByteIndex         = 0;
+
+	/* 09/11/07 NN Type cast mismatch variables */
+	usLastBitIndex = (unsigned short) (a_usiDataSize - 1);
+
+	/*
+	*
+	* Iterate through the data bits.
+	*
+	*/
+
+	for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize;
+		usDataSizeIndex++) {
+		if (cByteIndex == 0) {
+
+			/*
+			 * Grab byte from DMASK buffer.
+			 */
+
+			if (g_usDataType & DMASK_DATA) {
+				cDMASKByte = g_pucOutDMaskData[usBufferIndex];
+			} else {
+				cDMASKByte = 0x00;
+			}
+
+			/*
+			 * Grab byte from TDI buffer.
+			 */
+
+			if (g_usDataType & TDI_DATA) {
+				cInDataByte = g_pucInData[usBufferIndex];
+			}
+
+			usBufferIndex++;
+		}
+
+		cCurBit = readPort();
+		cDataByte = (unsigned char)(((cInDataByte << cByteIndex) & 0x80)
+			? 0x01 : 0x00);
+
+		/*
+		 * Initialize the byte to be zero.
+		 */
+
+		if (usOutBitIndex % 8 == 0) {
+			g_pucOutData[usOutBitIndex / 8] = 0x00;
+		}
+
+		/*
+		 * Use TDI, DMASK, and device TDO to create new TDI (actually
+		 * stored in g_pucOutData).
+		 */
+
+		if ((((cDMASKByte << cByteIndex) & 0x80) ? 0x01 : 0x00)) {
+
+			if (g_pLVDSList) {
+				for (usLVDSIndex = 0;
+					 usLVDSIndex < g_usLVDSPairCount;
+					usLVDSIndex++) {
+					if (g_pLVDSList[usLVDSIndex].
+						usNegativeIndex ==
+						usDataSizeIndex) {
+						g_pLVDSList[usLVDSIndex].
+							ucUpdate = 0x01;
+						break;
+					}
+				}
+			}
+
+			/*
+			 * DMASK bit is 1, use TDI.
+			 */
+
+			g_pucOutData[usOutBitIndex / 8] |= (unsigned char)
+				(((cDataByte & 0x1) ? 0x01 : 0x00) <<
+				(7 - usOutBitIndex % 8));
+		} else {
+
+			/*
+			 * DMASK bit is 0, use device TDO.
+			 */
+
+			g_pucOutData[usOutBitIndex / 8] |= (unsigned char)
+				(((cCurBit & 0x1) ? 0x01 : 0x00) <<
+				(7 - usOutBitIndex % 8));
+		}
+
+		/*
+		 * Shift in TDI in order to get TDO out.
+		 */
+
+		usOutBitIndex++;
+		writePort(g_ucPinTDI, cDataByte);
+		if (usDataSizeIndex < usLastBitIndex) {
+			sclock();
+		}
+
+		/*
+		 * Increment the byte index. If it exceeds 7, then reset it back
+		 * to zero.
+		 */
+
+		cByteIndex++;
+		if (cByteIndex >= 8) {
+			cByteIndex = 0;
+		}
+	}
+
+	/*
+	 * If g_pLVDSList exists and pairs need updating, then update
+	 * the negative-pair to receive the flipped positive-pair value.
+	 */
+
+	if (g_pLVDSList) {
+		for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount;
+			usLVDSIndex++) {
+			if (g_pLVDSList[usLVDSIndex].ucUpdate) {
+
+				/*
+				 * Read the positive value and flip it.
+				 */
+
+				cDataByte = (unsigned char)
+				 (((g_pucOutData[g_pLVDSList[usLVDSIndex].
+					usPositiveIndex / 8]
+					<< (g_pLVDSList[usLVDSIndex].
+					usPositiveIndex % 8)) & 0x80) ?
+					0x01 : 0x00);
+				/* 09/11/07 NN Type cast mismatch variables */
+				cDataByte = (unsigned char) (!cDataByte);
+
+				/*
+				 * Get the byte that needs modification.
+				 */
+
+				cInDataByte =
+				g_pucOutData[g_pLVDSList[usLVDSIndex].
+					usNegativeIndex / 8];
+
+				if (cDataByte) {
+
+					/*
+					 * Copy over the current byte and
+					 * set the negative bit to 1.
+					 */
+
+					cDataByte = 0x00;
+					for (cLVDSByteIndex = 7;
+						cLVDSByteIndex >= 0;
+						cLVDSByteIndex--) {
+						cDataByte <<= 1;
+						if (7 -
+						(g_pLVDSList[usLVDSIndex].
+							usNegativeIndex % 8) ==
+							cLVDSByteIndex) {
+
+							/*
+							 * Set negative bit to 1
+							 */
+
+							cDataByte |= 0x01;
+						} else if (cInDataByte & 0x80) {
+							cDataByte |= 0x01;
+						}
+
+						cInDataByte <<= 1;
+					}
+
+					/*
+					 * Store the modified byte.
+					 */
+
+					g_pucOutData[g_pLVDSList[usLVDSIndex].
+					usNegativeIndex / 8] = cDataByte;
+				} else {
+
+					/*
+					 * Copy over the current byte and set
+					 * the negative bit to 0.
+					 */
+
+					cDataByte = 0x00;
+					for (cLVDSByteIndex = 7;
+						cLVDSByteIndex >= 0;
+						cLVDSByteIndex--) {
+						cDataByte <<= 1;
+						if (7 -
+						(g_pLVDSList[usLVDSIndex].
+						usNegativeIndex % 8) ==
+						cLVDSByteIndex) {
+
+							/*
+							 * Set negative bit to 0
+							 */
+
+							cDataByte |= 0x00;
+						} else if (cInDataByte & 0x80) {
+							cDataByte |= 0x01;
+						}
+
+						cInDataByte <<= 1;
+					}
+
+					/*
+					 * Store the modified byte.
+					 */
+
+					g_pucOutData[g_pLVDSList[usLVDSIndex].
+					usNegativeIndex / 8] = cDataByte;
+				}
+
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+signed char ispVMProcessLVDS(unsigned short a_usLVDSCount)
+{
+	unsigned short usLVDSIndex = 0;
+
+	/*
+	 * Allocate memory to hold LVDS pairs.
+	 */
+
+	ispVMMemManager(LVDS, a_usLVDSCount);
+	g_usLVDSPairCount = a_usLVDSCount;
+
+#ifdef DEBUG
+	printf("LVDS %d (", a_usLVDSCount);
+#endif /* DEBUG */
+
+	/*
+	 * Iterate through each given LVDS pair.
+	 */
+
+	for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++) {
+
+		/*
+		 * Assign the positive and negative indices of the LVDS pair.
+		 */
+
+		/* 09/11/07 NN Type cast mismatch variables */
+		g_pLVDSList[usLVDSIndex].usPositiveIndex =
+			(unsigned short) ispVMDataSize();
+		/* 09/11/07 NN Type cast mismatch variables */
+		g_pLVDSList[usLVDSIndex].usNegativeIndex =
+			(unsigned short)ispVMDataSize();
+
+#ifdef DEBUG
+		if (usLVDSIndex < g_usLVDSPairCount - 1) {
+			printf("%d:%d, ",
+				g_pLVDSList[usLVDSIndex].usPositiveIndex,
+				g_pLVDSList[usLVDSIndex].usNegativeIndex);
+		} else {
+			printf("%d:%d",
+				g_pLVDSList[usLVDSIndex].usPositiveIndex,
+				g_pLVDSList[usLVDSIndex].usNegativeIndex);
+		}
+#endif /* DEBUG */
+
+	}
+
+#ifdef DEBUG
+	printf(");\n", a_usLVDSCount);
+#endif /* DEBUG */
+
+	return 0;
+}
diff --git a/drivers/fpga/lattice.c b/drivers/fpga/lattice.c
new file mode 100644
index 0000000..a0e7823
--- /dev/null
+++ b/drivers/fpga/lattice.c
@@ -0,0 +1,399 @@
+/*
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic at denx.de.
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland at enterasys.com.
+ *
+ * ispVM functions adapted from Lattice's ispmVMEmbedded code:
+ * Copyright 2009 Lattice Semiconductor Corp.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <fpga.h>
+#include <lattice.h>
+
+static lattice_board_specific_func *pfns;
+static char *fpga_image;
+static unsigned long read_bytes;
+static unsigned long bufsize;
+static unsigned short expectedCRC;
+
+/*
+ * External variables and functions declared in ivm_core.c module.
+ */
+extern unsigned short g_usCalculatedCRC;
+extern unsigned short g_usDataType;
+extern unsigned char *g_pucIntelBuffer;
+extern unsigned char *g_pucHeapMemory;
+extern unsigned short g_iHeapCounter;
+extern unsigned short g_iHEAPSize;
+extern unsigned short g_usIntelDataIndex;
+extern unsigned short g_usIntelBufferSize;
+extern char *const g_szSupportedVersions[];
+
+
+/*
+ * ispVMDelay
+ *
+ * Users must implement a delay to observe a_usTimeDelay, where
+ * bit 15 of the a_usTimeDelay defines the unit.
+ *      1 = milliseconds
+ *      0 = microseconds
+ * Example:
+ *      a_usTimeDelay = 0x0001 = 1 microsecond delay.
+ *      a_usTimeDelay = 0x8001 = 1 millisecond delay.
+ *
+ * This subroutine is called upon to provide a delay from 1 millisecond to a few
+ * hundreds milliseconds each time.
+ * It is understood that due to a_usTimeDelay is defined as unsigned short, a 16
+ * bits integer, this function is restricted to produce a delay to 64000
+ * micro-seconds or 32000 milli-second maximum. The VME file will never pass on
+ * to this function a delay time > those maximum number. If it needs more than
+ * those maximum, the VME file will launch the delay function several times to
+ * realize a larger delay time cummulatively.
+ * It is perfectly alright to provide a longer delay than required. It is not
+ * acceptable if the delay is shorter.
+ */
+void ispVMDelay(unsigned short delay)
+{
+	if (delay & 0x8000)
+		delay = (delay & ~0x8000) * 1000;
+	udelay(delay);
+}
+
+void writePort(unsigned char a_ucPins, unsigned char a_ucValue)
+{
+	a_ucValue = a_ucValue ? 1 : 0;
+
+	switch (a_ucPins) {
+	case g_ucPinTDI:
+		pfns->jtag_set_tdi(a_ucValue);
+		break;
+	case g_ucPinTCK:
+		pfns->jtag_set_tck(a_ucValue);
+		break;
+	case g_ucPinTMS:
+		pfns->jtag_set_tms(a_ucValue);
+		break;
+	default:
+		printf("%s: requested unknown pin\n", __func__);
+	}
+}
+
+unsigned char readPort(void)
+{
+	return pfns->jtag_get_tdo();
+}
+
+void sclock(void)
+{
+	writePort(g_ucPinTCK, 0x01);
+	writePort(g_ucPinTCK, 0x00);
+}
+
+void calibration(void)
+{
+	/* Apply 2 pulses to TCK. */
+	writePort(g_ucPinTCK, 0x00);
+	writePort(g_ucPinTCK, 0x01);
+	writePort(g_ucPinTCK, 0x00);
+	writePort(g_ucPinTCK, 0x01);
+	writePort(g_ucPinTCK, 0x00);
+
+	ispVMDelay(0x8001);
+
+	/* Apply 2 pulses to TCK. */
+	writePort(g_ucPinTCK, 0x01);
+	writePort(g_ucPinTCK, 0x00);
+	writePort(g_ucPinTCK, 0x01);
+	writePort(g_ucPinTCK, 0x00);
+}
+
+/*
+ * GetByte
+ *
+ * Returns a byte to the caller. The returned byte depends on the
+ * g_usDataType register. If the HEAP_IN bit is set, then the byte
+ * is returned from the HEAP. If the LHEAP_IN bit is set, then
+ * the byte is returned from the intelligent buffer. Otherwise,
+ * the byte is returned directly from the VME file.
+ */
+unsigned char GetByte(void)
+{
+	unsigned char ucData;
+	unsigned int block_size = 4 * 1024;
+
+	if (g_usDataType & HEAP_IN) {
+
+		/*
+		 * Get data from repeat buffer.
+		 */
+
+		if (g_iHeapCounter > g_iHEAPSize) {
+
+			/*
+			 * Data over-run.
+			 */
+
+			return 0xFF;
+		}
+
+		ucData = g_pucHeapMemory[g_iHeapCounter++];
+	} else if (g_usDataType & LHEAP_IN) {
+
+		/*
+		 * Get data from intel buffer.
+		 */
+
+		if (g_usIntelDataIndex >= g_usIntelBufferSize) {
+			return 0xFF;
+		}
+
+		ucData = g_pucIntelBuffer[g_usIntelDataIndex++];
+	} else {
+		if (read_bytes == bufsize) {
+			return 0xFF;
+		}
+		ucData = *fpga_image++;
+		read_bytes++;
+
+		if (!(read_bytes % block_size)) {
+			printf("Downloading FPGA %ld/%ld completed\r",
+				read_bytes,
+				bufsize);
+		}
+
+		if (expectedCRC != 0) {
+			ispVMCalculateCRC32(ucData);
+		}
+	}
+
+	return ucData;
+}
+
+signed char ispVM(void)
+{
+	char szFileVersion[9]      = { 0 };
+	signed char cRetCode         = 0;
+	signed char cIndex           = 0;
+	signed char cVersionIndex    = 0;
+	unsigned char ucReadByte     = 0;
+	unsigned short crc;
+
+	g_pucHeapMemory		= NULL;
+	g_iHeapCounter		= 0;
+	g_iHEAPSize		= 0;
+	g_usIntelDataIndex	= 0;
+	g_usIntelBufferSize	= 0;
+	g_usCalculatedCRC = 0;
+	expectedCRC   = 0;
+	ucReadByte = GetByte();
+	switch (ucReadByte) {
+	case FILE_CRC:
+		crc = (unsigned char)GetByte();
+		crc <<= 8;
+		crc |= GetByte();
+		expectedCRC = crc;
+
+		for (cIndex = 0; cIndex < 8; cIndex++)
+			szFileVersion[cIndex] = GetByte();
+
+		break;
+	default:
+		szFileVersion[0] = (signed char) ucReadByte;
+		for (cIndex = 1; cIndex < 8; cIndex++)
+			szFileVersion[cIndex] = GetByte();
+
+		break;
+	}
+
+	/*
+	 *
+	 * Compare the VME file version against the supported version.
+	 *
+	 */
+
+	for (cVersionIndex = 0; g_szSupportedVersions[cVersionIndex] != 0;
+		cVersionIndex++) {
+		for (cIndex = 0; cIndex < 8; cIndex++) {
+			if (szFileVersion[cIndex] !=
+				g_szSupportedVersions[cVersionIndex][cIndex]) {
+				cRetCode = VME_VERSION_FAILURE;
+				break;
+			}
+			cRetCode = 0;
+		}
+
+		if (cRetCode == 0) {
+			break;
+		}
+	}
+
+	if (cRetCode < 0) {
+		return VME_VERSION_FAILURE;
+	}
+
+	printf("VME file checked: starting downloading to FPGA\n");
+
+	ispVMStart();
+
+	cRetCode = ispVMCode();
+
+	ispVMEnd();
+	ispVMFreeMem();
+	puts("\n");
+
+	if (cRetCode == 0 && expectedCRC != 0 &&
+			(expectedCRC != g_usCalculatedCRC)) {
+		printf("Expected CRC:   0x%.4X\n", expectedCRC);
+		printf("Calculated CRC: 0x%.4X\n", g_usCalculatedCRC);
+		return VME_CRC_FAILURE;
+	}
+	return cRetCode;
+}
+
+static int lattice_validate(Lattice_desc *desc, const char *fn)
+{
+	int ret_val = FALSE;
+
+	if (desc) {
+		if ((desc->family > min_lattice_type) &&
+			(desc->family < max_lattice_type)) {
+			if ((desc->iface > min_lattice_iface_type) &&
+				(desc->iface < max_lattice_iface_type)) {
+				if (desc->size) {
+					ret_val = TRUE;
+				} else {
+					printf("%s: NULL part size\n", fn);
+				}
+			} else {
+				printf("%s: Invalid Interface type, %d\n",
+					fn, desc->iface);
+			}
+		} else {
+			printf("%s: Invalid family type, %d\n",
+				fn, desc->family);
+		}
+	} else {
+		printf("%s: NULL descriptor!\n", fn);
+	}
+
+	return ret_val;
+}
+
+int lattice_load(Lattice_desc *desc, void *buf, size_t bsize)
+{
+	int ret_val = FPGA_FAIL;
+
+	if (!lattice_validate(desc, (char *)__func__)) {
+		printf("%s: Invalid device descriptor\n", __func__);
+	} else {
+		pfns = desc->iface_fns;
+
+		switch (desc->family) {
+		case Lattice_XP2:
+			fpga_image = buf;
+			read_bytes = 0;
+			bufsize = bsize;
+			debug("%s: Launching the Lattice ISPVME Loader:"
+				" addr 0x%x size 0x%x...\n",
+				__func__, fpga_image, bufsize);
+			ret_val = ispVM();
+			if (ret_val)
+				printf("%s: error %d downloading FPGA image\n",
+					__func__, ret_val);
+			else
+				puts("FPGA downloaded successfully\n");
+			break;
+		default:
+			printf("%s: Unsupported family type, %d\n",
+					__func__, desc->family);
+		}
+	}
+
+	return ret_val;
+}
+
+int lattice_dump(Lattice_desc *desc, void *buf, size_t bsize)
+{
+	puts("Dump not supported for Lattice FPGA\n");
+
+	return FPGA_FAIL;
+
+}
+
+int lattice_info(Lattice_desc *desc)
+{
+	int ret_val = FPGA_FAIL;
+
+	if (lattice_validate(desc, (char *)__func__)) {
+		printf("Family:        \t");
+		switch (desc->family) {
+		case Lattice_XP2:
+			puts("XP2\n");
+			break;
+			/* Add new family types here */
+		default:
+			printf("Unknown family type, %d\n", desc->family);
+		}
+
+		puts("Interface type:\t");
+		switch (desc->iface) {
+		case lattice_jtag_mode:
+			puts("JTAG Mode\n");
+			break;
+			/* Add new interface types here */
+		default:
+			printf("Unsupported interface type, %d\n", desc->iface);
+		}
+
+		printf("Device Size:   \t%d bytes\n",
+				desc->size);
+
+		if (desc->iface_fns) {
+			printf("Device Function Table @ 0x%p\n",
+				desc->iface_fns);
+			switch (desc->family) {
+			case Lattice_XP2:
+				break;
+				/* Add new family types here */
+			default:
+				break;
+			}
+		} else {
+			puts("No Device Function Table.\n");
+		}
+
+		if (desc->desc)
+			printf("Model:         \t%s\n", desc->desc);
+
+		ret_val = FPGA_SUCCESS;
+	} else {
+		printf("%s: Invalid device descriptor\n", __func__);
+	}
+
+	return ret_val;
+}
+
+
diff --git a/include/fpga.h b/include/fpga.h
index 84d7b9f..ac24f2b 100644
--- a/include/fpga.h
+++ b/include/fpga.h
@@ -61,6 +61,7 @@ typedef enum {			/* typedef fpga_type */
 	fpga_min_type,		/* range check value */
 	fpga_xilinx,		/* Xilinx Family) */
 	fpga_altera,		/* unimplemented */
+	fpga_lattice,		/* Lattice family */
 	fpga_undefined		/* invalid range check value */
 } fpga_type;			/* end, typedef fpga_type */
 
diff --git a/include/lattice.h b/include/lattice.h
new file mode 100755
index 0000000..33d2ac3
--- /dev/null
+++ b/include/lattice.h
@@ -0,0 +1,319 @@
+/*
+ * Porting to U-Boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic at denx.de.
+ *
+ * Lattice's ispVME Embedded Tool to load Lattice's FPGA:
+ *
+ * Lattice Semiconductor Corp. Copyright 2009
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef _VME_OPCODE_H
+#define _VME_OPCODE_H
+
+#define VME_VERSION_NUMBER "12.1"
+
+/* Maximum declarations. */
+
+#define VMEHEXMAX	60000L	/* The hex file is split 60K per file. */
+#define SCANMAX		64000L	/* The maximum SDR/SIR burst. */
+
+/*
+ *
+ * Supported JTAG state transitions.
+ *
+ */
+
+#define RESET		0x00
+#define IDLE		0x01
+#define IRPAUSE		0x02
+#define DRPAUSE		0x03
+#define SHIFTIR		0x04
+#define SHIFTDR		0x05
+/* 11/15/05 Nguyen changed to support DRCAPTURE*/
+#define DRCAPTURE	0x06
+
+/*
+ * Flow control register bit definitions.  A set bit indicates
+ * that the register currently exhibits the corresponding mode.
+ */
+
+#define INTEL_PRGM	0x0001	/* Intelligent programming is in effect. */
+#define CASCADE		0x0002	/* Currently splitting large SDR. */
+#define REPEATLOOP	0x0008	/* Currently executing a repeat loop. */
+#define SHIFTRIGHT	0x0080	/* The next data stream needs a right shift. */
+#define SHIFTLEFT	0x0100	/* The next data stream needs a left shift. */
+#define VERIFYUES	0x0200	/* Continue if fail is in effect. */
+
+/*
+ * DataType register bit definitions.  A set bit indicates
+ * that the register currently holds the corresponding type of data.
+ */
+
+#define EXPRESS		0x0001    /* Simultaneous program and verify. */
+#define SIR_DATA	0x0002    /* SIR is the active SVF command. */
+#define SDR_DATA	0x0004    /* SDR is the active SVF command. */
+#define COMPRESS	0x0008    /* Data is compressed. */
+#define TDI_DATA	0x0010    /* TDI data is present. */
+#define TDO_DATA	0x0020    /* TDO data is present. */
+#define MASK_DATA	0x0040    /* MASK data is present. */
+#define HEAP_IN		0x0080    /* Data is from the heap. */
+#define LHEAP_IN	0x0200    /* Data is from intel data buffer. */
+#define VARIABLE	0x0400    /* Data is from a declared variable. */
+#define CRC_DATA	0x0800	 /* CRC data is pressent. */
+#define CMASK_DATA	0x1000    /* CMASK data is pressent. */
+#define RMASK_DATA	0x2000	 /* RMASK data is pressent. */
+#define READ_DATA	0x4000    /* READ data is pressent. */
+#define DMASK_DATA	0x8000	 /* DMASK data is pressent. */
+
+/*
+ *
+ * Pin opcodes.
+ *
+ */
+
+#define signalENABLE	0x1C    /* ispENABLE pin. */
+#define signalTMS	0x1D    /* TMS pin. */
+#define signalTCK	0x1E    /* TCK pin. */
+#define signalTDI	0x1F    /* TDI pin. */
+#define signalTRST	0x20    /* TRST pin. */
+
+/*
+ *
+ * Supported vendors.
+ *
+ */
+
+#define VENDOR		0x56
+#define LATTICE		0x01
+#define ALTERA		0x02
+#define XILINX		0x03
+
+/*
+ * Opcode definitions.
+ *
+ * Note: opcodes must be unique.
+ */
+
+#define ENDDATA		0x00	/* The end of the current SDR data stream. */
+#define RUNTEST		0x01	/* The duration to stay at the stable state. */
+#define ENDDR		0x02	/* The stable state after SDR. */
+#define ENDIR		0x03	/* The stable state after SIR. */
+#define ENDSTATE	0x04	/* The stable state after RUNTEST. */
+#define TRST		0x05	/* Assert the TRST pin. */
+#define HIR		0x06	/*
+				 * The sum of the IR bits of the
+				 * leading devices.
+				 */
+#define TIR		0x07	/*
+				 * The sum of the IR bits of the trailing
+				 * devices.
+				 */
+#define HDR		0x08	/* The number of leading devices. */
+#define TDR		0x09	/* The number of trailing devices. */
+#define ispEN		0x0A	/* Assert the ispEN pin. */
+#define FREQUENCY	0x0B	/*
+				 * The maximum clock rate to run the JTAG state
+				 * machine.
+				 */
+#define STATE		0x10	/* Move to the next stable state. */
+#define SIR		0x11	/* The instruction stream follows. */
+#define SDR		0x12	/* The data stream follows. */
+#define TDI		0x13	/* The following data stream feeds into
+					the device. */
+#define TDO		0x14	/*
+				 * The following data stream is compared against
+				 * the device.
+				 */
+#define MASK		0x15	/* The following data stream is used as mask. */
+#define XSDR		0x16	/*
+				 * The following data stream is for simultaneous
+				 * program and verify.
+				 */
+#define XTDI		0x17	/* The following data stream is for shift in
+				 * only. It must be stored for the next
+				 * XSDR.
+				 */
+#define XTDO		0x18	/*
+				 * There is not data stream.  The data stream
+				 * was stored from the previous XTDI.
+				 */
+#define MEM		0x19	/*
+				 * The maximum memory needed to allocate in
+				 * order hold one row of data.
+				 */
+#define WAIT		0x1A	/* The duration of delay to observe. */
+#define TCK		0x1B	/* The number of TCK pulses. */
+#define SHR		0x23	/*
+				 * Set the flow control register for
+				 * right shift
+				 */
+#define SHL		0x24	/*
+				 * Set the flow control register for left shift.
+				 */
+#define HEAP		0x32	/* The memory size needed to hold one loop. */
+#define REPEAT		0x33	/* The beginning of the loop. */
+#define LEFTPAREN	0x35	/* The beginning of data following the loop. */
+#define VAR		0x55	/* Plac holder for loop data. */
+#define SEC		0x1C	/*
+				 * The delay time in seconds that must be
+				 * observed.
+				 */
+#define SMASK		0x1D	/* The mask for TDI data. */
+#define MAX_WAIT	0x1E	/* The absolute maximum wait time. */
+#define ON		0x1F	/* Assert the targeted pin. */
+#define OFF		0x20	/* Dis-assert the targeted pin. */
+#define SETFLOW		0x30	/* Change the flow control register. */
+#define RESETFLOW	0x31	/* Clear the flow control register. */
+
+#define CRC		0x47	/*
+				 * The following data stream is used for CRC
+				 * calculation.
+				 */
+#define CMASK		0x48	/*
+				 * The following data stream is used as mask
+				 * for CRC calculation.
+				 */
+#define RMASK		0x49	/*
+				 * The following data stream is used as mask
+				 * for read and save.
+				 */
+#define READ		0x50	/*
+				 * The following data stream is used for read
+				 * and save.
+				 */
+#define ENDLOOP		0x59	/* The end of the repeat loop. */
+#define SECUREHEAP	0x60	/* Used to secure the HEAP opcode. */
+#define VUES		0x61	/* Support continue if fail. */
+#define DMASK		0x62	/*
+				 * The following data stream is used for dynamic
+				 * I/O.
+				 */
+#define COMMENT		0x63	/* Support SVF comments in the VME file. */
+#define HEADER		0x64	/* Support header in VME file. */
+#define FILE_CRC	0x65	/* Support crc-protected VME file. */
+#define LCOUNT		0x66	/* Support intelligent programming. */
+#define LDELAY		0x67	/* Support intelligent programming. */
+#define LSDR		0x68	/* Support intelligent programming. */
+#define LHEAP		0x69	/*
+				 * Memory needed to hold intelligent data
+				 * buffer
+				 */
+#define CONTINUE	0x70	/* Allow continuation. */
+#define LVDS		0x71	/* Support LVDS. */
+#define ENDVME		0x7F	/* End of the VME file. */
+#define ENDFILE		0xFF	/* End of file. */
+
+/*
+ *
+ * ispVM Embedded Return Codes.
+ *
+ */
+
+#define VME_VERIFICATION_FAILURE	-1
+#define VME_FILE_READ_FAILURE		-2
+#define VME_VERSION_FAILURE		-3
+#define VME_INVALID_FILE		-4
+#define VME_ARGUMENT_FAILURE		-5
+#define VME_CRC_FAILURE			-6
+
+#define g_ucPinTDI	0x01
+#define g_ucPinTCK	0x02
+#define g_ucPinTMS	0x04
+#define g_ucPinENABLE	0x08
+#define g_ucPinTRST	0x10
+
+/*
+ *
+ * Type definitions.
+ *
+ */
+
+/* Support LVDS */
+typedef struct {
+	unsigned short usPositiveIndex;
+	unsigned short usNegativeIndex;
+	unsigned char  ucUpdate;
+} LVDSPair;
+
+typedef enum {
+	min_lattice_iface_type,		/* insert all new types after this */
+	lattice_jtag_mode,		/* jtag/tap  */
+	max_lattice_iface_type		/* insert all new types before this */
+} Lattice_iface;
+
+typedef enum {
+	min_lattice_type,
+	Lattice_XP2,			/* Lattice XP2 Family */
+	max_lattice_type		/* insert all new types before this */
+} Lattice_Family;
+
+typedef struct {
+	Lattice_Family	family;	/* part type */
+	Lattice_iface	iface;	/* interface type */
+	size_t		size;	/* bytes of data part can accept */
+	void		*iface_fns; /* interface function table */
+	void		*base;	/* base interface address */
+	int		cookie;	/* implementation specific cookie */
+	char		*desc;	/* description string */
+} Lattice_desc;			/* end, typedef Altera_desc */
+
+/* Lattice Model Type */
+#define CONFIG_SYS_XP2		CONFIG_SYS_FPGA_DEV(0x1)
+
+/* Board specific implementation specific function types */
+typedef void (*Lattice_jtag_init)(void);
+typedef void (*Lattice_jtag_set_tdi)(int v);
+typedef void (*Lattice_jtag_set_tms)(int v);
+typedef void (*Lattice_jtag_set_tck)(int v);
+typedef int (*Lattice_jtag_get_tdo)(void);
+
+typedef struct {
+	Lattice_jtag_init	jtag_init;
+	Lattice_jtag_set_tdi	jtag_set_tdi;
+	Lattice_jtag_set_tms	jtag_set_tms;
+	Lattice_jtag_set_tck	jtag_set_tck;
+	Lattice_jtag_get_tdo	jtag_get_tdo;
+} lattice_board_specific_func;
+
+void writePort(unsigned char pins, unsigned char value);
+unsigned char readPort(void);
+void sclock(void);
+void ispVMDelay(unsigned short int a_usMicroSecondDelay);
+void calibration(void);
+
+int lattice_load(Lattice_desc *desc, void *buf, size_t bsize);
+int lattice_dump(Lattice_desc *desc, void *buf, size_t bsize);
+int lattice_info(Lattice_desc *desc);
+
+void ispVMStart(void);
+void ispVMEnd(void);
+signed char ispVMCode(void);
+void ispVMDelay(unsigned short int a_usMicroSecondDelay);
+void ispVMCalculateCRC32(unsigned char a_ucData);
+unsigned char GetByte(void);
+void writePort(unsigned char pins, unsigned char value);
+unsigned char readPort(void);
+void sclock(void);
+#endif
+
-- 
1.6.3.3



More information about the U-Boot mailing list