--- /dev/null
+/*
+ * ecpprog -- simple programming tool for FTDI-based JTAG programmers
+ * Based on iceprog
+ *
+ * Copyright (C) 2015 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Piotr Esden-Tempski <piotr@esden.net>
+ * Copyright (C) 2020 Gregory Davill <greg.davill@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Relevant Documents:
+ * -------------------
+ * http://www.latticesemi.com/~/media/Documents/UserManuals/EI/icestickusermanual.pdf
+ * http://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_32mb_3v_65nm.pdf
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <io.h> /* _setmode() */
+#include <fcntl.h> /* _O_BINARY */
+#endif
+
+#include "mpsse.h"
+#include "jtag.h"
+#include "lattice_cmds.h"
+
+static bool verbose = false;
+
+// ---------------------------------------------------------
+// FLASH definitions
+// ---------------------------------------------------------
+
+/* Flash command definitions */
+/* This command list is based on the Winbond W25Q128JV Datasheet */
+enum flash_cmd {
+ FC_WE = 0x06, /* Write Enable */
+ FC_SRWE = 0x50, /* Volatile SR Write Enable */
+ FC_WD = 0x04, /* Write Disable */
+ FC_RPD = 0xAB, /* Release Power-Down, returns Device ID */
+ FC_MFGID = 0x90, /* Read Manufacturer/Device ID */
+ FC_JEDECID = 0x9F, /* Read JEDEC ID */
+ FC_UID = 0x4B, /* Read Unique ID */
+ FC_RD = 0x03, /* Read Data */
+ FC_FR = 0x0B, /* Fast Read */
+ FC_PP = 0x02, /* Page Program */
+ FC_SE = 0x20, /* Sector Erase 4kb */
+ FC_BE32 = 0x52, /* Block Erase 32kb */
+ FC_BE64 = 0xD8, /* Block Erase 64kb */
+ FC_CE = 0xC7, /* Chip Erase */
+ FC_RSR1 = 0x05, /* Read Status Register 1 */
+ FC_WSR1 = 0x01, /* Write Status Register 1 */
+ FC_RSR2 = 0x35, /* Read Status Register 2 */
+ FC_WSR2 = 0x31, /* Write Status Register 2 */
+ FC_RSR3 = 0x15, /* Read Status Register 3 */
+ FC_WSR3 = 0x11, /* Write Status Register 3 */
+ FC_RSFDP = 0x5A, /* Read SFDP Register */
+ FC_ESR = 0x44, /* Erase Security Register */
+ FC_PSR = 0x42, /* Program Security Register */
+ FC_RSR = 0x48, /* Read Security Register */
+ FC_GBL = 0x7E, /* Global Block Lock */
+ FC_GBU = 0x98, /* Global Block Unlock */
+ FC_RBL = 0x3D, /* Read Block Lock */
+ FC_RPR = 0x3C, /* Read Sector Protection Registers (adesto) */
+ FC_IBL = 0x36, /* Individual Block Lock */
+ FC_IBU = 0x39, /* Individual Block Unlock */
+ FC_EPS = 0x75, /* Erase / Program Suspend */
+ FC_EPR = 0x7A, /* Erase / Program Resume */
+ FC_PD = 0xB9, /* Power-down */
+ FC_QPI = 0x38, /* Enter QPI mode */
+ FC_ERESET = 0x66, /* Enable Reset */
+ FC_RESET = 0x99, /* Reset Device */
+};
+
+// ---------------------------------------------------------
+// FLASH function implementations
+// ---------------------------------------------------------
+
+static void flash_read_id()
+{
+ /* JEDEC ID structure:
+ * Byte No. | Data Type
+ * ---------+----------
+ * 0 | FC_JEDECID Request Command
+ * 1 | MFG ID
+ * 2 | Dev ID 1
+ * 3 | Dev ID 2
+ * 4 | Ext Dev Str Len
+ */
+
+ uint8_t data[260] = { FC_JEDECID };
+ int len = 5; // command + 4 response bytes
+
+ if (verbose)
+ fprintf(stderr, "read flash ID..\n");
+
+ //flash_chip_select();
+
+ // Write command and read first 4 bytes
+ //mpsse_xfer_spi(data, len);
+ xfer_spi(data, len);
+ //jtag_go_to_state(STATE_SHIFT_DR);
+ //jtag_tap_shift(data, data, 8*5, false);
+
+ if (data[4] == 0xFF)
+ fprintf(stderr, "Extended Device String Length is 0xFF, "
+ "this is likely a read error. Ignorig...\n");
+ else {
+ // Read extended JEDEC ID bytes
+ if (data[4] != 0) {
+ len += data[4];
+ data[0] = FC_JEDECID;
+ xfer_spi(data, len);
+ }
+ }
+
+ ////flash_chip_deselect();
+
+ // TODO: Add full decode of the JEDEC ID.
+ fprintf(stderr, "flash ID:");
+ for (int i = 1; i < len; i++)
+ fprintf(stderr, " 0x%02X", data[i]);
+ fprintf(stderr, "\n");
+}
+
+static void flash_reset()
+{
+ uint8_t data[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ xfer_spi(data, 8);
+}
+
+static void flash_power_up()
+{
+ uint8_t data_rpd[1] = { FC_RPD };
+ xfer_spi(data_rpd, 1);
+}
+
+static void flash_power_down()
+{
+ uint8_t data[1] = { FC_PD };
+ jtag_go_to_state(STATE_SHIFT_DR);
+ jtag_tap_shift(data, data, 8, true);
+}
+
+static uint8_t flash_read_status()
+{
+ uint8_t data[2] = { FC_RSR1 };
+
+ xfer_spi(data, 2);
+
+ if (verbose) {
+ fprintf(stderr, "SR1: 0x%02X\n", data[1]);
+ fprintf(stderr, " - SPRL: %s\n",
+ ((data[1] & (1 << 7)) == 0) ?
+ "unlocked" :
+ "locked");
+ fprintf(stderr, " - SPM: %s\n",
+ ((data[1] & (1 << 6)) == 0) ?
+ "Byte/Page Prog Mode" :
+ "Sequential Prog Mode");
+ fprintf(stderr, " - EPE: %s\n",
+ ((data[1] & (1 << 5)) == 0) ?
+ "Erase/Prog success" :
+ "Erase/Prog error");
+ fprintf(stderr, "- SPM: %s\n",
+ ((data[1] & (1 << 4)) == 0) ?
+ "~WP asserted" :
+ "~WP deasserted");
+ fprintf(stderr, " - SWP: ");
+ switch((data[1] >> 2) & 0x3) {
+ case 0:
+ fprintf(stderr, "All sectors unprotected\n");
+ break;
+ case 1:
+ fprintf(stderr, "Some sectors protected\n");
+ break;
+ case 2:
+ fprintf(stderr, "Reserved (xxxx 10xx)\n");
+ break;
+ case 3:
+ fprintf(stderr, "All sectors protected\n");
+ break;
+ }
+ fprintf(stderr, " - WEL: %s\n",
+ ((data[1] & (1 << 1)) == 0) ?
+ "Not write enabled" :
+ "Write enabled");
+ fprintf(stderr, " - ~RDY: %s\n",
+ ((data[1] & (1 << 0)) == 0) ?
+ "Ready" :
+ "Busy");
+ }
+
+ usleep(1000);
+
+ return data[1];
+}
+
+static void flash_write_enable()
+{
+ if (verbose) {
+ fprintf(stderr, "status before enable:\n");
+ flash_read_status();
+ }
+
+ if (verbose)
+ fprintf(stderr, "write enable..\n");
+
+ uint8_t data[1] = { FC_WE };
+ //flash_chip_select();
+ mpsse_xfer_spi(data, 1);
+ //flash_chip_deselect();
+
+ if (verbose) {
+ fprintf(stderr, "status after enable:\n");
+ flash_read_status();
+ }
+}
+
+static void flash_bulk_erase()
+{
+ fprintf(stderr, "bulk erase..\n");
+
+ uint8_t data[1] = { FC_CE };
+ //flash_chip_select();
+ mpsse_xfer_spi(data, 1);
+ //flash_chip_deselect();
+}
+
+static void flash_4kB_sector_erase(int addr)
+{
+ fprintf(stderr, "erase 4kB sector at 0x%06X..\n", addr);
+
+ uint8_t command[4] = { FC_SE, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+
+ //flash_chip_select();
+ mpsse_send_spi(command, 4);
+ //flash_chip_deselect();
+}
+
+static void flash_32kB_sector_erase(int addr)
+{
+ fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr);
+
+ uint8_t command[4] = { FC_BE32, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+
+ //flash_chip_select();
+ mpsse_send_spi(command, 4);
+ //flash_chip_deselect();
+}
+
+static void flash_64kB_sector_erase(int addr)
+{
+ fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr);
+
+ uint8_t command[4] = { FC_BE64, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+
+ //flash_chip_select();
+ mpsse_send_spi(command, 4);
+ //flash_chip_deselect();
+}
+
+static void flash_prog(int addr, uint8_t *data, int n)
+{
+ if (verbose)
+ fprintf(stderr, "prog 0x%06X +0x%03X..\n", addr, n);
+
+ uint8_t command[4] = { FC_PP, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+
+ //flash_chip_select();
+ mpsse_send_spi(command, 4);
+ mpsse_send_spi(data, n);
+ //flash_chip_deselect();
+
+ if (verbose)
+ for (int i = 0; i < n; i++)
+ fprintf(stderr, "%02x%c", data[i], i == n - 1 || i % 32 == 31 ? '\n' : ' ');
+}
+
+static void flash_read(int addr, uint8_t *data, int n)
+{
+ if (verbose)
+ fprintf(stderr, "read 0x%06X +0x%03X..\n", addr, n);
+
+ uint8_t command[4] = { FC_RD, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+
+ //flash_chip_select();
+ mpsse_send_spi(command, 4);
+ memset(data, 0, n);
+ mpsse_xfer_spi(data, n);
+ //flash_chip_deselect();
+
+ if (verbose)
+ for (int i = 0; i < n; i++)
+ fprintf(stderr, "%02x%c", data[i], i == n - 1 || i % 32 == 31 ? '\n' : ' ');
+}
+
+static void flash_wait()
+{
+ if (verbose)
+ fprintf(stderr, "waiting..");
+
+ int count = 0;
+ while (1)
+ {
+ uint8_t data[2] = { FC_RSR1 };
+
+ //flash_chip_select();
+ mpsse_xfer_spi(data, 2);
+ //flash_chip_deselect();
+
+ if ((data[1] & 0x01) == 0) {
+ if (count < 2) {
+ count++;
+ if (verbose) {
+ fprintf(stderr, "r");
+ fflush(stderr);
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr, "R");
+ fflush(stderr);
+ }
+ break;
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr, ".");
+ fflush(stderr);
+ }
+ count = 0;
+ }
+
+ usleep(1000);
+ }
+
+ if (verbose)
+ fprintf(stderr, "\n");
+
+}
+
+static void flash_disable_protection()
+{
+ fprintf(stderr, "disable flash protection...\n");
+
+ // Write Status Register 1 <- 0x00
+ uint8_t data[2] = { FC_WSR1, 0x00 };
+ //flash_chip_select();
+ mpsse_xfer_spi(data, 2);
+ //flash_chip_deselect();
+
+ flash_wait();
+
+ // Read Status Register 1
+ data[0] = FC_RSR1;
+
+ //flash_chip_select();
+ mpsse_xfer_spi(data, 2);
+ //flash_chip_deselect();
+
+ if (data[1] != 0x00)
+ fprintf(stderr, "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", data[1]);
+
+}
+
+// ---------------------------------------------------------
+// JTAG -> SPI functions
+// ---------------------------------------------------------
+
+/*
+ * JTAG performrs all shifts LSB first, our FLSAH is expeting bytes MSB first,
+ * There are a few ways to fix this, for now we just bit-reverse all the input data to the JTAG core
+ */
+uint8_t bit_reverse(uint8_t in){
+
+ uint8_t out = (in & 0x01) ? 0x80 : 0x00;
+ out |= (in & 0x02) ? 0x40 : 0x00;
+ out |= (in & 0x04) ? 0x20 : 0x00;
+ out |= (in & 0x08) ? 0x10 : 0x00;
+ out |= (in & 0x10) ? 0x08 : 0x00;
+ out |= (in & 0x20) ? 0x04 : 0x00;
+ out |= (in & 0x40) ? 0x02 : 0x00;
+ out |= (in & 0x80) ? 0x01 : 0x00;
+
+ return out;
+}
+
+void xfer_spi(uint8_t* data, uint32_t len){
+ /* Flip bit order of all bytes */
+ for(int i = 0; i < len; i++){
+ data[i] = bit_reverse(data[i]);
+ }
+
+ jtag_go_to_state(STATE_SHIFT_DR);
+ jtag_tap_shift(data, data, len * 8, true);
+
+ /* Flip bit order of all bytes */
+ for(int i = 0; i < len; i++){
+ data[i] = bit_reverse(data[i]);
+ }
+}
+
+// ---------------------------------------------------------
+// ECP5 specific JTAG functions
+// ---------------------------------------------------------
+
+
+static void print_idcode(uint32_t idcode){
+ for(int i = 0; i < sizeof(ecp_devices)/sizeof(struct ecp_device_id); i++){
+ if(idcode == ecp_devices[i].device_id)
+ {
+ printf("IDCODE: 0x%08x (%s)\n", idcode ,ecp_devices[i].device_name);
+ return;
+ }
+ }
+ printf("IDCODE: 0x%08x does not match :(\n", idcode);
+}
+
+static void read_idcode(){
+
+ uint8_t data[4] = {READ_ID};
+
+ jtag_go_to_state(STATE_SHIFT_IR);
+ jtag_tap_shift(data, data, 8, true);
+
+ data[0] = 0;
+ jtag_go_to_state(STATE_SHIFT_DR);
+ jtag_tap_shift(data, data, 32, true);
+
+ uint32_t idcode = 0;
+
+ /* Format the IDCODE into a 32bit value */
+ for(int i = 0; i< 4; i++)
+ idcode = data[i] << 24 | idcode >> 8;
+
+ print_idcode(idcode);
+}
+
+
+static void print_status_register(uint32_t status){
+ printf("ECP5 Status Register: 0x%08x\n", status);
+
+ if(verbose){
+ printf(" Transparent Mode: %s\n", status & (1 << 0) ? "Yes" : "No" );
+ printf(" Config Target: %s\n", status & (7 << 1) ? "SRAM" : "eFuse" );
+ printf(" JTAG Active: %s\n", status & (1 << 4) ? "Yes" : "No" );
+ printf(" PWD Protection: %s\n", status & (1 << 5) ? "Yes" : "No" );
+ printf(" Decrypt Enable: %s\n", status & (1 << 7) ? "Yes" : "No" );
+ printf(" DONE: %s\n", status & (1 << 8) ? "Yes" : "No" );
+ printf(" ISC Enable: %s\n", status & (1 << 9) ? "Yes" : "No" );
+ printf(" Write Enable: %s\n", status & (1 << 10) ? "Writable" : "Not Writable");
+ printf(" Read Enable: %s\n", status & (1 << 11) ? "Readable" : "Not Readable");
+ printf(" Busy Flag: %s\n", status & (1 << 12) ? "Yes" : "No" );
+ printf(" Fail Flag: %s\n", status & (1 << 13) ? "Yes" : "No" );
+ printf(" Feature OTP: %s\n", status & (1 << 14) ? "Yes" : "No" );
+ printf(" Decrypt Only: %s\n", status & (1 << 15) ? "Yes" : "No" );
+ printf(" PWD Enable: %s\n", status & (1 << 16) ? "Yes" : "No" );
+ printf(" Encrypt Preamble: %s\n", status & (1 << 20) ? "Yes" : "No" );
+ printf(" Std Preamble: %s\n", status & (1 << 21) ? "Yes" : "No" );
+ printf(" SPIm Fail 1: %s\n", status & (1 << 22) ? "Yes" : "No" );
+
+ uint8_t bse_error = (status & (7 << 23)) >> 23;
+ switch (bse_error){
+ case 0b000: printf(" BSE Error Code: No Error (0b000)\n"); break;
+ case 0b001: printf(" BSE Error Code: ID Error (0b001)\n"); break;
+ case 0b010: printf(" BSE Error Code: CMD Error - illegal command (0b010)\n"); break;
+ case 0b011: printf(" BSE Error Code: CRC Error (0b011)\n"); break;
+ case 0b100: printf(" BSE Error Code: PRMB Error - preamble error (0b100)\n"); break;
+ case 0b101: printf(" BSE Error Code: ABRT Error - configuration aborted by the user (0b101)\n"); break;
+ case 0b110: printf(" BSE Error Code: OVFL Error - data overflow error (0b110)\n"); break;
+ case 0b111: printf(" BSE Error Code: SDM Error - bitstream pass the size of SRAM array (0b111)\n"); break;
+ }
+
+ printf(" Execution Error: %s\n", status & (1 << 26) ? "Yes" : "No" );
+ printf(" ID Error: %s\n", status & (1 << 27) ? "Yes" : "No" );
+ printf(" Invalid Command: %s\n", status & (1 << 28) ? "Yes" : "No" );
+ printf(" SED Error: %s\n", status & (1 << 29) ? "Yes" : "No" );
+ printf(" Bypass Mode: %s\n", status & (1 << 30) ? "Yes" : "No" );
+ printf(" Flow Througuh Mode: %s\n", status & (1 << 31) ? "Yes" : "No" );
+
+ }
+
+
+}
+
+
+static void read_status_register(){
+
+ uint8_t data[4] = {LSC_READ_STATUS};
+
+ jtag_go_to_state(STATE_SHIFT_IR);
+ jtag_tap_shift(data, data, 8, true);
+
+ data[0] = 0;
+ jtag_go_to_state(STATE_SHIFT_DR);
+ jtag_tap_shift(data, data, 32, true);
+
+ uint32_t status = 0;
+
+ /* Format the IDCODE into a 32bit value */
+ for(int i = 0; i< 4; i++)
+ status = data[i] << 24 | status >> 8;
+
+ print_status_register(status);
+}
+
+
+
+static void enter_spi_background_mode(){
+
+ uint8_t data_in[4] = {0,0,0,0};
+ uint8_t data_out[4] = {0,0,0,0};
+
+ data_in[0] = 0x3A;
+ jtag_go_to_state(STATE_SHIFT_IR);
+ jtag_tap_shift(data_in, data_out, 8, true);
+
+ /* These bytes seem to be required to un-lock the SPI interface */
+ data_in[0] = 0xFE;
+ data_in[1] = 0x68;
+ jtag_go_to_state(STATE_SHIFT_DR);
+ jtag_tap_shift(data_in, data_out, 16, true);
+
+ /* Entering IDLE is essential */
+ jtag_go_to_state(STATE_RUN_TEST_IDLE);
+}
+
+
+void ecp_jtag_cmd(uint8_t cmd){
+ uint8_t data_in[1] = {0};
+ uint8_t data_out[1] = {0};
+
+ data_in[0] = cmd;
+ jtag_go_to_state(STATE_SHIFT_IR);
+ jtag_tap_shift(data_in, data_out, 8, true);
+
+ jtag_go_to_state(STATE_RUN_TEST_IDLE);
+ jtag_wait_time(10);
+}
+
+// ---------------------------------------------------------
+// iceprog implementation
+// ---------------------------------------------------------
+
+static void help(const char *progname)
+{
+ fprintf(stderr, "Simple programming tool for FTDI-based Lattice ECP JTAG programmers.\n");
+ fprintf(stderr, "Usage: %s [-b|-n|-c] <input file>\n", progname);
+ fprintf(stderr, " %s -r|-R<bytes> <output file>\n", progname);
+ fprintf(stderr, " %s -S <input file>\n", progname);
+ fprintf(stderr, " %s -t\n", progname);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "General options:\n");
+ fprintf(stderr, " -d <device string> use the specified USB device [default: i:0x0403:0x6010 or i:0x0403:0x6014]\n");
+ fprintf(stderr, " d:<devicenode> (e.g. d:002/005)\n");
+ fprintf(stderr, " i:<vendor>:<product> (e.g. i:0x0403:0x6010)\n");
+ fprintf(stderr, " i:<vendor>:<product>:<index> (e.g. i:0x0403:0x6010:0)\n");
+ fprintf(stderr, " s:<vendor>:<product>:<serial-string>\n");
+ fprintf(stderr, " -I [ABCD] connect to the specified interface on the FTDI chip\n");
+ fprintf(stderr, " [default: A]\n");
+ fprintf(stderr, " -o <offset in bytes> start address for read/write [default: 0]\n");
+ fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n");
+ fprintf(stderr, " or 'M' for size in megabytes)\n");
+ fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n");
+ fprintf(stderr, " -v verbose output\n");
+ fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Mode of operation:\n");
+ fprintf(stderr, " [default] write file contents to flash, then verify\n");
+ fprintf(stderr, " -X write file contents to flash only\n");
+ fprintf(stderr, " -r read first 256 kB from flash and write to file\n");
+ fprintf(stderr, " -R <size in bytes> read the specified number of bytes from flash\n");
+ fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n");
+ fprintf(stderr, " or 'M' for size in megabytes)\n");
+ fprintf(stderr, " -c do not write flash, only verify (`check')\n");
+ fprintf(stderr, " -S perform SRAM programming\n");
+ fprintf(stderr, " -t just read the flash ID sequence\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Erase mode (only meaningful in default mode):\n");
+ fprintf(stderr, " [default] erase aligned chunks of 64kB in write mode\n");
+ fprintf(stderr, " This means that some data after the written data (or\n");
+ fprintf(stderr, " even before when -o is used) may be erased as well.\n");
+ fprintf(stderr, " -b bulk erase entire flash before writing\n");
+ fprintf(stderr, " -e <size in bytes> erase flash as if we were writing that number of bytes\n");
+ fprintf(stderr, " -n do not erase flash before writing\n");
+ fprintf(stderr, " -p disable write protection before erasing or writing\n");
+ fprintf(stderr, " This can be useful if flash memory appears to be\n");
+ fprintf(stderr, " bricked and won't respond to erasing or programming.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Miscellaneous options:\n");
+ fprintf(stderr, " --help display this help and exit\n");
+ fprintf(stderr, " -- treat all remaining arguments as filenames\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Exit status:\n");
+ fprintf(stderr, " 0 on success,\n");
+ fprintf(stderr, " 1 if a non-hardware error occurred (e.g., failure to read from or\n");
+ fprintf(stderr, " write to a file, or invoked with invalid options),\n");
+ fprintf(stderr, " 2 if communication with the hardware failed (e.g., cannot find the\n");
+ fprintf(stderr, " iCE FTDI USB device),\n");
+ fprintf(stderr, " 3 if verification of the data failed.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "If you have a bug report, please file an issue on github:\n");
+ fprintf(stderr, " https://github.com/gregdavill/ecpprog/issues\n");
+}
+
+int main(int argc, char **argv)
+{
+ /* used for error reporting */
+ const char *my_name = argv[0];
+ for (size_t i = 0; argv[0][i]; i++)
+ if (argv[0][i] == '/')
+ my_name = argv[0] + i + 1;
+
+ int read_size = 256 * 1024;
+ int erase_block_size = 64;
+ int erase_size = 0;
+ int rw_offset = 0;
+
+ bool read_mode = false;
+ bool check_mode = false;
+ bool erase_mode = false;
+ bool bulk_erase = false;
+ bool dont_erase = false;
+ bool prog_sram = false;
+ bool test_mode = false;
+ bool slow_clock = false;
+ bool disable_protect = false;
+ bool disable_verify = false;
+ const char *filename = NULL;
+ const char *devstr = NULL;
+ int ifnum = 0;
+
+#ifdef _WIN32
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, -2},
+ {NULL, 0, NULL, 0}
+ };
+
+ /* Decode command line parameters */
+ int opt;
+ char *endptr;
+ while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStvspX", long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'd': /* device string */
+ devstr = optarg;
+ break;
+ case 'i': /* block erase size */
+ if (!strcmp(optarg, "4"))
+ erase_block_size = 4;
+ else if (!strcmp(optarg, "32"))
+ erase_block_size = 32;
+ else if (!strcmp(optarg, "64"))
+ erase_block_size = 64;
+ else {
+ fprintf(stderr, "%s: `%s' is not a valid erase block size (must be `4', `32' or `64')\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'I': /* FTDI Chip interface select */
+ if (!strcmp(optarg, "A"))
+ ifnum = 0;
+ else if (!strcmp(optarg, "B"))
+ ifnum = 1;
+ else if (!strcmp(optarg, "C"))
+ ifnum = 2;
+ else if (!strcmp(optarg, "D"))
+ ifnum = 3;
+ else {
+ fprintf(stderr, "%s: `%s' is not a valid interface (must be `A', `B', `C', or `D')\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'r': /* Read 256 bytes to file */
+ read_mode = true;
+ break;
+ case 'R': /* Read n bytes to file */
+ read_mode = true;
+ read_size = strtol(optarg, &endptr, 0);
+ if (*endptr == '\0')
+ /* ok */;
+ else if (!strcmp(endptr, "k"))
+ read_size *= 1024;
+ else if (!strcmp(endptr, "M"))
+ read_size *= 1024 * 1024;
+ else {
+ fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'e': /* Erase blocks as if we were writing n bytes */
+ erase_mode = true;
+ erase_size = strtol(optarg, &endptr, 0);
+ if (*endptr == '\0')
+ /* ok */;
+ else if (!strcmp(endptr, "k"))
+ erase_size *= 1024;
+ else if (!strcmp(endptr, "M"))
+ erase_size *= 1024 * 1024;
+ else {
+ fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'o': /* set address offset */
+ rw_offset = strtol(optarg, &endptr, 0);
+ if (*endptr == '\0')
+ /* ok */;
+ else if (!strcmp(endptr, "k"))
+ rw_offset *= 1024;
+ else if (!strcmp(endptr, "M"))
+ rw_offset *= 1024 * 1024;
+ else {
+ fprintf(stderr, "%s: `%s' is not a valid offset\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'c': /* do not write just check */
+ check_mode = true;
+ break;
+ case 'b': /* bulk erase before writing */
+ bulk_erase = true;
+ break;
+ case 'n': /* do not erase before writing */
+ dont_erase = true;
+ break;
+ case 'S': /* write to sram directly */
+ prog_sram = true;
+ break;
+ case 't': /* just read flash id */
+ test_mode = true;
+ break;
+ case 'v': /* provide verbose output */
+ verbose = true;
+ break;
+ case 's': /* use slow SPI clock */
+ slow_clock = true;
+ break;
+ case 'p': /* disable flash protect before erase/write */
+ disable_protect = true;
+ break;
+ case 'X': /* disable verification */
+ disable_verify = true;
+ break;
+ case -2:
+ help(argv[0]);
+ return EXIT_SUCCESS;
+ default:
+ /* error message has already been printed */
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Make sure that the combination of provided parameters makes sense */
+
+ if (read_mode + erase_mode + check_mode + prog_sram + test_mode > 1) {
+ fprintf(stderr, "%s: options `-r'/`-R', `-e`, `-c', `-S', and `-t' are mutually exclusive\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (bulk_erase && dont_erase) {
+ fprintf(stderr, "%s: options `-b' and `-n' are mutually exclusive\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (disable_protect && (read_mode || check_mode || prog_sram || test_mode)) {
+ fprintf(stderr, "%s: option `-p' only valid in programming mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (bulk_erase && (read_mode || check_mode || prog_sram || test_mode)) {
+ fprintf(stderr, "%s: option `-b' only valid in programming mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (dont_erase && (read_mode || check_mode || prog_sram || test_mode)) {
+ fprintf(stderr, "%s: option `-n' only valid in programming mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (rw_offset != 0 && prog_sram) {
+ fprintf(stderr, "%s: option `-o' not supported in SRAM mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (rw_offset != 0 && test_mode) {
+ fprintf(stderr, "%s: option `-o' not supported in test mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (optind + 1 == argc) {
+ if (test_mode) {
+ fprintf(stderr, "%s: test mode doesn't take a file name\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ filename = argv[optind];
+ } else if (optind != argc) {
+ fprintf(stderr, "%s: too many arguments\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ } else if (bulk_erase || disable_protect) {
+ filename = "/dev/null";
+ } else if (!test_mode && !erase_mode && !disable_protect) {
+ fprintf(stderr, "%s: missing argument\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ /* open input/output file in advance
+ so we can fail before initializing the hardware */
+
+ FILE *f = NULL;
+ long file_size = -1;
+
+ if (test_mode) {
+ /* nop */;
+ } else if (erase_mode) {
+ file_size = erase_size;
+ } else if (read_mode) {
+ f = (strcmp(filename, "-") == 0) ? stdout : fopen(filename, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open '%s' for writing: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ } else {
+ f = (strcmp(filename, "-") == 0) ? stdin : fopen(filename, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open '%s' for reading: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+
+ /* For regular programming, we need to read the file
+ twice--once for programming and once for verifying--and
+ need to know the file size in advance in order to erase
+ the correct amount of memory.
+
+ See if we can seek on the input file. Checking for "-"
+ as an argument isn't enough as we might be reading from a
+ named pipe, or contrarily, the standard input may be an
+ ordinary file. */
+
+ if (!prog_sram && !check_mode) {
+ if (fseek(f, 0L, SEEK_END) != -1) {
+ file_size = ftell(f);
+ if (file_size == -1) {
+ fprintf(stderr, "%s: %s: ftell: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ if (fseek(f, 0L, SEEK_SET) == -1) {
+ fprintf(stderr, "%s: %s: fseek: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ } else {
+ FILE *pipe = f;
+
+ f = tmpfile();
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open temporary file\n", my_name);
+ return EXIT_FAILURE;
+ }
+ file_size = 0;
+
+ while (true) {
+ static unsigned char buffer[4096];
+ size_t rc = fread(buffer, 1, 4096, pipe);
+ if (rc <= 0)
+ break;
+ size_t wc = fwrite(buffer, 1, rc, f);
+ if (wc != rc) {
+ fprintf(stderr, "%s: can't write to temporary file\n", my_name);
+ return EXIT_FAILURE;
+ }
+ file_size += rc;
+ }
+ fclose(pipe);
+
+ /* now seek to the beginning so we can
+ start reading again */
+ fseek(f, 0, SEEK_SET);
+ }
+ }
+ }
+
+ // ---------------------------------------------------------
+ // Initialize USB connection to FT2232H
+ // ---------------------------------------------------------
+
+ fprintf(stderr, "init..\n");
+
+ mpsse_init(ifnum, devstr, slow_clock);
+ mpsse_jtag_init();
+
+ read_idcode();
+ read_status_register();
+
+ usleep(20000);
+
+ if (test_mode)
+ {
+
+
+ /* Reset ECP5 to release SPI interface */
+ ecp_jtag_cmd(ISC_ENABLE);
+ ecp_jtag_cmd(ISC_ERASE);
+ ecp_jtag_cmd(ISC_DISABLE);
+
+ /* Put device into SPI bypass mode */
+ enter_spi_background_mode();
+
+ flash_read_id();
+ }
+ else if (prog_sram)
+ {
+ // ---------------------------------------------------------
+ // Reset
+ // ---------------------------------------------------------
+
+ fprintf(stderr, "reset..\n");
+
+ //sram_reset();
+ usleep(100);
+
+ //sram_chip_select();
+ usleep(2000);
+
+
+ // ---------------------------------------------------------
+ // Program
+ // ---------------------------------------------------------
+
+ fprintf(stderr, "programming..\n");
+ while (1) {
+ static unsigned char buffer[4096];
+ int rc = fread(buffer, 1, 4096, f);
+ if (rc <= 0)
+ break;
+ if (verbose)
+ fprintf(stderr, "sending %d bytes.\n", rc);
+ mpsse_send_spi(buffer, rc);
+ }
+
+ mpsse_send_dummy_bytes(6);
+ mpsse_send_dummy_bit();
+
+
+ }
+ else /* program flash */
+ {
+ // ---------------------------------------------------------
+ // Reset
+ // ---------------------------------------------------------
+
+ fprintf(stderr, "reset..\n");
+
+ //flash_chip_deselect();
+ usleep(250000);
+
+
+
+ flash_reset();
+ flash_power_up();
+
+ flash_read_id();
+
+
+ // ---------------------------------------------------------
+ // Program
+ // ---------------------------------------------------------
+
+ if (!read_mode && !check_mode)
+ {
+ if (disable_protect)
+ {
+ flash_write_enable();
+ flash_disable_protection();
+ }
+
+ if (!dont_erase)
+ {
+ if (bulk_erase)
+ {
+ flash_write_enable();
+ flash_bulk_erase();
+ flash_wait();
+ }
+ else
+ {
+ fprintf(stderr, "file size: %ld\n", file_size);
+
+ int block_size = erase_block_size << 10;
+ int block_mask = block_size - 1;
+ int begin_addr = rw_offset & ~block_mask;
+ int end_addr = (rw_offset + file_size + block_mask) & ~block_mask;
+
+ for (int addr = begin_addr; addr < end_addr; addr += block_size) {
+ flash_write_enable();
+ switch(erase_block_size) {
+ case 4:
+ flash_4kB_sector_erase(addr);
+ break;
+ case 32:
+ flash_32kB_sector_erase(addr);
+ break;
+ case 64:
+ flash_64kB_sector_erase(addr);
+ break;
+ }
+ if (verbose) {
+ fprintf(stderr, "Status after block erase:\n");
+ flash_read_status();
+ }
+ flash_wait();
+ }
+ }
+ }
+
+ if (!erase_mode)
+ {
+ fprintf(stderr, "programming..\n");
+
+ for (int rc, addr = 0; true; addr += rc) {
+ uint8_t buffer[256];
+ int page_size = 256 - (rw_offset + addr) % 256;
+ rc = fread(buffer, 1, page_size, f);
+ if (rc <= 0)
+ break;
+ flash_write_enable();
+ flash_prog(rw_offset + addr, buffer, rc);
+ flash_wait();
+ }
+
+ /* seek to the beginning for second pass */
+ fseek(f, 0, SEEK_SET);
+ }
+ }
+
+ // ---------------------------------------------------------
+ // Read/Verify
+ // ---------------------------------------------------------
+
+ if (read_mode) {
+ fprintf(stderr, "reading..\n");
+ for (int addr = 0; addr < read_size; addr += 256) {
+ uint8_t buffer[256];
+ flash_read(rw_offset + addr, buffer, 256);
+ fwrite(buffer, read_size - addr > 256 ? 256 : read_size - addr, 1, f);
+ }
+ } else if (!erase_mode && !disable_verify) {
+ fprintf(stderr, "reading..\n");
+ for (int addr = 0; true; addr += 256) {
+ uint8_t buffer_flash[256], buffer_file[256];
+ int rc = fread(buffer_file, 1, 256, f);
+ if (rc <= 0)
+ break;
+ flash_read(rw_offset + addr, buffer_flash, rc);
+ if (memcmp(buffer_file, buffer_flash, rc)) {
+ fprintf(stderr, "Found difference between flash and file!\n");
+ mpsse_error(3);
+ }
+ }
+
+ fprintf(stderr, "VERIFY OK\n");
+ }
+
+
+ // ---------------------------------------------------------
+ // Reset
+ // ---------------------------------------------------------
+
+ //flash_power_down();
+
+ usleep(250000);
+
+
+ }
+
+ if (f != NULL && f != stdin && f != stdout)
+ fclose(f);
+
+ // ---------------------------------------------------------
+ // Exit
+ // ---------------------------------------------------------
+
+ fprintf(stderr, "Bye.\n");
+ mpsse_close();
+ return 0;
+}
+++ /dev/null
-/*
- * ecpprog -- simple programming tool for FTDI-based JTAG programmers
- * Based on iceprog
- *
- * Copyright (C) 2015 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2018 Piotr Esden-Tempski <piotr@esden.net>
- * Copyright (C) 2020 Gregory Davill <greg.davill@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Relevant Documents:
- * -------------------
- * http://www.latticesemi.com/~/media/Documents/UserManuals/EI/icestickusermanual.pdf
- * http://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_32mb_3v_65nm.pdf
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef _WIN32
-#include <io.h> /* _setmode() */
-#include <fcntl.h> /* _O_BINARY */
-#endif
-
-#include "mpsse.h"
-#include "jtag.h"
-#include "lattice_cmds.h"
-
-static bool verbose = false;
-
-// ---------------------------------------------------------
-// FLASH definitions
-// ---------------------------------------------------------
-
-/* Flash command definitions */
-/* This command list is based on the Winbond W25Q128JV Datasheet */
-enum flash_cmd {
- FC_WE = 0x06, /* Write Enable */
- FC_SRWE = 0x50, /* Volatile SR Write Enable */
- FC_WD = 0x04, /* Write Disable */
- FC_RPD = 0xAB, /* Release Power-Down, returns Device ID */
- FC_MFGID = 0x90, /* Read Manufacturer/Device ID */
- FC_JEDECID = 0x9F, /* Read JEDEC ID */
- FC_UID = 0x4B, /* Read Unique ID */
- FC_RD = 0x03, /* Read Data */
- FC_FR = 0x0B, /* Fast Read */
- FC_PP = 0x02, /* Page Program */
- FC_SE = 0x20, /* Sector Erase 4kb */
- FC_BE32 = 0x52, /* Block Erase 32kb */
- FC_BE64 = 0xD8, /* Block Erase 64kb */
- FC_CE = 0xC7, /* Chip Erase */
- FC_RSR1 = 0x05, /* Read Status Register 1 */
- FC_WSR1 = 0x01, /* Write Status Register 1 */
- FC_RSR2 = 0x35, /* Read Status Register 2 */
- FC_WSR2 = 0x31, /* Write Status Register 2 */
- FC_RSR3 = 0x15, /* Read Status Register 3 */
- FC_WSR3 = 0x11, /* Write Status Register 3 */
- FC_RSFDP = 0x5A, /* Read SFDP Register */
- FC_ESR = 0x44, /* Erase Security Register */
- FC_PSR = 0x42, /* Program Security Register */
- FC_RSR = 0x48, /* Read Security Register */
- FC_GBL = 0x7E, /* Global Block Lock */
- FC_GBU = 0x98, /* Global Block Unlock */
- FC_RBL = 0x3D, /* Read Block Lock */
- FC_RPR = 0x3C, /* Read Sector Protection Registers (adesto) */
- FC_IBL = 0x36, /* Individual Block Lock */
- FC_IBU = 0x39, /* Individual Block Unlock */
- FC_EPS = 0x75, /* Erase / Program Suspend */
- FC_EPR = 0x7A, /* Erase / Program Resume */
- FC_PD = 0xB9, /* Power-down */
- FC_QPI = 0x38, /* Enter QPI mode */
- FC_ERESET = 0x66, /* Enable Reset */
- FC_RESET = 0x99, /* Reset Device */
-};
-
-// ---------------------------------------------------------
-// FLASH function implementations
-// ---------------------------------------------------------
-
-static void flash_read_id()
-{
- /* JEDEC ID structure:
- * Byte No. | Data Type
- * ---------+----------
- * 0 | FC_JEDECID Request Command
- * 1 | MFG ID
- * 2 | Dev ID 1
- * 3 | Dev ID 2
- * 4 | Ext Dev Str Len
- */
-
- uint8_t data[260] = { FC_JEDECID };
- int len = 5; // command + 4 response bytes
-
- if (verbose)
- fprintf(stderr, "read flash ID..\n");
-
- //flash_chip_select();
-
- // Write command and read first 4 bytes
- //mpsse_xfer_spi(data, len);
- xfer_spi(data, len);
- //jtag_go_to_state(STATE_SHIFT_DR);
- //jtag_tap_shift(data, data, 8*5, false);
-
- if (data[4] == 0xFF)
- fprintf(stderr, "Extended Device String Length is 0xFF, "
- "this is likely a read error. Ignorig...\n");
- else {
- // Read extended JEDEC ID bytes
- if (data[4] != 0) {
- len += data[4];
- data[0] = FC_JEDECID;
- xfer_spi(data, len);
- }
- }
-
- ////flash_chip_deselect();
-
- // TODO: Add full decode of the JEDEC ID.
- fprintf(stderr, "flash ID:");
- for (int i = 1; i < len; i++)
- fprintf(stderr, " 0x%02X", data[i]);
- fprintf(stderr, "\n");
-}
-
-static void flash_reset()
-{
- uint8_t data[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- xfer_spi(data, 8);
-}
-
-static void flash_power_up()
-{
- uint8_t data_rpd[1] = { FC_RPD };
- xfer_spi(data_rpd, 1);
-}
-
-static void flash_power_down()
-{
- uint8_t data[1] = { FC_PD };
- jtag_go_to_state(STATE_SHIFT_DR);
- jtag_tap_shift(data, data, 8, true);
-}
-
-static uint8_t flash_read_status()
-{
- uint8_t data[2] = { FC_RSR1 };
-
- xfer_spi(data, 2);
-
- if (verbose) {
- fprintf(stderr, "SR1: 0x%02X\n", data[1]);
- fprintf(stderr, " - SPRL: %s\n",
- ((data[1] & (1 << 7)) == 0) ?
- "unlocked" :
- "locked");
- fprintf(stderr, " - SPM: %s\n",
- ((data[1] & (1 << 6)) == 0) ?
- "Byte/Page Prog Mode" :
- "Sequential Prog Mode");
- fprintf(stderr, " - EPE: %s\n",
- ((data[1] & (1 << 5)) == 0) ?
- "Erase/Prog success" :
- "Erase/Prog error");
- fprintf(stderr, "- SPM: %s\n",
- ((data[1] & (1 << 4)) == 0) ?
- "~WP asserted" :
- "~WP deasserted");
- fprintf(stderr, " - SWP: ");
- switch((data[1] >> 2) & 0x3) {
- case 0:
- fprintf(stderr, "All sectors unprotected\n");
- break;
- case 1:
- fprintf(stderr, "Some sectors protected\n");
- break;
- case 2:
- fprintf(stderr, "Reserved (xxxx 10xx)\n");
- break;
- case 3:
- fprintf(stderr, "All sectors protected\n");
- break;
- }
- fprintf(stderr, " - WEL: %s\n",
- ((data[1] & (1 << 1)) == 0) ?
- "Not write enabled" :
- "Write enabled");
- fprintf(stderr, " - ~RDY: %s\n",
- ((data[1] & (1 << 0)) == 0) ?
- "Ready" :
- "Busy");
- }
-
- usleep(1000);
-
- return data[1];
-}
-
-static void flash_write_enable()
-{
- if (verbose) {
- fprintf(stderr, "status before enable:\n");
- flash_read_status();
- }
-
- if (verbose)
- fprintf(stderr, "write enable..\n");
-
- uint8_t data[1] = { FC_WE };
- //flash_chip_select();
- mpsse_xfer_spi(data, 1);
- //flash_chip_deselect();
-
- if (verbose) {
- fprintf(stderr, "status after enable:\n");
- flash_read_status();
- }
-}
-
-static void flash_bulk_erase()
-{
- fprintf(stderr, "bulk erase..\n");
-
- uint8_t data[1] = { FC_CE };
- //flash_chip_select();
- mpsse_xfer_spi(data, 1);
- //flash_chip_deselect();
-}
-
-static void flash_4kB_sector_erase(int addr)
-{
- fprintf(stderr, "erase 4kB sector at 0x%06X..\n", addr);
-
- uint8_t command[4] = { FC_SE, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
-
- //flash_chip_select();
- mpsse_send_spi(command, 4);
- //flash_chip_deselect();
-}
-
-static void flash_32kB_sector_erase(int addr)
-{
- fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr);
-
- uint8_t command[4] = { FC_BE32, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
-
- //flash_chip_select();
- mpsse_send_spi(command, 4);
- //flash_chip_deselect();
-}
-
-static void flash_64kB_sector_erase(int addr)
-{
- fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr);
-
- uint8_t command[4] = { FC_BE64, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
-
- //flash_chip_select();
- mpsse_send_spi(command, 4);
- //flash_chip_deselect();
-}
-
-static void flash_prog(int addr, uint8_t *data, int n)
-{
- if (verbose)
- fprintf(stderr, "prog 0x%06X +0x%03X..\n", addr, n);
-
- uint8_t command[4] = { FC_PP, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
-
- //flash_chip_select();
- mpsse_send_spi(command, 4);
- mpsse_send_spi(data, n);
- //flash_chip_deselect();
-
- if (verbose)
- for (int i = 0; i < n; i++)
- fprintf(stderr, "%02x%c", data[i], i == n - 1 || i % 32 == 31 ? '\n' : ' ');
-}
-
-static void flash_read(int addr, uint8_t *data, int n)
-{
- if (verbose)
- fprintf(stderr, "read 0x%06X +0x%03X..\n", addr, n);
-
- uint8_t command[4] = { FC_RD, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
-
- //flash_chip_select();
- mpsse_send_spi(command, 4);
- memset(data, 0, n);
- mpsse_xfer_spi(data, n);
- //flash_chip_deselect();
-
- if (verbose)
- for (int i = 0; i < n; i++)
- fprintf(stderr, "%02x%c", data[i], i == n - 1 || i % 32 == 31 ? '\n' : ' ');
-}
-
-static void flash_wait()
-{
- if (verbose)
- fprintf(stderr, "waiting..");
-
- int count = 0;
- while (1)
- {
- uint8_t data[2] = { FC_RSR1 };
-
- //flash_chip_select();
- mpsse_xfer_spi(data, 2);
- //flash_chip_deselect();
-
- if ((data[1] & 0x01) == 0) {
- if (count < 2) {
- count++;
- if (verbose) {
- fprintf(stderr, "r");
- fflush(stderr);
- }
- } else {
- if (verbose) {
- fprintf(stderr, "R");
- fflush(stderr);
- }
- break;
- }
- } else {
- if (verbose) {
- fprintf(stderr, ".");
- fflush(stderr);
- }
- count = 0;
- }
-
- usleep(1000);
- }
-
- if (verbose)
- fprintf(stderr, "\n");
-
-}
-
-static void flash_disable_protection()
-{
- fprintf(stderr, "disable flash protection...\n");
-
- // Write Status Register 1 <- 0x00
- uint8_t data[2] = { FC_WSR1, 0x00 };
- //flash_chip_select();
- mpsse_xfer_spi(data, 2);
- //flash_chip_deselect();
-
- flash_wait();
-
- // Read Status Register 1
- data[0] = FC_RSR1;
-
- //flash_chip_select();
- mpsse_xfer_spi(data, 2);
- //flash_chip_deselect();
-
- if (data[1] != 0x00)
- fprintf(stderr, "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", data[1]);
-
-}
-
-// ---------------------------------------------------------
-// JTAG -> SPI functions
-// ---------------------------------------------------------
-
-/*
- * JTAG performrs all shifts LSB first, our FLSAH is expeting bytes MSB first,
- * There are a few ways to fix this, for now we just bit-reverse all the input data to the JTAG core
- */
-uint8_t bit_reverse(uint8_t in){
-
- uint8_t out = (in & 0x01) ? 0x80 : 0x00;
- out |= (in & 0x02) ? 0x40 : 0x00;
- out |= (in & 0x04) ? 0x20 : 0x00;
- out |= (in & 0x08) ? 0x10 : 0x00;
- out |= (in & 0x10) ? 0x08 : 0x00;
- out |= (in & 0x20) ? 0x04 : 0x00;
- out |= (in & 0x40) ? 0x02 : 0x00;
- out |= (in & 0x80) ? 0x01 : 0x00;
-
- return out;
-}
-
-void xfer_spi(uint8_t* data, uint32_t len){
- /* Flip bit order of all bytes */
- for(int i = 0; i < len; i++){
- data[i] = bit_reverse(data[i]);
- }
-
- jtag_go_to_state(STATE_SHIFT_DR);
- jtag_tap_shift(data, data, len * 8, true);
-
- /* Flip bit order of all bytes */
- for(int i = 0; i < len; i++){
- data[i] = bit_reverse(data[i]);
- }
-}
-
-// ---------------------------------------------------------
-// ECP5 specific JTAG functions
-// ---------------------------------------------------------
-
-
-static void print_idcode(uint32_t idcode){
- for(int i = 0; i < sizeof(ecp_devices)/sizeof(struct ecp_device_id); i++){
- if(idcode == ecp_devices[i].device_id)
- {
- printf("IDCODE: 0x%08x (%s)\n", idcode ,ecp_devices[i].device_name);
- return;
- }
- }
- printf("IDCODE: 0x%08x does not match :(\n", idcode);
-}
-
-static void read_idcode(){
-
- uint8_t data[4] = {READ_ID};
-
- jtag_go_to_state(STATE_SHIFT_IR);
- jtag_tap_shift(data, data, 8, true);
-
- data[0] = 0;
- jtag_go_to_state(STATE_SHIFT_DR);
- jtag_tap_shift(data, data, 32, true);
-
- uint32_t idcode = 0;
-
- /* Format the IDCODE into a 32bit value */
- for(int i = 0; i< 4; i++)
- idcode = data[i] << 24 | idcode >> 8;
-
- print_idcode(idcode);
-}
-
-
-static void print_status_register(uint32_t status){
- printf("ECP5 Status Register: 0x%08x\n", status);
-
- if(verbose){
- printf(" Transparent Mode: %s\n", status & (1 << 0) ? "Yes" : "No" );
- printf(" Config Target: %s\n", status & (7 << 1) ? "SRAM" : "eFuse" );
- printf(" JTAG Active: %s\n", status & (1 << 4) ? "Yes" : "No" );
- printf(" PWD Protection: %s\n", status & (1 << 5) ? "Yes" : "No" );
- printf(" Decrypt Enable: %s\n", status & (1 << 7) ? "Yes" : "No" );
- printf(" DONE: %s\n", status & (1 << 8) ? "Yes" : "No" );
- printf(" ISC Enable: %s\n", status & (1 << 9) ? "Yes" : "No" );
- printf(" Write Enable: %s\n", status & (1 << 10) ? "Writable" : "Not Writable");
- printf(" Read Enable: %s\n", status & (1 << 11) ? "Readable" : "Not Readable");
- printf(" Busy Flag: %s\n", status & (1 << 12) ? "Yes" : "No" );
- printf(" Fail Flag: %s\n", status & (1 << 13) ? "Yes" : "No" );
- printf(" Feature OTP: %s\n", status & (1 << 14) ? "Yes" : "No" );
- printf(" Decrypt Only: %s\n", status & (1 << 15) ? "Yes" : "No" );
- printf(" PWD Enable: %s\n", status & (1 << 16) ? "Yes" : "No" );
- printf(" Encrypt Preamble: %s\n", status & (1 << 20) ? "Yes" : "No" );
- printf(" Std Preamble: %s\n", status & (1 << 21) ? "Yes" : "No" );
- printf(" SPIm Fail 1: %s\n", status & (1 << 22) ? "Yes" : "No" );
-
- uint8_t bse_error = (status & (7 << 23)) >> 23;
- switch (bse_error){
- case 0b000: printf(" BSE Error Code: No Error (0b000)\n"); break;
- case 0b001: printf(" BSE Error Code: ID Error (0b001)\n"); break;
- case 0b010: printf(" BSE Error Code: CMD Error - illegal command (0b010)\n"); break;
- case 0b011: printf(" BSE Error Code: CRC Error (0b011)\n"); break;
- case 0b100: printf(" BSE Error Code: PRMB Error - preamble error (0b100)\n"); break;
- case 0b101: printf(" BSE Error Code: ABRT Error - configuration aborted by the user (0b101)\n"); break;
- case 0b110: printf(" BSE Error Code: OVFL Error - data overflow error (0b110)\n"); break;
- case 0b111: printf(" BSE Error Code: SDM Error - bitstream pass the size of SRAM array (0b111)\n"); break;
- }
-
- printf(" Execution Error: %s\n", status & (1 << 26) ? "Yes" : "No" );
- printf(" ID Error: %s\n", status & (1 << 27) ? "Yes" : "No" );
- printf(" Invalid Command: %s\n", status & (1 << 28) ? "Yes" : "No" );
- printf(" SED Error: %s\n", status & (1 << 29) ? "Yes" : "No" );
- printf(" Bypass Mode: %s\n", status & (1 << 30) ? "Yes" : "No" );
- printf(" Flow Througuh Mode: %s\n", status & (1 << 31) ? "Yes" : "No" );
-
- }
-
-
-}
-
-
-static void read_status_register(){
-
- uint8_t data[4] = {LSC_READ_STATUS};
-
- jtag_go_to_state(STATE_SHIFT_IR);
- jtag_tap_shift(data, data, 8, true);
-
- data[0] = 0;
- jtag_go_to_state(STATE_SHIFT_DR);
- jtag_tap_shift(data, data, 32, true);
-
- uint32_t status = 0;
-
- /* Format the IDCODE into a 32bit value */
- for(int i = 0; i< 4; i++)
- status = data[i] << 24 | status >> 8;
-
- print_status_register(status);
-}
-
-
-
-static void enter_spi_background_mode(){
-
- uint8_t data_in[4] = {0,0,0,0};
- uint8_t data_out[4] = {0,0,0,0};
-
- data_in[0] = 0x3A;
- jtag_go_to_state(STATE_SHIFT_IR);
- jtag_tap_shift(data_in, data_out, 8, true);
-
- /* These bytes seem to be required to un-lock the SPI interface */
- data_in[0] = 0xFE;
- data_in[1] = 0x68;
- jtag_go_to_state(STATE_SHIFT_DR);
- jtag_tap_shift(data_in, data_out, 16, true);
-
- /* Entering IDLE is essential */
- jtag_go_to_state(STATE_RUN_TEST_IDLE);
-}
-
-
-void ecp_jtag_cmd(uint8_t cmd){
- uint8_t data_in[1] = {0};
- uint8_t data_out[1] = {0};
-
- data_in[0] = cmd;
- jtag_go_to_state(STATE_SHIFT_IR);
- jtag_tap_shift(data_in, data_out, 8, true);
-
- jtag_go_to_state(STATE_RUN_TEST_IDLE);
- jtag_wait_time(10);
-}
-
-// ---------------------------------------------------------
-// iceprog implementation
-// ---------------------------------------------------------
-
-static void help(const char *progname)
-{
- fprintf(stderr, "Simple programming tool for FTDI-based Lattice iCE programmers.\n");
- fprintf(stderr, "Usage: %s [-b|-n|-c] <input file>\n", progname);
- fprintf(stderr, " %s -r|-R<bytes> <output file>\n", progname);
- fprintf(stderr, " %s -S <input file>\n", progname);
- fprintf(stderr, " %s -t\n", progname);
- fprintf(stderr, "\n");
- fprintf(stderr, "General options:\n");
- fprintf(stderr, " -d <device string> use the specified USB device [default: i:0x0403:0x6010 or i:0x0403:0x6014]\n");
- fprintf(stderr, " d:<devicenode> (e.g. d:002/005)\n");
- fprintf(stderr, " i:<vendor>:<product> (e.g. i:0x0403:0x6010)\n");
- fprintf(stderr, " i:<vendor>:<product>:<index> (e.g. i:0x0403:0x6010:0)\n");
- fprintf(stderr, " s:<vendor>:<product>:<serial-string>\n");
- fprintf(stderr, " -I [ABCD] connect to the specified interface on the FTDI chip\n");
- fprintf(stderr, " [default: A]\n");
- fprintf(stderr, " -o <offset in bytes> start address for read/write [default: 0]\n");
- fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n");
- fprintf(stderr, " or 'M' for size in megabytes)\n");
- fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n");
- fprintf(stderr, " -v verbose output\n");
- fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Mode of operation:\n");
- fprintf(stderr, " [default] write file contents to flash, then verify\n");
- fprintf(stderr, " -X write file contents to flash only\n");
- fprintf(stderr, " -r read first 256 kB from flash and write to file\n");
- fprintf(stderr, " -R <size in bytes> read the specified number of bytes from flash\n");
- fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n");
- fprintf(stderr, " or 'M' for size in megabytes)\n");
- fprintf(stderr, " -c do not write flash, only verify (`check')\n");
- fprintf(stderr, " -S perform SRAM programming\n");
- fprintf(stderr, " -t just read the flash ID sequence\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Erase mode (only meaningful in default mode):\n");
- fprintf(stderr, " [default] erase aligned chunks of 64kB in write mode\n");
- fprintf(stderr, " This means that some data after the written data (or\n");
- fprintf(stderr, " even before when -o is used) may be erased as well.\n");
- fprintf(stderr, " -b bulk erase entire flash before writing\n");
- fprintf(stderr, " -e <size in bytes> erase flash as if we were writing that number of bytes\n");
- fprintf(stderr, " -n do not erase flash before writing\n");
- fprintf(stderr, " -p disable write protection before erasing or writing\n");
- fprintf(stderr, " This can be useful if flash memory appears to be\n");
- fprintf(stderr, " bricked and won't respond to erasing or programming.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Miscellaneous options:\n");
- fprintf(stderr, " --help display this help and exit\n");
- fprintf(stderr, " -- treat all remaining arguments as filenames\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Exit status:\n");
- fprintf(stderr, " 0 on success,\n");
- fprintf(stderr, " 1 if a non-hardware error occurred (e.g., failure to read from or\n");
- fprintf(stderr, " write to a file, or invoked with invalid options),\n");
- fprintf(stderr, " 2 if communication with the hardware failed (e.g., cannot find the\n");
- fprintf(stderr, " iCE FTDI USB device),\n");
- fprintf(stderr, " 3 if verification of the data failed.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Notes for iCEstick (iCE40HX-1k devel board):\n");
- fprintf(stderr, " An unmodified iCEstick can only be programmed via the serial flash.\n");
- fprintf(stderr, " Direct programming of the SRAM is not supported. For direct SRAM\n");
- fprintf(stderr, " programming the flash chip and one zero ohm resistor must be desoldered\n");
- fprintf(stderr, " and the FT2232H SI pin must be connected to the iCE SPI_SI pin, as shown\n");
- fprintf(stderr, " in this picture:\n");
- fprintf(stderr, " http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Notes for the iCE40-HX8K Breakout Board:\n");
- fprintf(stderr, " Make sure that the jumper settings on the board match the selected\n");
- fprintf(stderr, " mode (SRAM or FLASH). See the iCE40-HX8K user manual for details.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "If you have a bug report, please file an issue on github:\n");
- fprintf(stderr, " https://github.com/cliffordwolf/icestorm/issues\n");
-}
-
-int main(int argc, char **argv)
-{
- /* used for error reporting */
- const char *my_name = argv[0];
- for (size_t i = 0; argv[0][i]; i++)
- if (argv[0][i] == '/')
- my_name = argv[0] + i + 1;
-
- int read_size = 256 * 1024;
- int erase_block_size = 64;
- int erase_size = 0;
- int rw_offset = 0;
-
- bool read_mode = false;
- bool check_mode = false;
- bool erase_mode = false;
- bool bulk_erase = false;
- bool dont_erase = false;
- bool prog_sram = false;
- bool test_mode = false;
- bool slow_clock = false;
- bool disable_protect = false;
- bool disable_verify = false;
- const char *filename = NULL;
- const char *devstr = NULL;
- int ifnum = 0;
-
-#ifdef _WIN32
- _setmode(_fileno(stdin), _O_BINARY);
- _setmode(_fileno(stdout), _O_BINARY);
-#endif
-
- static struct option long_options[] = {
- {"help", no_argument, NULL, -2},
- {NULL, 0, NULL, 0}
- };
-
- /* Decode command line parameters */
- int opt;
- char *endptr;
- while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStvspX", long_options, NULL)) != -1) {
- switch (opt) {
- case 'd': /* device string */
- devstr = optarg;
- break;
- case 'i': /* block erase size */
- if (!strcmp(optarg, "4"))
- erase_block_size = 4;
- else if (!strcmp(optarg, "32"))
- erase_block_size = 32;
- else if (!strcmp(optarg, "64"))
- erase_block_size = 64;
- else {
- fprintf(stderr, "%s: `%s' is not a valid erase block size (must be `4', `32' or `64')\n", my_name, optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'I': /* FTDI Chip interface select */
- if (!strcmp(optarg, "A"))
- ifnum = 0;
- else if (!strcmp(optarg, "B"))
- ifnum = 1;
- else if (!strcmp(optarg, "C"))
- ifnum = 2;
- else if (!strcmp(optarg, "D"))
- ifnum = 3;
- else {
- fprintf(stderr, "%s: `%s' is not a valid interface (must be `A', `B', `C', or `D')\n", my_name, optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'r': /* Read 256 bytes to file */
- read_mode = true;
- break;
- case 'R': /* Read n bytes to file */
- read_mode = true;
- read_size = strtol(optarg, &endptr, 0);
- if (*endptr == '\0')
- /* ok */;
- else if (!strcmp(endptr, "k"))
- read_size *= 1024;
- else if (!strcmp(endptr, "M"))
- read_size *= 1024 * 1024;
- else {
- fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'e': /* Erase blocks as if we were writing n bytes */
- erase_mode = true;
- erase_size = strtol(optarg, &endptr, 0);
- if (*endptr == '\0')
- /* ok */;
- else if (!strcmp(endptr, "k"))
- erase_size *= 1024;
- else if (!strcmp(endptr, "M"))
- erase_size *= 1024 * 1024;
- else {
- fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'o': /* set address offset */
- rw_offset = strtol(optarg, &endptr, 0);
- if (*endptr == '\0')
- /* ok */;
- else if (!strcmp(endptr, "k"))
- rw_offset *= 1024;
- else if (!strcmp(endptr, "M"))
- rw_offset *= 1024 * 1024;
- else {
- fprintf(stderr, "%s: `%s' is not a valid offset\n", my_name, optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'c': /* do not write just check */
- check_mode = true;
- break;
- case 'b': /* bulk erase before writing */
- bulk_erase = true;
- break;
- case 'n': /* do not erase before writing */
- dont_erase = true;
- break;
- case 'S': /* write to sram directly */
- prog_sram = true;
- break;
- case 't': /* just read flash id */
- test_mode = true;
- break;
- case 'v': /* provide verbose output */
- verbose = true;
- break;
- case 's': /* use slow SPI clock */
- slow_clock = true;
- break;
- case 'p': /* disable flash protect before erase/write */
- disable_protect = true;
- break;
- case 'X': /* disable verification */
- disable_verify = true;
- break;
- case -2:
- help(argv[0]);
- return EXIT_SUCCESS;
- default:
- /* error message has already been printed */
- fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
- return EXIT_FAILURE;
- }
- }
-
- /* Make sure that the combination of provided parameters makes sense */
-
- if (read_mode + erase_mode + check_mode + prog_sram + test_mode > 1) {
- fprintf(stderr, "%s: options `-r'/`-R', `-e`, `-c', `-S', and `-t' are mutually exclusive\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (bulk_erase && dont_erase) {
- fprintf(stderr, "%s: options `-b' and `-n' are mutually exclusive\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (disable_protect && (read_mode || check_mode || prog_sram || test_mode)) {
- fprintf(stderr, "%s: option `-p' only valid in programming mode\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (bulk_erase && (read_mode || check_mode || prog_sram || test_mode)) {
- fprintf(stderr, "%s: option `-b' only valid in programming mode\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (dont_erase && (read_mode || check_mode || prog_sram || test_mode)) {
- fprintf(stderr, "%s: option `-n' only valid in programming mode\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (rw_offset != 0 && prog_sram) {
- fprintf(stderr, "%s: option `-o' not supported in SRAM mode\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (rw_offset != 0 && test_mode) {
- fprintf(stderr, "%s: option `-o' not supported in test mode\n", my_name);
- return EXIT_FAILURE;
- }
-
- if (optind + 1 == argc) {
- if (test_mode) {
- fprintf(stderr, "%s: test mode doesn't take a file name\n", my_name);
- fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
- return EXIT_FAILURE;
- }
- filename = argv[optind];
- } else if (optind != argc) {
- fprintf(stderr, "%s: too many arguments\n", my_name);
- fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
- return EXIT_FAILURE;
- } else if (bulk_erase || disable_protect) {
- filename = "/dev/null";
- } else if (!test_mode && !erase_mode && !disable_protect) {
- fprintf(stderr, "%s: missing argument\n", my_name);
- fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- /* open input/output file in advance
- so we can fail before initializing the hardware */
-
- FILE *f = NULL;
- long file_size = -1;
-
- if (test_mode) {
- /* nop */;
- } else if (erase_mode) {
- file_size = erase_size;
- } else if (read_mode) {
- f = (strcmp(filename, "-") == 0) ? stdout : fopen(filename, "wb");
- if (f == NULL) {
- fprintf(stderr, "%s: can't open '%s' for writing: ", my_name, filename);
- perror(0);
- return EXIT_FAILURE;
- }
- } else {
- f = (strcmp(filename, "-") == 0) ? stdin : fopen(filename, "rb");
- if (f == NULL) {
- fprintf(stderr, "%s: can't open '%s' for reading: ", my_name, filename);
- perror(0);
- return EXIT_FAILURE;
- }
-
- /* For regular programming, we need to read the file
- twice--once for programming and once for verifying--and
- need to know the file size in advance in order to erase
- the correct amount of memory.
-
- See if we can seek on the input file. Checking for "-"
- as an argument isn't enough as we might be reading from a
- named pipe, or contrarily, the standard input may be an
- ordinary file. */
-
- if (!prog_sram && !check_mode) {
- if (fseek(f, 0L, SEEK_END) != -1) {
- file_size = ftell(f);
- if (file_size == -1) {
- fprintf(stderr, "%s: %s: ftell: ", my_name, filename);
- perror(0);
- return EXIT_FAILURE;
- }
- if (fseek(f, 0L, SEEK_SET) == -1) {
- fprintf(stderr, "%s: %s: fseek: ", my_name, filename);
- perror(0);
- return EXIT_FAILURE;
- }
- } else {
- FILE *pipe = f;
-
- f = tmpfile();
- if (f == NULL) {
- fprintf(stderr, "%s: can't open temporary file\n", my_name);
- return EXIT_FAILURE;
- }
- file_size = 0;
-
- while (true) {
- static unsigned char buffer[4096];
- size_t rc = fread(buffer, 1, 4096, pipe);
- if (rc <= 0)
- break;
- size_t wc = fwrite(buffer, 1, rc, f);
- if (wc != rc) {
- fprintf(stderr, "%s: can't write to temporary file\n", my_name);
- return EXIT_FAILURE;
- }
- file_size += rc;
- }
- fclose(pipe);
-
- /* now seek to the beginning so we can
- start reading again */
- fseek(f, 0, SEEK_SET);
- }
- }
- }
-
- // ---------------------------------------------------------
- // Initialize USB connection to FT2232H
- // ---------------------------------------------------------
-
- fprintf(stderr, "init..\n");
-
- mpsse_init(ifnum, devstr, slow_clock);
- mpsse_jtag_init();
-
- read_idcode();
- read_status_register();
-
- /* Reset ECP5 to release SPI interface */
- ecp_jtag_cmd(ISC_ENABLE);
- ecp_jtag_cmd(ISC_ERASE);
- ecp_jtag_cmd(ISC_DISABLE);
-
- /* Put device into SPI bypass mode */
- enter_spi_background_mode();
-
- usleep(20000);
-
- if (test_mode)
- {
- flash_read_id();
- }
- else if (prog_sram)
- {
- // ---------------------------------------------------------
- // Reset
- // ---------------------------------------------------------
-
- fprintf(stderr, "reset..\n");
-
- //sram_reset();
- usleep(100);
-
- //sram_chip_select();
- usleep(2000);
-
-
- // ---------------------------------------------------------
- // Program
- // ---------------------------------------------------------
-
- fprintf(stderr, "programming..\n");
- while (1) {
- static unsigned char buffer[4096];
- int rc = fread(buffer, 1, 4096, f);
- if (rc <= 0)
- break;
- if (verbose)
- fprintf(stderr, "sending %d bytes.\n", rc);
- mpsse_send_spi(buffer, rc);
- }
-
- mpsse_send_dummy_bytes(6);
- mpsse_send_dummy_bit();
-
-
- }
- else /* program flash */
- {
- // ---------------------------------------------------------
- // Reset
- // ---------------------------------------------------------
-
- fprintf(stderr, "reset..\n");
-
- //flash_chip_deselect();
- usleep(250000);
-
-
-
- flash_reset();
- flash_power_up();
-
- flash_read_id();
-
-
- // ---------------------------------------------------------
- // Program
- // ---------------------------------------------------------
-
- if (!read_mode && !check_mode)
- {
- if (disable_protect)
- {
- flash_write_enable();
- flash_disable_protection();
- }
-
- if (!dont_erase)
- {
- if (bulk_erase)
- {
- flash_write_enable();
- flash_bulk_erase();
- flash_wait();
- }
- else
- {
- fprintf(stderr, "file size: %ld\n", file_size);
-
- int block_size = erase_block_size << 10;
- int block_mask = block_size - 1;
- int begin_addr = rw_offset & ~block_mask;
- int end_addr = (rw_offset + file_size + block_mask) & ~block_mask;
-
- for (int addr = begin_addr; addr < end_addr; addr += block_size) {
- flash_write_enable();
- switch(erase_block_size) {
- case 4:
- flash_4kB_sector_erase(addr);
- break;
- case 32:
- flash_32kB_sector_erase(addr);
- break;
- case 64:
- flash_64kB_sector_erase(addr);
- break;
- }
- if (verbose) {
- fprintf(stderr, "Status after block erase:\n");
- flash_read_status();
- }
- flash_wait();
- }
- }
- }
-
- if (!erase_mode)
- {
- fprintf(stderr, "programming..\n");
-
- for (int rc, addr = 0; true; addr += rc) {
- uint8_t buffer[256];
- int page_size = 256 - (rw_offset + addr) % 256;
- rc = fread(buffer, 1, page_size, f);
- if (rc <= 0)
- break;
- flash_write_enable();
- flash_prog(rw_offset + addr, buffer, rc);
- flash_wait();
- }
-
- /* seek to the beginning for second pass */
- fseek(f, 0, SEEK_SET);
- }
- }
-
- // ---------------------------------------------------------
- // Read/Verify
- // ---------------------------------------------------------
-
- if (read_mode) {
- fprintf(stderr, "reading..\n");
- for (int addr = 0; addr < read_size; addr += 256) {
- uint8_t buffer[256];
- flash_read(rw_offset + addr, buffer, 256);
- fwrite(buffer, read_size - addr > 256 ? 256 : read_size - addr, 1, f);
- }
- } else if (!erase_mode && !disable_verify) {
- fprintf(stderr, "reading..\n");
- for (int addr = 0; true; addr += 256) {
- uint8_t buffer_flash[256], buffer_file[256];
- int rc = fread(buffer_file, 1, 256, f);
- if (rc <= 0)
- break;
- flash_read(rw_offset + addr, buffer_flash, rc);
- if (memcmp(buffer_file, buffer_flash, rc)) {
- fprintf(stderr, "Found difference between flash and file!\n");
- mpsse_error(3);
- }
- }
-
- fprintf(stderr, "VERIFY OK\n");
- }
-
-
- // ---------------------------------------------------------
- // Reset
- // ---------------------------------------------------------
-
- //flash_power_down();
-
- usleep(250000);
-
-
- }
-
- if (f != NULL && f != stdin && f != stdout)
- fclose(f);
-
- // ---------------------------------------------------------
- // Exit
- // ---------------------------------------------------------
-
- fprintf(stderr, "Bye.\n");
- mpsse_close();
- return 0;
-}