/* ---------------------------------------------------------------- * morphic_program.c * * 8/3/2011 D. W. Hawkins (dwh@ovro.caltech.edu) * * Program the Morph-IC FPGA. * * Morph-IC is a development kit from Future Technology * Devices, Inc (FTDI) containing an FT2232 USB-to-serial * interface and an Altera ACEX 1K FPGA. * * This program uses the FTDI direct programming interface * library (FTD2XX) to configure the FT2232 device into * MPSSE (multi-protocol synchronous serial engine) mode * and then program the FPGA using passive serial mode. * * ---------------------------------------------------------------- * Notes: * ------ * * 1. Operating systems support * * The Makefile supports building for Cygwin and Linux. The * application uses getopt, which was not supported by any * standard Microsoft Visual Studio 2010 libraries. * * 2. Coding style * * The coding style is ugly. This is a one-off program to * get the FPGA on the board programmed, so the style was * not a design consideration. * * ---------------------------------------------------------------- * References: * ----------- * * [1] FTDI, "D2XX Programmers Guide", version 1.2, 2011. * * [2] FTDI, "AN108: Command processor for MPSSE and MCU host bus * emulation modes", version 1.4, 2011. * * [3] FTDI, "AN135: FTDI MPSSE Basics", version 1.1, 2010. * * [4] FTDI, "TN109: Instructions on including the FTD2XX DLL in a * VS2008 project", version 1.0, 2009. * * [5] FTDI, "FT2232C Dual USB UART/FIFO IC", version 1.4, 2005. * * [6] FTDI, "Morph-IC datasheet", version 1.0, 2004. * * ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- * Includes * ---------------------------------------------------------------- */ /* Standard C includes */ #include #include #include #include #include #include #include #include /* Windows datatypes used by the FTDI D2XX direct API header */ #ifdef __linux__ #include "WinTypes.h" /* FTDI D2XX direct API - version 1.0.4 header/library */ #include "ftd2xx_linux.h" #else #include /* FTDI D2XX direct API - version 2.08.14 header/library */ #include "ftd2xx.h" #endif /* ---------------------------------------------------------------- * Local function declarations * ---------------------------------------------------------------- */ static void show_usage(void); /* ---------------------------------------------------------------- * Main application * ---------------------------------------------------------------- */ int main( int argc, char **argv) { int opt; int option_index = 0; static struct option long_options[] = { /* Long options */ /* Long and short options */ {"file", 1, 0, 'f'}, {"help", 0, 0, 'h'}, {"clear", 0, 0, 'x'}, {0, 0, 0, 0} }; FT_STATUS ftStatus; FT_HANDLE ftHandle; // UCHAR bitmode; // DWORD pid, vid; DWORD i; DWORD nDevices; DWORD bytesToRead, bytesRead; DWORD bytesToWrite, bytesWritten; char *buffer; BYTE *readBuffer; BYTE *writeBuffer; DWORD Flags; DWORD ID; DWORD Type; DWORD LocId; char SerialNumber[16]; char Description[64]; #ifdef __CYGWIN__ DWORD version; #endif // char rbf_filename[] = "morphio.rbf"; // char rbf_filename[] = "morphic_basic.rbf"; char *rbf_filename = NULL; int rbf_size; int fd; int clear_config = 0; int morphic_detected = 0; BYTE nSTATUS, nCONF_DONE; while ((opt = getopt_long( argc, argv, "f:hx", long_options, &option_index)) != -1) { switch (opt) { /* Long options */ /* Long and short options */ case 'f': rbf_filename = optarg; break; case 'h': show_usage(); return 0; case 'x': clear_config = 1; break; default: show_usage(); return 0; } } if (clear_config == 0) { if ( (rbf_filename == NULL) || (strlen(rbf_filename) == 0)) { printf("Error: FPGA configuration file (.rbf) filename required\n"); printf("\nUse morphic_program -h to see the correct program usage\n\n"); return -1; } } printf("\n"); printf("Morph-IC programmer\n"); printf("-------------------\n"); /* ------------------------------------------------------------ * Buffers * ------------------------------------------------------------ */ buffer = (char *)malloc(1024); if (buffer == NULL) { printf("Error: buffer allocation failed!\n"); return -1; } memset(buffer,0, 1024); readBuffer = (BYTE *)malloc(1024); if (readBuffer == NULL) { printf("Error: readBuffer allocation failed!\n"); return -1; } memset(readBuffer,0, 1024); writeBuffer = (BYTE *)malloc(1024); if (writeBuffer == NULL) { printf("Error: writeBuffer allocation failed!\n"); return -1; } memset(writeBuffer,0, 1024); /* ------------------------------------------------------------ * Confirm the device is a Morph-IC * ------------------------------------------------------------ */ morphic_detected = 0; printf("Use FT_CreateDeviceInfoList() to get the number "\ "of devices\n"); nDevices = 0; ftStatus = FT_CreateDeviceInfoList(&nDevices); if (ftStatus != FT_OK) { printf("Error: FT_CreateDeviceInfoList returned %d\n", (int)ftStatus); return 1; } printf(" * number of devices = %d\n", (int)nDevices); if (nDevices == 0) { printf("Error: the Morph-IC board was not detected\n"); return -1; } /* * D2XX programmer's manual methods for accessing the device * descriptions, locations, and serial numbers. * * p10 has an example * * The output for the Morph-IC is * * Device 0: * Flags = 0h * Type = 4h * ID = 4036010h * LocID = 5021h * SerialNumber = FTMJZ5JSA * Description = Morph-IC A * Handle = 0h * * Device 1: * Flags = 0h * Type = 4h * ID = 4036010h * LocID = 5022h * SerialNumber = FTMJZ5JSB * Description = Morph-IC B * Handle = 0h */ printf("Use FT_GetDeviceInfoDetail() to list the device "\ "properties for the %d devices\n", (int)nDevices); for (i = 0; i < nDevices; i++) { printf(" * Device %d:\n", (int)i); ftStatus = FT_GetDeviceInfoDetail( i, &Flags, &Type, &ID, &LocId, SerialNumber, Description, &ftHandle); if (ftStatus != FT_OK) { printf("Error: FT_GetDeviceInfoDetail returned %d\n", (int)ftStatus); return 1; } printf(" Flags = %Xh\n"\ " Type = %Xh\n"\ " ID = %Xh\n"\ " LocID = %Xh\n"\ " SerialNumber = '%s'\n"\ " Description = '%s'\n"\ " Handle = %Xh\n", (int)Flags, (int)Type, (int)ID, (int)LocId, SerialNumber, Description, (int)ftHandle); if (i == 0) { if (strncmp(Description, "Morph-IC A", 10) == 0) { morphic_detected = 1; } } } if (morphic_detected == 0) { printf("Error: the Morph-IC board was not detected\n"); #ifdef __linux__ printf("Note: make sure to rmmod ftdi_sio\n"); #endif return 1; } else { printf(" * Morph-IC detected\n"); } /* ------------------------------------------------------------ * MPSSE setup per AN-135 * ------------------------------------------------------------ */ printf("Setup MPSSE mode\n"); printf(" * open the device at index 0\n"); ftStatus = FT_Open( 0, &ftHandle); if (ftStatus != FT_OK) { printf("Error: FT_Open returned %d\n", (int)ftStatus); #ifdef __linux__ if (ftStatus == FT_DEVICE_NOT_OPENED) { printf("Note: make sure to rmmod ftdi_sio\n"); } #endif return 1; } /* The library and driver version functions are windows-only */ #ifdef __CYGWIN__ ftStatus = FT_GetLibraryVersion(&version); if (ftStatus != FT_OK) { printf("Error: FT_GetLibraryVersion returned %d\n", (int)ftStatus); return 1; } printf(" * FTDI library version %.8X\n", (int)version); ftStatus = FT_GetDriverVersion(ftHandle, &version); if (ftStatus != FT_OK) { printf("Error: FT_GetDriverVersion returned %d\n", (int)ftStatus); return 1; } printf(" * FTDI driver version %.8X\n", (int)version); #endif ftStatus = FT_ResetDevice(ftHandle); if (ftStatus != FT_OK) { printf(" * device %d reset failed - %d\n", (int)i, (int)ftStatus); return 1; } ftStatus = FT_GetQueueStatus(ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } printf(" * %d bytes in receive queue\n", (int)bytesToRead); if (bytesToRead > 0) { ftStatus = FT_Read(ftHandle, readBuffer, (int)bytesToRead, &bytesRead); if (ftStatus != FT_OK) { printf("Error: FT_Read returned %d\n", (int)ftStatus); return 1; } } ftStatus = FT_SetUSBParameters(ftHandle, 1<<16, (1<<16)); if (ftStatus != FT_OK) { printf("Error: FT_SetUSBParameters returned %d\n", (int)ftStatus); return 1; } ftStatus = FT_SetChars(ftHandle, 0, 0, 0, 0); if (ftStatus != FT_OK) { printf("Error: FT_SetChars returned %d\n", (int)ftStatus); return 1; } ftStatus = FT_SetTimeouts(ftHandle, 0, 5000); if (ftStatus != FT_OK) { printf("Error: FT_SetTimeouts returned %d\n", (int)ftStatus); return 1; } ftStatus = FT_SetLatencyTimer(ftHandle, 1); if (ftStatus != FT_OK) { printf("Error: FT_SetLatencyTimer returned %d\n", (int)ftStatus); return 1; } ftStatus = FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0, 0); if (ftStatus != FT_OK) { printf("Error: FT_SetFlowControl returned %d\n", (int)ftStatus); return 1; } printf(" * set the bit mode to MPSSE\n"); ftStatus = FT_SetBitMode(ftHandle, 0, 0); if (ftStatus != FT_OK) { printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus); return 1; } ftStatus = FT_SetBitMode(ftHandle, 0, 2); if (ftStatus != FT_OK) { printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus); return 1; } /* Wait for the USB transactions to complete per p16 AN135 */ usleep(50000); printf(" * synchronize to the MPSSE\n"); /* Loopback mode */ printf(" - enable loopback mode\n"); writeBuffer[0] = 0x84; /* OPCODE: loopback enable */ bytesToWrite = 1; ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes\n", (int)bytesWritten); return 1; } ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } if (bytesToRead != 0) { printf("Error: The MPSSE receive buffer should be empty\n"); return 1; } /* Send a bogus command and check the echo */ printf(" - send a bogus command\n"); writeBuffer[0] = 0xAB; bytesToWrite = 1; ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } if (bytesWritten != bytesToWrite) { printf("Error: bytes were not written!\n"); return 1; } printf(" - poll for the command echo\n"); bytesToRead = 0; while (bytesToRead == 0) { ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } printf(" - bytesToRead = %d\n", (int)bytesToRead); } ftStatus = FT_Read(ftHandle, readBuffer, (int)bytesToRead, &bytesRead); if (ftStatus != FT_OK) { printf("Error: FT_Read returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes received\n", (int)bytesRead); for (i = 0; i < bytesRead; i++) { printf(" %.2X\n", (int)readBuffer[i]); } if (bytesRead != 2) { printf("Error: FT_Read should have returned 2-bytes\n"); return 1; } if ((readBuffer[0] != 0xFA) && (readBuffer[1] != 0xAB)) { printf("Error: MPSSE is not synchronized\n"); return 1; } else { printf(" * MPSSE synchronized Ok\n"); } /* Disable loopback mode */ printf(" - disable loopback mode\n"); writeBuffer[0] = 0x85; /* OPCODE: loopback disable */ bytesToWrite = 1; ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } if (bytesToRead != 0) { printf("Error: The MPSSE receive buffer should be empty\n"); return 1; } /* Setup the port for FPGA configuration at 6MHz per the * Morph-IC Delphi example code */ printf("Setup and read-back the MPSSE pins\n"); printf(" * Configure MPSSE\n"); bytesToWrite = 0; writeBuffer[bytesToWrite++] = 0x86; /* OPCODE: set TCK divisor */ writeBuffer[bytesToWrite++] = 0x00; /* divisor low-byte */ writeBuffer[bytesToWrite++] = 0x00; /* divisor high-byte */ writeBuffer[bytesToWrite++] = 0x80; /* OPCODE: Set low-byte data bits */ writeBuffer[bytesToWrite++] = 0x06; /* value; CONFIG# and DATA0 high */ writeBuffer[bytesToWrite++] = 0x87; /* direction */ ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } /* Read the MPSSE pin values */ printf(" * Read the MPSSE pins\n"); bytesToWrite = 0; writeBuffer[bytesToWrite++] = 0x81; /* OPCODE: Read low-byte data bits */ writeBuffer[bytesToWrite++] = 0x87; /* OPCODE: Send immediate */ ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } bytesToRead = 0; while (bytesToRead == 0) { ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } printf(" - bytesToRead = %d\n", (int)bytesToRead); } ftStatus = FT_Read(ftHandle, readBuffer, (int)bytesToRead, &bytesRead); if (ftStatus != FT_OK) { printf("Error: FT_Read returned %d\n", (int)ftStatus); return 1; } printf(" * %d-bytes received\n", (int)bytesRead); if (bytesRead != 1) { printf("Error: only one byte should have been returned\n"); return 1; } printf(" * Passive serial configuration pins\n"); printf(" DCLK = %d\n", readBuffer[0] & 1); printf(" DATA0 = %d\n", (readBuffer[0]>>1) & 1); printf(" nCONFIG = %d\n", (readBuffer[0]>>2) & 1); printf(" nSTATUS = %d\n", (readBuffer[0]>>3) & 1); printf(" CONF_DONE = %d\n", (readBuffer[0]>>4) & 1); printf(" nRESET = %d\n", (readBuffer[0]>>7) & 1); nCONF_DONE = (readBuffer[0]>>4) & 1; if ((clear_config == 1) && (nCONF_DONE == 0)) { /* All done */ printf("The FPGA was not configured\n"); free(buffer); free(readBuffer); free(writeBuffer); FT_Close(ftHandle); return 0; } printf("Pulse nCONFIG (5us)\n"); printf(" * Set nCONFIG low for 5 writes, then high\n"); bytesToWrite = 0; writeBuffer[bytesToWrite++] = 0x80; /* OPCODE: Set low-byte data bits */ writeBuffer[bytesToWrite++] = 0x06; /* value; nCONFIG and DATA0 high */ writeBuffer[bytesToWrite++] = 0x87; /* direction */ /* The tCFG requirement for an ACEX 1K is 2us minimum, * and tCFG2CK is 5us. Since each MPSSE command takes * about 1us, set nCONFIG low 5 times. */ for (i = 0; i < 5; i++) { writeBuffer[bytesToWrite++] = 0x80; writeBuffer[bytesToWrite++] = 0x02; /* nCONFIG low */ writeBuffer[bytesToWrite++] = 0x87; } writeBuffer[bytesToWrite++] = 0x80; writeBuffer[bytesToWrite++] = 0x06; /* nCONFIG high */ writeBuffer[bytesToWrite++] = 0x87; ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } /* Read the MPSSE pin values and confirm nSTATUS and nCONFIG */ printf(" * Read the MPSSE pins\n"); bytesToWrite = 0; writeBuffer[bytesToWrite++] = 0x81; /* OPCODE: Read low-byte data bits */ writeBuffer[bytesToWrite++] = 0x87; /* OPCODE: Send immediate */ ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } bytesToRead = 0; while (bytesToRead == 0) { ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } printf(" - bytesToRead = %d\n", (int)bytesToRead); } ftStatus = FT_Read(ftHandle, readBuffer, (int)bytesToRead, &bytesRead); if (ftStatus != FT_OK) { printf("Error: FT_Read returned %d\n", (int)ftStatus); return 1; } if (bytesRead != 1) { printf("Error: only one byte should have been returned\n"); return 1; } nSTATUS = (readBuffer[0]>>3) & 1; nCONF_DONE = (readBuffer[0]>>4) & 1; if (nSTATUS != 1) { printf("Error: nSTATUS should be high\n"); return 1; } if (nCONF_DONE != 0) { printf("Error: CONF_DONE should be low\n"); return 1; } if (clear_config == 1) { /* All done */ printf("The FPGA configuration has been cleared\n"); free(buffer); free(readBuffer); free(writeBuffer); FT_Close(ftHandle); return 0; } /* Check the RBF file size */ printf("Open the RBF file\n"); /* Check the RBF file size is 19895-bytes */ fd = open(rbf_filename,O_RDONLY); if (fd < 0) { printf("Error: open for file '%s' failed - %d\n", rbf_filename, fd); return 1; } struct stat st; int status = fstat(fd, &st); if (status < 0) { printf("Error: fstat() call failed - %d\n", status); return 1; } rbf_size = st.st_size; if (rbf_size != 19895) { printf("Error: incorrect RBF file size - %d\n", rbf_size); return 1; } printf(" * RBF file size = %d\n", rbf_size); BYTE *rbfBuffer; rbfBuffer = (BYTE *)malloc(rbf_size); if (rbfBuffer == NULL) { printf("Error: RBF buffer allocation failed\n"); return 1; } status = read(fd, rbfBuffer, rbf_size); if (status != rbf_size) { printf("Error: RBF read into buffer failed\n"); return 1; } /* Send the configuration .rbf file 512-bytes at a time */ i = rbf_size; int j; int rbfIndex = 0; int rbfBlockSize = 512; while (i > 0) { if (i < 512) { rbfBlockSize = i; } i -= rbfBlockSize; bytesToWrite = 0; /* OPCODE: Data out, LSB first, -ve edge */ writeBuffer[bytesToWrite++] = 0x19; /* Length-1, low-byte and high-byte */ writeBuffer[bytesToWrite++] = (rbfBlockSize-1) & 0xFF; writeBuffer[bytesToWrite++] = ((rbfBlockSize-1) >> 8) & 0xFF; /* The RBF data */ for (j = 0; j < rbfBlockSize; j++) { writeBuffer[bytesToWrite++] = rbfBuffer[rbfIndex++]; } ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } } free(rbfBuffer); /* Toggle DCLK, and leave DATA0 high * - the DLCK period is ~166ns, or 6MHz clock * - each byte takes just under 1.5us * - if the DATA is 0x55, then the period of that * square wave is ~330ns or 3MHz. */ bytesToWrite = 0; /* OPCODE: Data out, LSB first, -ve edge */ writeBuffer[bytesToWrite++] = 0x19; /* Length-1, low-byte and high-byte */ writeBuffer[bytesToWrite++] = 0x03; writeBuffer[bytesToWrite++] = 0x00; /* 16 bytes */ for (i = 0; i < 4; i++) { writeBuffer[bytesToWrite++] = 0xFF; //writeBuffer[bytesToWrite++] = 0x55; } ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } /* Read the MPSSE pin values */ bytesToWrite = 0; writeBuffer[bytesToWrite++] = 0x81; /* OPCODE: Read low-byte data bits */ writeBuffer[bytesToWrite++] = 0x87; /* OPCODE: Send immediate */ ftStatus = FT_Write( ftHandle, writeBuffer, bytesToWrite, &bytesWritten); if (ftStatus != FT_OK) { printf("Error: FT_Write returned %d\n", (int)ftStatus); return 1; } printf(" - %d-bytes written\n", (int)bytesWritten); if (bytesWritten != bytesToWrite) { printf("Error: FT_Write wrote %d-bytes, but it should have been %d-bytes\n", (int)bytesWritten, (int)bytesToWrite); return 1; } bytesToRead = 0; while (bytesToRead == 0) { ftStatus = FT_GetQueueStatus( ftHandle, &bytesToRead); if (ftStatus != FT_OK) { printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus); return 1; } printf(" - bytesToRead = %d\n", (int)bytesToRead); } ftStatus = FT_Read(ftHandle, readBuffer, (int)bytesToRead, &bytesRead); if (ftStatus != FT_OK) { printf("Error: FT_Read returned %d\n", (int)ftStatus); return 1; } printf(" * %d-bytes received\n", (int)bytesRead); if (bytesRead != 1) { printf("Error: only one byte should have been returned\n"); return 1; } printf(" * Passive serial configuration pins\n"); printf(" DCLK = %d\n", readBuffer[0] & 1); printf(" DATA0 = %d\n", (readBuffer[0]>>1) & 1); printf(" nCONFIG = %d\n", (readBuffer[0]>>2) & 1); printf(" nSTATUS = %d\n", (readBuffer[0]>>3) & 1); printf(" CONF_DONE = %d\n", (readBuffer[0]>>4) & 1); printf(" nRESET = %d\n", (readBuffer[0]>>7) & 1); nCONF_DONE = (readBuffer[0]>>4) & 1; if (nCONF_DONE == 1) { printf("The FPGA is configured\n"); } else { printf("Oh-oh, something went wrong!\n"); } /* TODO: release reset on the board * * Actually, since that would be useful as a command line * tool, create a morphic tool with command line arguments * to program the board, reset the configuration, or * reset the FPGA, etc. * */ free(buffer); free(readBuffer); free(writeBuffer); FT_Close(ftHandle); printf("\n"); return 0; } /* ---------------------------------------------------------------- * Local function definitions * ---------------------------------------------------------------- */ static void show_usage(void) { printf( "\n"\ "Morph-IC FPGA programmer\n"\ "------------------------\n\n"\ "Usage: morphic_program [options]\n\n"\ "Options:\n"\ " -h | --help Help (this message)\n"\ " -f | --file FPGA configuration file (RBF format)\n"\ " -x | --clear Clear the FPGA configuration\n"\ "\n" ); }