move project into folder
authorGreg Davill <greg.davill@gmail.com>
Sun, 19 Apr 2020 04:00:19 +0000 (13:30 +0930)
committerGreg Davill <greg.davill@gmail.com>
Sun, 19 Apr 2020 04:00:19 +0000 (13:30 +0930)
15 files changed:
.gitignore
Makefile [deleted file]
ecpprog.c [deleted file]
ecpprog/Makefile [new file with mode: 0644]
ecpprog/ecpprog.c [new file with mode: 0644]
ecpprog/jtag.h [new file with mode: 0644]
ecpprog/jtag_tap.c [new file with mode: 0644]
ecpprog/lattice_cmds.h [new file with mode: 0644]
ecpprog/mpsse.c [new file with mode: 0644]
ecpprog/mpsse.h [new file with mode: 0644]
jtag.h [deleted file]
jtag_tap.c [deleted file]
lattice_cmds.h [deleted file]
mpsse.c [deleted file]
mpsse.h [deleted file]

index 51413026d902053973eb802a16ff66b02706013b..60aca84d251c79d8980386749b7c3daa309a47ef 100644 (file)
@@ -1,4 +1,4 @@
-ecpprog
+ecpprog/ecpprog
 *.exe
 *.o
 *.d
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index 611d39d..0000000
--- a/Makefile
+++ /dev/null
@@ -1,71 +0,0 @@
-PREFIX ?= /usr/local
-DEBUG ?= 0
-ICEPROG ?= 1
-PROGRAM_PREFIX ?=
-
-CXX ?= clang++
-CC ?= clang
-PKG_CONFIG ?= pkg-config
-
-C_STD ?= c99
-CXX_STD ?= c++11
-ifeq ($(DEBUG),1)
-OPT_LEVEL ?= 0
-DBG_LEVEL ?= -ggdb
-else
-OPT_LEVEL ?= 2
-DBG_LEVEL ?=
-endif
-WARN_LEVEL ?= all
-
-LDLIBS = -lm -lstdc++
-CFLAGS += -MD -O$(OPT_LEVEL) $(DBG_LEVEL) -W$(WARN_LEVEL) -std=$(C_STD) -I$(PREFIX)/include
-CXXFLAGS += -MD -O$(OPT_LEVEL) $(DBG_LEVEL) -W$(WARN_LEVEL) -std=$(CXX_STD) -I$(PREFIX)/include
-
-DESTDIR ?=
-CHIPDB_SUBDIR ?= $(PROGRAM_PREFIX)icebox
-
-ifeq ($(MXE),1)
-EXE = .exe
-CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
-CC = $(CXX)
-PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
-endif
-
-ifneq ($(shell uname -s),Darwin)
-  LDLIBS = -L/usr/local/lib -lm
-else
-  LIBFTDI_NAME = $(shell $(PKG_CONFIG) --exists libftdi1 && echo ftdi1 || echo ftdi)
-  LDLIBS = -L/usr/local/lib -l$(LIBFTDI_NAME) -lm
-endif
-
-ifeq ($(STATIC),1)
-LDFLAGS += -static
-LDLIBS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --static --libs $$pkg && exit; done; echo -lftdi; )
-CFLAGS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --static --cflags $$pkg && exit; done; )
-else
-LDLIBS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --libs $$pkg && exit; done; echo -lftdi; )
-CFLAGS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --cflags $$pkg && exit; done; )
-endif
-
-all: $(PROGRAM_PREFIX)ecpprog$(EXE)
-
-$(PROGRAM_PREFIX)ecpprog$(EXE): ecpprog.o mpsse.o jtag_tap.o
-       $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS)
-
-install: all
-       mkdir -p $(DESTDIR)$(PREFIX)/bin
-       cp $(PROGRAM_PREFIX)ecpprog$(EXE) $(DESTDIR)$(PREFIX)/bin/$(PROGRAM_PREFIX)ecpprog$(EXE)
-
-uninstall:
-       rm -f $(DESTDIR)$(PREFIX)/bin/$(PROGRAM_PREFIX)ecpprog$(EXE)
-
-clean:
-       rm -f $(PROGRAM_PREFIX)ecpprog
-       rm -f $(PROGRAM_PREFIX)ecpprog.exe
-       rm -f *.o *.d
-
--include *.d
-
-.PHONY: all install uninstall clean
-
diff --git a/ecpprog.c b/ecpprog.c
deleted file mode 100644 (file)
index e058a38..0000000
--- a/ecpprog.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- *  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 "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 */
-};
-
-
-// ---------------------------------------------------------
-// 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){
-       /* Reverse bit order of all bytes */
-       for(int i = 0; i < len; i++){
-               data[i] = bit_reverse(data[i]);
-       }
-
-       /* Don't switch states if we're already in SHIFT-DR */
-       if(jtag_current_state() != STATE_SHIFT_DR)
-               jtag_go_to_state(STATE_SHIFT_DR);
-       jtag_tap_shift(data, data, len * 8, true);
-
-       /* Reverse bit order of all return bytes */
-       for(int i = 0; i < len; i++){
-               data[i] = bit_reverse(data[i]);
-       }
-}
-
-void send_spi(uint8_t* data, uint32_t len){
-       uint8_t unused[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);
-       /* Stay in SHIFT-DR state, this keep CS low */
-       jtag_tap_shift(data, unused, len * 8, false); 
-}
-
-// ---------------------------------------------------------
-// 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");
-
-       // Write command and read first 4 bytes
-       xfer_spi(data, len);
-
-       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);
-               }
-       }
-       
-       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 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");
-       }
-
-       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 };
-       xfer_spi(data, 1);
-
-       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 };
-       xfer_spi(data, 1);
-}
-
-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 };
-
-       xfer_spi(command, 4);
-}
-
-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 };
-
-       xfer_spi(command, 4);
-}
-
-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 };
-
-       xfer_spi(command, 4);
-}
-
-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 };
-
-       send_spi(command, 4);
-       xfer_spi(data, n);
-       
-       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 };
-
-       send_spi(command, 4);
-       memset(data, 0, n);
-       xfer_spi(data, n);
-       
-       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 };
-
-               xfer_spi(data, 2);
-
-               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 };
-       xfer_spi(data, 2);
-       
-       flash_wait();
-       
-       // Read Status Register 1
-       data[0] = FC_RSR1;
-
-       xfer_spi(data, 2);
-
-       if (data[1] != 0x00)
-               fprintf(stderr, "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", data[1]);
-
-}
-
-// ---------------------------------------------------------
-// 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)  ? "eFuse" : "SRAM" );
-               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 Through 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[1] = {cmd};
-
-       jtag_go_to_state(STATE_SHIFT_IR);
-       jtag_tap_shift(data, data, 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..");
-       jtag_init(ifnum, devstr, slow_clock);
-
-       fprintf(stderr, "idcode..\n");
-       read_idcode();
-
-       fprintf(stderr, "status..\n");
-       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_reset();
-               flash_read_id();
-       }
-       else if (prog_sram)
-       {
-               // ---------------------------------------------------------
-               // Reset
-               // ---------------------------------------------------------
-
-               fprintf(stderr, "Not Supported yet\n");
-               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_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");
-                                       jtag_error(3);
-                               }
-                       }
-
-                       fprintf(stderr, "VERIFY OK\n");
-               }
-       }
-
-       if (f != NULL && f != stdin && f != stdout)
-               fclose(f);
-
-       // ---------------------------------------------------------
-       // Exit
-       // ---------------------------------------------------------
-
-       fprintf(stderr, "Bye.\n");
-       jtag_deinit();
-       return 0;
-}
diff --git a/ecpprog/Makefile b/ecpprog/Makefile
new file mode 100644 (file)
index 0000000..611d39d
--- /dev/null
@@ -0,0 +1,71 @@
+PREFIX ?= /usr/local
+DEBUG ?= 0
+ICEPROG ?= 1
+PROGRAM_PREFIX ?=
+
+CXX ?= clang++
+CC ?= clang
+PKG_CONFIG ?= pkg-config
+
+C_STD ?= c99
+CXX_STD ?= c++11
+ifeq ($(DEBUG),1)
+OPT_LEVEL ?= 0
+DBG_LEVEL ?= -ggdb
+else
+OPT_LEVEL ?= 2
+DBG_LEVEL ?=
+endif
+WARN_LEVEL ?= all
+
+LDLIBS = -lm -lstdc++
+CFLAGS += -MD -O$(OPT_LEVEL) $(DBG_LEVEL) -W$(WARN_LEVEL) -std=$(C_STD) -I$(PREFIX)/include
+CXXFLAGS += -MD -O$(OPT_LEVEL) $(DBG_LEVEL) -W$(WARN_LEVEL) -std=$(CXX_STD) -I$(PREFIX)/include
+
+DESTDIR ?=
+CHIPDB_SUBDIR ?= $(PROGRAM_PREFIX)icebox
+
+ifeq ($(MXE),1)
+EXE = .exe
+CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
+CC = $(CXX)
+PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
+endif
+
+ifneq ($(shell uname -s),Darwin)
+  LDLIBS = -L/usr/local/lib -lm
+else
+  LIBFTDI_NAME = $(shell $(PKG_CONFIG) --exists libftdi1 && echo ftdi1 || echo ftdi)
+  LDLIBS = -L/usr/local/lib -l$(LIBFTDI_NAME) -lm
+endif
+
+ifeq ($(STATIC),1)
+LDFLAGS += -static
+LDLIBS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --static --libs $$pkg && exit; done; echo -lftdi; )
+CFLAGS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --static --cflags $$pkg && exit; done; )
+else
+LDLIBS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --libs $$pkg && exit; done; echo -lftdi; )
+CFLAGS += $(shell for pkg in libftdi1 libftdi; do $(PKG_CONFIG) --silence-errors --cflags $$pkg && exit; done; )
+endif
+
+all: $(PROGRAM_PREFIX)ecpprog$(EXE)
+
+$(PROGRAM_PREFIX)ecpprog$(EXE): ecpprog.o mpsse.o jtag_tap.o
+       $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS)
+
+install: all
+       mkdir -p $(DESTDIR)$(PREFIX)/bin
+       cp $(PROGRAM_PREFIX)ecpprog$(EXE) $(DESTDIR)$(PREFIX)/bin/$(PROGRAM_PREFIX)ecpprog$(EXE)
+
+uninstall:
+       rm -f $(DESTDIR)$(PREFIX)/bin/$(PROGRAM_PREFIX)ecpprog$(EXE)
+
+clean:
+       rm -f $(PROGRAM_PREFIX)ecpprog
+       rm -f $(PROGRAM_PREFIX)ecpprog.exe
+       rm -f *.o *.d
+
+-include *.d
+
+.PHONY: all install uninstall clean
+
diff --git a/ecpprog/ecpprog.c b/ecpprog/ecpprog.c
new file mode 100644 (file)
index 0000000..e058a38
--- /dev/null
@@ -0,0 +1,1075 @@
+/*
+ *  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 "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 */
+};
+
+
+// ---------------------------------------------------------
+// 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){
+       /* Reverse bit order of all bytes */
+       for(int i = 0; i < len; i++){
+               data[i] = bit_reverse(data[i]);
+       }
+
+       /* Don't switch states if we're already in SHIFT-DR */
+       if(jtag_current_state() != STATE_SHIFT_DR)
+               jtag_go_to_state(STATE_SHIFT_DR);
+       jtag_tap_shift(data, data, len * 8, true);
+
+       /* Reverse bit order of all return bytes */
+       for(int i = 0; i < len; i++){
+               data[i] = bit_reverse(data[i]);
+       }
+}
+
+void send_spi(uint8_t* data, uint32_t len){
+       uint8_t unused[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);
+       /* Stay in SHIFT-DR state, this keep CS low */
+       jtag_tap_shift(data, unused, len * 8, false); 
+}
+
+// ---------------------------------------------------------
+// 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");
+
+       // Write command and read first 4 bytes
+       xfer_spi(data, len);
+
+       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);
+               }
+       }
+       
+       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 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");
+       }
+
+       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 };
+       xfer_spi(data, 1);
+
+       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 };
+       xfer_spi(data, 1);
+}
+
+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 };
+
+       xfer_spi(command, 4);
+}
+
+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 };
+
+       xfer_spi(command, 4);
+}
+
+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 };
+
+       xfer_spi(command, 4);
+}
+
+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 };
+
+       send_spi(command, 4);
+       xfer_spi(data, n);
+       
+       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 };
+
+       send_spi(command, 4);
+       memset(data, 0, n);
+       xfer_spi(data, n);
+       
+       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 };
+
+               xfer_spi(data, 2);
+
+               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 };
+       xfer_spi(data, 2);
+       
+       flash_wait();
+       
+       // Read Status Register 1
+       data[0] = FC_RSR1;
+
+       xfer_spi(data, 2);
+
+       if (data[1] != 0x00)
+               fprintf(stderr, "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", data[1]);
+
+}
+
+// ---------------------------------------------------------
+// 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)  ? "eFuse" : "SRAM" );
+               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 Through 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[1] = {cmd};
+
+       jtag_go_to_state(STATE_SHIFT_IR);
+       jtag_tap_shift(data, data, 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..");
+       jtag_init(ifnum, devstr, slow_clock);
+
+       fprintf(stderr, "idcode..\n");
+       read_idcode();
+
+       fprintf(stderr, "status..\n");
+       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_reset();
+               flash_read_id();
+       }
+       else if (prog_sram)
+       {
+               // ---------------------------------------------------------
+               // Reset
+               // ---------------------------------------------------------
+
+               fprintf(stderr, "Not Supported yet\n");
+               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_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");
+                                       jtag_error(3);
+                               }
+                       }
+
+                       fprintf(stderr, "VERIFY OK\n");
+               }
+       }
+
+       if (f != NULL && f != stdin && f != stdout)
+               fclose(f);
+
+       // ---------------------------------------------------------
+       // Exit
+       // ---------------------------------------------------------
+
+       fprintf(stderr, "Bye.\n");
+       jtag_deinit();
+       return 0;
+}
diff --git a/ecpprog/jtag.h b/ecpprog/jtag.h
new file mode 100644 (file)
index 0000000..51caa9d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Code for interacting with the FPGA via JTAG.
+ * This file is part of LUNA.
+ *
+ * This JTAG driver is intended to be as simple as possible in order to facilitate
+ * configuration and debugging of the attached FPGA. It is not intended to be a general-
+ * purpose JTAG link.
+ */
+
+#ifndef __JTAG_H__
+#define __JTAG_H__
+
+typedef enum e_TAPState
+{
+       STATE_TEST_LOGIC_RESET =  0,
+       STATE_RUN_TEST_IDLE    =  1,
+       STATE_SELECT_DR_SCAN   =  2,
+       STATE_CAPTURE_DR       =  3,
+       STATE_SHIFT_DR         =  4,
+       STATE_EXIT1_DR         =  5,
+       STATE_PAUSE_DR         =  6,
+       STATE_EXIT2_DR         =  7,
+       STATE_UPDATE_DR        =  8,
+       STATE_SELECT_IR_SCAN   =  9, 
+       STATE_CAPTURE_IR       = 10,
+       STATE_SHIFT_IR         = 11,
+       STATE_EXIT1_IR         = 12,
+       STATE_PAUSE_IR         = 13,
+       STATE_EXIT2_IR         = 14,
+       STATE_UPDATE_IR        = 15
+} jtag_tap_state_t;
+
+
+/**
+ * Performs the start-of-day tasks necessary to talk JTAG to our FPGA.
+ */
+void jtag_init(int ifnum, const char *devstr, bool slow_clock);
+
+
+/**
+ * De-inits the JTAG connection, so the JTAG chain. is no longer driven.
+ */
+void jtag_deinit(void);
+
+
+/**
+ * Moves to a given JTAG state.
+ */
+void jtag_goto_state(int state);
+
+
+/**
+ * Performs a raw TAP scan.
+ */
+void jtag_tap_shift(
+       uint8_t *input_data,
+       uint8_t *output_data,
+       uint32_t data_bits,
+       bool must_end);
+
+void jtag_error(int status);
+
+void jtag_wait_time(uint32_t microseconds);
+
+void jtag_go_to_state(unsigned state);
+
+uint8_t jtag_current_state(void);
+
+#endif
diff --git a/ecpprog/jtag_tap.c b/ecpprog/jtag_tap.c
new file mode 100644 (file)
index 0000000..44781f5
--- /dev/null
@@ -0,0 +1,268 @@
+/**
+ * Code adapted from Arduino-JTAG;
+ *    portions copyright (c) 2015 Marcelo Roberto Jimenez <marcelo.jimenez (at) gmail (dot) com>.
+ *    portions copyright (c) 2019 Katherine J. Temkin <kate@ktemkin.com>
+ *    portions copyright (c) 2019 Great Scott Gadgets <ktemkin@greatscottgadgets.com>
+ */
+
+#include <ftdi.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "mpsse.h"
+#include "jtag.h"
+
+void jtag_state_ack(bool tms);
+
+/*
+ * Low nibble : TMS == 0
+ * High nibble: TMS == 1
+ */
+
+#define TMS_T(TMS_HIGH_STATE, TMS_LOW_STATE) (((TMS_HIGH_STATE) << 4) | (TMS_LOW_STATE))
+
+static const uint8_t tms_transitions[] = {
+       /* STATE_TEST_LOGIC_RESET */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_RUN_TEST_IDLE),
+       /* STATE_RUN_TEST_IDLE    */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
+       /* STATE_SELECT_DR_SCAN   */ TMS_T(STATE_SELECT_IR_SCAN,   STATE_CAPTURE_DR),
+       /* STATE_CAPTURE_DR       */ TMS_T(STATE_EXIT1_DR,         STATE_SHIFT_DR),
+       /* STATE_SHIFT_DR         */ TMS_T(STATE_EXIT1_DR,         STATE_SHIFT_DR),
+       /* STATE_EXIT1_DR         */ TMS_T(STATE_UPDATE_DR,        STATE_PAUSE_DR),
+       /* STATE_PAUSE_DR         */ TMS_T(STATE_EXIT2_DR,         STATE_PAUSE_DR),
+       /* STATE_EXIT2_DR         */ TMS_T(STATE_UPDATE_DR,        STATE_SHIFT_DR),
+       /* STATE_UPDATE_DR        */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
+       /* STATE_SELECT_IR_SCAN   */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_CAPTURE_IR),
+       /* STATE_CAPTURE_IR       */ TMS_T(STATE_EXIT1_IR,         STATE_SHIFT_IR),
+       /* STATE_SHIFT_IR         */ TMS_T(STATE_EXIT1_IR,         STATE_SHIFT_IR),
+       /* STATE_EXIT1_IR         */ TMS_T(STATE_UPDATE_IR,        STATE_PAUSE_IR),
+       /* STATE_PAUSE_IR         */ TMS_T(STATE_EXIT2_IR,         STATE_PAUSE_IR),
+       /* STATE_EXIT2_IR         */ TMS_T(STATE_UPDATE_IR,        STATE_SHIFT_IR),
+       /* STATE_UPDATE_IR        */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
+};
+
+#define BITSTR(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ( \
+       ((uint16_t)(A) << 15) | \
+       ((uint16_t)(B) << 14) | \
+       ((uint16_t)(C) << 13) | \
+       ((uint16_t)(D) << 12) | \
+       ((uint16_t)(E) << 11) | \
+       ((uint16_t)(F) << 10) | \
+       ((uint16_t)(G) <<  9) | \
+       ((uint16_t)(H) <<  8) | \
+       ((uint16_t)(I) <<  7) | \
+       ((uint16_t)(J) <<  6) | \
+       ((uint16_t)(K) <<  5) | \
+       ((uint16_t)(L) <<  4) | \
+       ((uint16_t)(M) <<  3) | \
+       ((uint16_t)(N) <<  2) | \
+       ((uint16_t)(O) <<  1) | \
+       ((uint16_t)(P) <<  0) )
+
+/*
+ * The index of this vector is the current state. The i-th bit tells you the
+ * value TMS must assume in order to go to state "i".
+
+------------------------------------------------------------------------------------------------------------
+|                        |   || F | E | D | C || B | A | 9 | 8 || 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 ||   HEX  |
+------------------------------------------------------------------------------------------------------------
+| STATE_TEST_LOGIC_RESET | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 1 || 0x0001 |
+| STATE_RUN_TEST_IDLE    | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFFFD |
+| STATE_SELECT_DR_SCAN   | 2 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 0 | 0 | 0 | 0 || 0 | x | 1 | 1 || 0xFE03 |
+| STATE_CAPTURE_DR       | 3 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || x | 1 | 1 | 1 || 0xFFE7 |
+| STATE_SHIFT_DR         | 4 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 1 | 1 | 1 | 1 || 0xFFEF |
+| STATE_EXIT1_DR         | 5 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0 | 0 | x | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
+| STATE_PAUSE_DR         | 6 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 0 | 1 | 1 || 1 | 1 | 1 | 1 || 0xFFBF |
+| STATE_EXIT2_DR         | 7 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || x | 0 | 0 | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
+| STATE_UPDATE_DR        | 8 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | x || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFEFD |
+| STATE_SELECT_IR_SCAN   | 9 || 0 | 0 | 0 | 0 || 0 | 0 | x | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x01FF |
+| STATE_CAPTURE_IR       | A || 1 | 1 | 1 | 1 || 0 | x | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF3FF |
+| STATE_SHIFT_IR         | B || 1 | 1 | 1 | 1 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF7FF |
+| STATE_EXIT1_IR         | C || 1 | 0 | 0 | x || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
+| STATE_PAUSE_IR         | D || 1 | 1 | 0 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xDFFF |
+| STATE_EXIT2_IR         | E || 1 | x | 0 | 0 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
+| STATE_UPDATE_IR        | F || x | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0x7FFD |
+------------------------------------------------------------------------------------------------------------
+
+*/
+static const uint16_t tms_map[] = {
+/* STATE_TEST_LOGIC_RESET */ BITSTR(  0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 1  ),
+/* STATE_RUN_TEST_IDLE    */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 0, 1  ),
+/* STATE_SELECT_DR_SCAN   */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 0,   0, 0, 0, 0,   0, 0, 1, 1  ),
+/* STATE_CAPTURE_DR       */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 0,   0, 1, 1, 1  ),
+/* STATE_SHIFT_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 0,   1, 1, 1, 1  ),
+/* STATE_EXIT1_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 1  ),
+/* STATE_PAUSE_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 0, 1, 1,   1, 1, 1, 1  ),
+/* STATE_EXIT2_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 1  ),
+/* STATE_UPDATE_DR        */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 0,   1, 1, 1, 1,   1, 1, 0, 1  ),
+/* STATE_SELECT_IR_SCAN   */ BITSTR(  0, 0, 0, 0,   0, 0, 0, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_CAPTURE_IR       */ BITSTR(  1, 1, 1, 1,   0, 0, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_SHIFT_IR         */ BITSTR(  1, 1, 1, 1,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_EXIT1_IR         */ BITSTR(  1, 0, 0, 0,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_PAUSE_IR         */ BITSTR(  1, 1, 0, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_EXIT2_IR         */ BITSTR(  1, 0, 0, 0,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
+/* STATE_UPDATE_IR        */ BITSTR(  0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 0, 1  ),
+};
+
+static uint8_t current_state;
+
+uint8_t jtag_current_state(void)
+{
+       return current_state;
+}
+
+void jtag_set_current_state(uint8_t state)
+{
+       current_state = state;
+}
+
+void jtag_error(int status){
+       mpsse_error(status);
+}
+
+void jtag_deinit(){
+       mpsse_close();
+}
+
+/**
+ * Performs any start-of-day tasks necessary to talk JTAG to our FPGA.
+ */
+void jtag_init(int ifnum, const char *devstr, bool slow_clock)
+{
+       mpsse_init(ifnum, devstr, slow_clock);
+
+       jtag_set_current_state(STATE_TEST_LOGIC_RESET);
+    jtag_go_to_state(STATE_TEST_LOGIC_RESET);
+}
+
+uint8_t data[32*1024];
+uint8_t* ptr;
+uint16_t rx_cnt;
+
+extern struct ftdi_context mpsse_ftdic;
+
+static inline void jtag_pulse_clock_and_read_tdo(bool tms, bool tdi)
+{
+    *ptr++ = MC_DATA_TMS | MC_DATA_IN | MC_DATA_LSB | MC_DATA_BITS;
+       *ptr++ =  0;        
+    *ptr++ = (tdi ? 0x80 : 0) | (tms ? 0x01 : 0);
+       rx_cnt++;
+}
+
+static void _jtag_tap_shift(
+       uint8_t *input_data,
+       uint8_t *output_data,
+       uint32_t data_bits,
+       bool must_end)
+{
+
+       //printf("_jtag_tap_shift(0x%08x,0x%08x,%u,%s);\n",input_data, output_data, data_bits, must_end ? "true" : "false");
+       uint32_t bit_count = data_bits;
+       uint32_t byte_count = (data_bits + 7) / 8;
+       rx_cnt = 0;
+       ptr = data;
+
+       for (uint32_t i = 0; i < byte_count; ++i) {
+               uint8_t byte_out = input_data[i];
+               for (int j = 0; j < 8 && bit_count-- > 0; ++j) {
+            bool tms = false;
+                       if (bit_count == 0 && must_end) {
+                tms = true;
+                               jtag_state_ack(1);
+                       }
+                       jtag_pulse_clock_and_read_tdo(tms, byte_out & 1);
+                       byte_out >>= 1;
+               }
+       }
+
+       mpsse_xfer(data, ptr-data, rx_cnt);
+       
+       /* Data out from the FTDI is actually from an internal shift register
+        * Instead of reconstructing the bitpattern, we can just take every 8th byte.*/
+       for(int i = 0; i < rx_cnt/8; i++)
+               output_data[i] = data[7+i*8];
+}
+
+#define MIN(a,b) (a < b) ? a : b
+
+void jtag_tap_shift(
+       uint8_t *input_data,
+       uint8_t *output_data,
+       uint32_t data_bits,
+       bool must_end)
+{
+       uint32_t data_bits_sent = 0;
+       while(data_bits_sent != data_bits){
+
+               uint32_t _data_bits = MIN(256, data_bits);
+               bool last = (data_bits_sent + _data_bits) == data_bits;
+
+               _jtag_tap_shift(
+                       input_data + data_bits_sent/8,
+                       output_data + data_bits_sent/8,
+                       _data_bits,
+                       last & must_end
+               );
+               data_bits_sent += _data_bits;
+       }
+}
+
+void jtag_state_ack(bool tms)
+{
+       if (tms) {
+               jtag_set_current_state((tms_transitions[jtag_current_state()] >> 4) & 0xf);
+       } else {
+               jtag_set_current_state(tms_transitions[jtag_current_state()] & 0xf);
+       }
+}
+
+void jtag_go_to_state(unsigned state)
+{
+
+       if (state == STATE_TEST_LOGIC_RESET) {
+               for (int i = 0; i < 5; ++i) {
+                       jtag_state_ack(true);
+               }
+
+               uint8_t data[3] = { 
+                       MC_DATA_TMS | MC_DATA_LSB | MC_DATA_BITS,
+                       5 - 1,
+                       0b11111
+               };
+               mpsse_xfer(data, 3, 0);
+               
+       } else {
+               while (jtag_current_state() != state) {
+                       uint8_t data[3] = {
+                               MC_DATA_TMS | MC_DATA_LSB | MC_DATA_ICN | MC_DATA_BITS,
+                               0,
+                               (tms_map[jtag_current_state()] >> state) & 1
+                       };
+
+                       jtag_state_ack((tms_map[jtag_current_state()] >> state) & 1);
+                       mpsse_xfer(data, 3, 0);
+               }
+       }
+}
+
+void jtag_wait_time(uint32_t microseconds)
+{
+       uint16_t bytes = microseconds / 8;
+       uint8_t remain = microseconds % 8;
+
+       uint8_t data[3] = {
+               MC_CLK_N8,
+               bytes & 0xFF,
+               (bytes >> 8) & 0xFF
+       };
+       mpsse_xfer(data, 3, 0);
+
+       if(remain){
+               data[0] = MC_CLK_N;
+               data[1] = remain;
+               mpsse_xfer(data, 2, 0);
+       }
+}
+
diff --git a/ecpprog/lattice_cmds.h b/ecpprog/lattice_cmds.h
new file mode 100644 (file)
index 0000000..5e42d6c
--- /dev/null
@@ -0,0 +1,65 @@
+
+#include <stdint.h>
+
+/* Not sure if all of these are applicable to the JTAG interface */
+enum lattice_cmd
+{
+       ISC_NOOP = 0xFF, /* 0 bits - Non-operation */
+       READ_ID = 0xE0, /* 24 bits - Read out the 32-bit IDCODE of the device */
+       USERCODE = 0xC0, /* 24 bits - Read 32-bit usercode */
+       LSC_READ_STATUS = 0x3C, /* 24 bits - Read out internal status */
+       LSC_CHECK_BUSY = 0xF0, /* 24 bits - Read 1 bit busy flag to check the command execution status */
+       LSC_REFRESH = 0x79, /* 24 bits - Equivalent to toggle PROGRAMN pin */
+       ISC_ENABLE = 0xC6, /* 24 bits - Enable the Offline configuration mode */
+       ISC_ENABLE_X = 0x74, /* 24 bits - Enable the Transparent configuration mode */
+       ISC_DISABLE = 0x26, /* 24 bits - Disable the configuration operation */
+       ISC_PROGRAM_USERCODE = 0xC2, /* 24 bits - Write the 32-bit new USERCODE data to USERCODE register */
+       ISC_ERASE = 0x0E, /* 24 bits - Bulk erase the memory array base on the access mode and array selection */
+       ISC_PROGRAM_DONE = 0x5E, /* 24 bits - Program the DONE bit if the device is in Configuration state. */
+       ISC_PROGRAM_SECURITY = 0xCE, /* 24 bits - Program the Security bit if the device is in Configuration state */
+       LSC_INIT_ADDRESS = 0x46, /* 24 bits - Initialize the Address Shift Register */
+       LSC_WRITE_ADDRESS = 0xB4, /* 24 bits - Write the 16 bit Address Register to move the address quickly */
+       LSC_BITSTREAM_BURST = 0x7A, /* 24 bits - Program the device the whole bitstream sent in as the command operand */
+       LSC_PROG_INCR_RTI = 0x82, /* 24 bits - Write configuration data to the configuration memory frame at current address and post increment the address, Byte 2~0 of the opcode indicate number of the frames included in the operand field */
+       LSC_PROG_INCR_ENC = 0xB6, /* 24 bits - Encrypt the configuration data then write */
+       LSC_PROG_INCR_CMP = 0xB8, /* 24 bits - Decompress the configuration data, then write */
+       LSC_PROG_INCR_CNE = 0xBA, /* 24 bits - Decompress and Encrypt the configuration data, then write */
+       LSC_VERIFY_INCR_RTI = 0x6A, /* 24 bits - Read back the configuration memory frame selected by the address register and post increment the address */
+       LSC_PROG_CTRL0 = 0x22, /* 24 bits - Modify the Control Register 0 */
+       LSC_READ_CTRL0 = 0x20, /* 24 bits - Read the Control Register 0 */
+       LSC_RESET_CRC = 0x3B, /* 24 bits - Reset 16-bit frame CRC register to 0x0000 */
+       LSC_READ_CRC = 0x60, /* 24 bits - Read 16-bit frame CRC register content */
+       LSC_PROG_SED_CRC = 0xA2, /* 24 bits - Program the calculated 32-bit CRC based on configuration bit values only into overall CRC register */
+       LSC_READ_SED_CRC = 0xA4, /* 24 bits - Read the 32-bit SED CRC */
+       LSC_PROG_PASSWORD = 0xF1, /* 24 bits - Program 64-bit password into the non-volatile memory (Efuse) */
+       LSC_READ_PASSWORD = 0xF2, /* 24 bits - Read out the 64-bit password before activated for verification */
+       LSC_SHIFT_PASSWORD = 0xBC, /* 24 bits - Shift in the password to unlock for re-configuration (necessary when password protection feature is active). */
+       LSC_PROG_CIPHER_KEY = 0xF3, /* 24 bits - Program the 128-bit cipher key into Efuse */
+       LSC_READ_CIPHER_KEY = 0xF4, /* 24 bits - Read out the 128-bit cipher key before activated for verification */
+       LSC_PROG_FEATURE = 0xE4, /* 24 bits - Program User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */
+       LSC_READ_FEATURE = 0xE7, /* 24 bits - Read User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */
+       LSC_PROG_FEABITS = 0xF8, /* 24 bits - Program User Feature Bits, such as CFG port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */
+       LSC_READ_FEABITS = 0xFB, /* 24 bits - Read User Feature Bits, such as CFH port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */
+       LSC_PROG_OTP = 0xF9, /* 24 bits - Program OTP bits, to set Memory Sectors One Time Programmable */
+       LSC_READ_OTP = 0xFA, /* 24 bits - Read OTP bits setting */
+};
+
+
+struct ecp_device_id {
+       const char* device_name;
+       uint32_t    device_id;
+};
+
+const struct ecp_device_id ecp_devices[] =
+{
+       {"LFE5U-12"   , 0x21111043 },
+       {"LFE5U-25"   , 0x41111043 },
+       {"LFE5U-45"   , 0x41112043 },
+       {"LFE5U-85"   , 0x41113043 },
+       {"LFE5UM-25"  , 0x01111043 },
+       {"LFE5UM-45"  , 0x01112043 },
+       {"LFE5UM-85"  , 0x01113043 },
+       {"LFE5UM5G-25", 0x81111043 },
+       {"LFE5UM5G-45", 0x81112043 },
+       {"LFE5UM5G-85", 0x81113043 }
+};
diff --git a/ecpprog/mpsse.c b/ecpprog/mpsse.c
new file mode 100644 (file)
index 0000000..5833c65
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ *  iceprog -- simple programming tool for FTDI-based Lattice iCE programmers
+ *
+ *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Piotr Esden-Tempski <piotr@esden.net>
+ *
+ *  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.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
+ */
+
+#define _GNU_SOURCE
+
+#include <ftdi.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "mpsse.h"
+
+// ---------------------------------------------------------
+// MPSSE / FTDI definitions
+// ---------------------------------------------------------
+
+/* FTDI bank pinout typically used for iCE dev boards
+ * BUS IO | Signal | Control
+ * -------+--------+--------------
+ * xDBUS0 |    SCK | MPSSE
+ * xDBUS1 |   MOSI | MPSSE
+ * xDBUS2 |   MISO | MPSSE
+ * xDBUS3 |     nc |
+ * xDBUS4 |     CS | GPIO
+ * xDBUS5 |     nc |
+ * xDBUS6 |  CDONE | GPIO
+ * xDBUS7 | CRESET | GPIO
+ */
+
+struct ftdi_context mpsse_ftdic;
+bool mpsse_ftdic_open = false;
+bool mpsse_ftdic_latency_set = false;
+unsigned char mpsse_ftdi_latency;
+
+
+// ---------------------------------------------------------
+// MPSSE / FTDI function implementations
+// ---------------------------------------------------------
+
+void mpsse_check_rx()
+{
+       uint8_t cnt = 0;
+       while (1) {
+               uint8_t data;
+               int rc = ftdi_read_data(&mpsse_ftdic, &data, 1);
+               if (rc <= 0)
+                       break;
+               fprintf(stderr, "unexpected rx byte: %02X\n", data);
+               cnt++;
+
+               if(cnt > 32)
+                       break;
+       }
+}
+
+void mpsse_error(int status)
+{
+       //mpsse_check_rx();
+       fprintf(stderr, "ABORT.\n");
+       if (mpsse_ftdic_open) {
+               if (mpsse_ftdic_latency_set)
+                       ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency);
+               ftdi_usb_close(&mpsse_ftdic);
+       }
+       ftdi_deinit(&mpsse_ftdic);
+       exit(status);
+}
+
+uint8_t mpsse_recv_byte()
+{
+       uint8_t data;
+       while (1) {
+               int rc = ftdi_read_data(&mpsse_ftdic, &data, 1);
+               if (rc < 0) {
+                       fprintf(stderr, "Read error.\n");
+                       mpsse_error(2);
+               }
+               if (rc == 1)
+                       break;
+               usleep(100);
+       }
+       return data;
+}
+
+void mpsse_send_byte(uint8_t data)
+{
+       int rc = ftdi_write_data(&mpsse_ftdic, &data, 1);
+       if (rc != 1) {
+               fprintf(stderr, "Write error (single byte, rc=%d, expected %d)(%s).\n", rc, 1, ftdi_get_error_string(&mpsse_ftdic));
+               mpsse_error(2);
+       }
+}
+
+void mpsse_purge(void){
+       int rc = ftdi_usb_purge_buffers(&mpsse_ftdic);
+       if (rc != 0) {
+               fprintf(stderr, "Purge error.\n");
+               mpsse_error(2);
+       }
+}
+
+void mpsse_xfer(uint8_t* data_buffer, uint16_t send_length, uint16_t receive_length)
+{
+       if(send_length){
+               int rc = ftdi_write_data(&mpsse_ftdic, data_buffer, send_length);
+               if (rc != send_length) {
+                       fprintf(stderr, "Write error (rc=%d, expected %d)[%s]\n", rc, 1, ftdi_get_error_string(&mpsse_ftdic));
+                       mpsse_error(2);
+               }
+       }
+
+       if(receive_length){
+               /* Calls to ftdi_read_data may return with less data than requested if it wasn't ready. 
+                * We stay in this while loop to collect all the data that we expect. */
+               uint16_t rx_len = 0;
+               while(rx_len != receive_length){
+                       int rc = ftdi_read_data(&mpsse_ftdic, data_buffer + rx_len, receive_length - rx_len);
+                       if (rc < 0) {
+                               fprintf(stderr, "Read error (rc=%d)[%s]\n", rc, ftdi_get_error_string(&mpsse_ftdic));
+                               mpsse_error(2);
+                       }else{
+                               rx_len += rc;
+                       }
+               }
+       }
+}
+
+void mpsse_init(int ifnum, const char *devstr, bool slow_clock)
+{
+       enum ftdi_interface ftdi_ifnum = INTERFACE_A;
+
+       switch (ifnum) {
+               case 0:
+                       ftdi_ifnum = INTERFACE_A;
+                       break;
+               case 1:
+                       ftdi_ifnum = INTERFACE_B;
+                       break;
+               case 2:
+                       ftdi_ifnum = INTERFACE_C;
+                       break;
+               case 3:
+                       ftdi_ifnum = INTERFACE_D;
+                       break;
+               default:
+                       ftdi_ifnum = INTERFACE_A;
+                       break;
+       }
+
+       ftdi_init(&mpsse_ftdic);
+       ftdi_set_interface(&mpsse_ftdic, ftdi_ifnum);
+
+       if (devstr != NULL) {
+               if (ftdi_usb_open_string(&mpsse_ftdic, devstr)) {
+                       fprintf(stderr, "Can't find iCE FTDI USB device (device string %s).\n", devstr);
+                       mpsse_error(2);
+               }
+       } else {
+               if (ftdi_usb_open(&mpsse_ftdic, 0x0403, 0x6010) && ftdi_usb_open(&mpsse_ftdic, 0x0403, 0x6014)) {
+                       fprintf(stderr, "Can't find iCE FTDI USB device (vendor_id 0x0403, device_id 0x6010 or 0x6014).\n");
+                       mpsse_error(2);
+               }
+       }
+
+       mpsse_ftdic_open = true;
+
+       if (ftdi_usb_reset(&mpsse_ftdic)) {
+               fprintf(stderr, "Failed to reset iCE FTDI USB device.\n");
+               mpsse_error(2);
+       }
+
+       if (ftdi_usb_purge_buffers(&mpsse_ftdic)) {
+               fprintf(stderr, "Failed to purge buffers on iCE FTDI USB device.\n");
+               mpsse_error(2);
+       }
+
+       if (ftdi_get_latency_timer(&mpsse_ftdic, &mpsse_ftdi_latency) < 0) {
+               fprintf(stderr, "Failed to get latency timer (%s).\n", ftdi_get_error_string(&mpsse_ftdic));
+               mpsse_error(2);
+       }
+
+       /* 1 is the fastest polling, it means 1 kHz polling */
+       if (ftdi_set_latency_timer(&mpsse_ftdic, 1) < 0) {
+               fprintf(stderr, "Failed to set latency timer (%s).\n", ftdi_get_error_string(&mpsse_ftdic));
+               mpsse_error(2);
+       }
+
+       mpsse_ftdic_latency_set = true;
+
+       /* Enter MPSSE (Multi-Protocol Synchronous Serial Engine) mode. Set all pins to output. */
+       if (ftdi_set_bitmode(&mpsse_ftdic, 0xff, BITMODE_MPSSE) < 0) {
+               fprintf(stderr, "Failed to set BITMODE_MPSSE on FTDI USB device.\n");
+               mpsse_error(2);
+       }
+
+       int rc = ftdi_usb_purge_buffers(&mpsse_ftdic);
+       if (rc != 0) {
+               fprintf(stderr, "Purge error.\n");
+               mpsse_error(2);
+       }
+
+       if (slow_clock) {
+               // set 50 kHz clock
+               mpsse_send_byte(MC_SET_CLK_DIV);
+               mpsse_send_byte(119);
+               mpsse_send_byte(0x00);
+       } else {
+               // set 6 MHz clock
+               mpsse_send_byte(MC_SET_CLK_DIV);
+               mpsse_send_byte(4);
+               mpsse_send_byte(0x00);
+       }
+
+       mpsse_send_byte(MC_SETB_LOW);
+       mpsse_send_byte(0x08); /* Value */
+       mpsse_send_byte(0x0B); /* Direction */
+}
+
+void mpsse_close(void)
+{
+       ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency);
+       ftdi_disable_bitbang(&mpsse_ftdic);
+       ftdi_usb_close(&mpsse_ftdic);
+       ftdi_deinit(&mpsse_ftdic);
+}
\ No newline at end of file
diff --git a/ecpprog/mpsse.h b/ecpprog/mpsse.h
new file mode 100644 (file)
index 0000000..e10601a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  iceprog -- simple programming tool for FTDI-based Lattice iCE programmers
+ *
+ *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Piotr Esden-Tempski <piotr@esden.net>
+ *
+ *  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.
+ */
+
+#ifndef MPSSE_H
+#define MPSSE_H
+
+#include <stdint.h>
+
+
+
+/* MPSSE engine command definitions */
+enum mpsse_cmd
+{
+       /* Mode commands */
+       MC_SETB_LOW = 0x80, /* Set Data bits LowByte */
+       MC_READB_LOW = 0x81, /* Read Data bits LowByte */
+       MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */
+       MC_READB_HIGH = 0x83, /* Read data bits HighByte */
+       MC_LOOPBACK_EN = 0x84, /* Enable loopback */
+       MC_LOOPBACK_DIS = 0x85, /* Disable loopback */
+       MC_SET_CLK_DIV = 0x86, /* Set clock divisor */
+       MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */
+       MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */
+       MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */
+       MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */
+       MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */
+       MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */
+       MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */
+       MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */
+       MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */
+       MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */
+       MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */
+       MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */
+       MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */
+       MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */
+       MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */
+       MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */
+       /* CPU mode commands */
+       MC_CPU_RS = 0x90, /* CPUMode read short address */
+       MC_CPU_RE = 0x91, /* CPUMode read extended address */
+       MC_CPU_WS = 0x92, /* CPUMode write short address */
+       MC_CPU_WE = 0x93, /* CPUMode write extended address */
+};
+
+
+/* Transfer Command bits */
+
+/* All byte based commands consist of:
+ * - Command byte
+ * - Length lsb
+ * - Length msb
+ *
+ * If data out is enabled the data follows after the above command bytes,
+ * otherwise no additional data is needed.
+ * - Data * n
+ *
+ * All bit based commands consist of:
+ * - Command byte
+ * - Length
+ *
+ * If data out is enabled a byte containing bitst to transfer follows.
+ * Otherwise no additional data is needed. Only up to 8 bits can be transferred
+ * per transaction when in bit mode.
+ */
+
+/* b 0000 0000
+ *   |||| |||`- Data out negative enable. Update DO on negative clock edge.
+ *   |||| ||`-- Bit count enable. When reset count represents bytes.
+ *   |||| |`--- Data in negative enable. Latch DI on negative clock edge.
+ *   |||| `---- LSB enable. When set clock data out LSB first.
+ *   ||||
+ *   |||`------ Data out enable
+ *   ||`------- Data in enable
+ *   |`-------- TMS mode enable
+ *   `--------- Special command mode enable. See mpsse_cmd enum.
+ */
+
+#define MC_DATA_TMS  (0x40) /* When set use TMS mode */
+#define MC_DATA_IN   (0x20) /* When set read data (Data IN) */
+#define MC_DATA_OUT  (0x10) /* When set write data (Data OUT) */
+#define MC_DATA_LSB  (0x08) /* When set input/output data LSB first. */
+#define MC_DATA_ICN  (0x04) /* When set receive data on negative clock edge */
+#define MC_DATA_BITS (0x02) /* When set count bits not bytes */
+#define MC_DATA_OCN  (0x01) /* When set update data on negative clock edge */
+
+
+void mpsse_check_rx(void);
+void mpsse_error(int status);
+uint8_t mpsse_recv_byte(void);
+void mpsse_xfer(uint8_t* data_buffer, uint16_t send_length, uint16_t receive_length);
+void mpsse_send_byte(uint8_t data);
+void mpsse_send_spi(uint8_t *data, int n);
+void mpsse_xfer_spi(uint8_t *data, int n);
+uint8_t mpsse_xfer_spi_bits(uint8_t data, int n);
+void mpsse_set_gpio(uint8_t gpio, uint8_t direction);
+int mpsse_readb_low(void);
+int mpsse_readb_high(void);
+void mpsse_send_dummy_bytes(uint8_t n);
+void mpsse_send_dummy_bit(void);
+void mpsse_init(int ifnum, const char *devstr, bool slow_clock);
+void mpsse_close(void);
+
+#endif /* MPSSE_H */
diff --git a/jtag.h b/jtag.h
deleted file mode 100644 (file)
index 51caa9d..0000000
--- a/jtag.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Code for interacting with the FPGA via JTAG.
- * This file is part of LUNA.
- *
- * This JTAG driver is intended to be as simple as possible in order to facilitate
- * configuration and debugging of the attached FPGA. It is not intended to be a general-
- * purpose JTAG link.
- */
-
-#ifndef __JTAG_H__
-#define __JTAG_H__
-
-typedef enum e_TAPState
-{
-       STATE_TEST_LOGIC_RESET =  0,
-       STATE_RUN_TEST_IDLE    =  1,
-       STATE_SELECT_DR_SCAN   =  2,
-       STATE_CAPTURE_DR       =  3,
-       STATE_SHIFT_DR         =  4,
-       STATE_EXIT1_DR         =  5,
-       STATE_PAUSE_DR         =  6,
-       STATE_EXIT2_DR         =  7,
-       STATE_UPDATE_DR        =  8,
-       STATE_SELECT_IR_SCAN   =  9, 
-       STATE_CAPTURE_IR       = 10,
-       STATE_SHIFT_IR         = 11,
-       STATE_EXIT1_IR         = 12,
-       STATE_PAUSE_IR         = 13,
-       STATE_EXIT2_IR         = 14,
-       STATE_UPDATE_IR        = 15
-} jtag_tap_state_t;
-
-
-/**
- * Performs the start-of-day tasks necessary to talk JTAG to our FPGA.
- */
-void jtag_init(int ifnum, const char *devstr, bool slow_clock);
-
-
-/**
- * De-inits the JTAG connection, so the JTAG chain. is no longer driven.
- */
-void jtag_deinit(void);
-
-
-/**
- * Moves to a given JTAG state.
- */
-void jtag_goto_state(int state);
-
-
-/**
- * Performs a raw TAP scan.
- */
-void jtag_tap_shift(
-       uint8_t *input_data,
-       uint8_t *output_data,
-       uint32_t data_bits,
-       bool must_end);
-
-void jtag_error(int status);
-
-void jtag_wait_time(uint32_t microseconds);
-
-void jtag_go_to_state(unsigned state);
-
-uint8_t jtag_current_state(void);
-
-#endif
diff --git a/jtag_tap.c b/jtag_tap.c
deleted file mode 100644 (file)
index 44781f5..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/**
- * Code adapted from Arduino-JTAG;
- *    portions copyright (c) 2015 Marcelo Roberto Jimenez <marcelo.jimenez (at) gmail (dot) com>.
- *    portions copyright (c) 2019 Katherine J. Temkin <kate@ktemkin.com>
- *    portions copyright (c) 2019 Great Scott Gadgets <ktemkin@greatscottgadgets.com>
- */
-
-#include <ftdi.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "mpsse.h"
-#include "jtag.h"
-
-void jtag_state_ack(bool tms);
-
-/*
- * Low nibble : TMS == 0
- * High nibble: TMS == 1
- */
-
-#define TMS_T(TMS_HIGH_STATE, TMS_LOW_STATE) (((TMS_HIGH_STATE) << 4) | (TMS_LOW_STATE))
-
-static const uint8_t tms_transitions[] = {
-       /* STATE_TEST_LOGIC_RESET */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_RUN_TEST_IDLE),
-       /* STATE_RUN_TEST_IDLE    */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
-       /* STATE_SELECT_DR_SCAN   */ TMS_T(STATE_SELECT_IR_SCAN,   STATE_CAPTURE_DR),
-       /* STATE_CAPTURE_DR       */ TMS_T(STATE_EXIT1_DR,         STATE_SHIFT_DR),
-       /* STATE_SHIFT_DR         */ TMS_T(STATE_EXIT1_DR,         STATE_SHIFT_DR),
-       /* STATE_EXIT1_DR         */ TMS_T(STATE_UPDATE_DR,        STATE_PAUSE_DR),
-       /* STATE_PAUSE_DR         */ TMS_T(STATE_EXIT2_DR,         STATE_PAUSE_DR),
-       /* STATE_EXIT2_DR         */ TMS_T(STATE_UPDATE_DR,        STATE_SHIFT_DR),
-       /* STATE_UPDATE_DR        */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
-       /* STATE_SELECT_IR_SCAN   */ TMS_T(STATE_TEST_LOGIC_RESET, STATE_CAPTURE_IR),
-       /* STATE_CAPTURE_IR       */ TMS_T(STATE_EXIT1_IR,         STATE_SHIFT_IR),
-       /* STATE_SHIFT_IR         */ TMS_T(STATE_EXIT1_IR,         STATE_SHIFT_IR),
-       /* STATE_EXIT1_IR         */ TMS_T(STATE_UPDATE_IR,        STATE_PAUSE_IR),
-       /* STATE_PAUSE_IR         */ TMS_T(STATE_EXIT2_IR,         STATE_PAUSE_IR),
-       /* STATE_EXIT2_IR         */ TMS_T(STATE_UPDATE_IR,        STATE_SHIFT_IR),
-       /* STATE_UPDATE_IR        */ TMS_T(STATE_SELECT_DR_SCAN,   STATE_RUN_TEST_IDLE),
-};
-
-#define BITSTR(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ( \
-       ((uint16_t)(A) << 15) | \
-       ((uint16_t)(B) << 14) | \
-       ((uint16_t)(C) << 13) | \
-       ((uint16_t)(D) << 12) | \
-       ((uint16_t)(E) << 11) | \
-       ((uint16_t)(F) << 10) | \
-       ((uint16_t)(G) <<  9) | \
-       ((uint16_t)(H) <<  8) | \
-       ((uint16_t)(I) <<  7) | \
-       ((uint16_t)(J) <<  6) | \
-       ((uint16_t)(K) <<  5) | \
-       ((uint16_t)(L) <<  4) | \
-       ((uint16_t)(M) <<  3) | \
-       ((uint16_t)(N) <<  2) | \
-       ((uint16_t)(O) <<  1) | \
-       ((uint16_t)(P) <<  0) )
-
-/*
- * The index of this vector is the current state. The i-th bit tells you the
- * value TMS must assume in order to go to state "i".
-
-------------------------------------------------------------------------------------------------------------
-|                        |   || F | E | D | C || B | A | 9 | 8 || 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 ||   HEX  |
-------------------------------------------------------------------------------------------------------------
-| STATE_TEST_LOGIC_RESET | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 1 || 0x0001 |
-| STATE_RUN_TEST_IDLE    | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFFFD |
-| STATE_SELECT_DR_SCAN   | 2 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 0 | 0 | 0 | 0 || 0 | x | 1 | 1 || 0xFE03 |
-| STATE_CAPTURE_DR       | 3 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || x | 1 | 1 | 1 || 0xFFE7 |
-| STATE_SHIFT_DR         | 4 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 1 | 1 | 1 | 1 || 0xFFEF |
-| STATE_EXIT1_DR         | 5 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0 | 0 | x | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
-| STATE_PAUSE_DR         | 6 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 0 | 1 | 1 || 1 | 1 | 1 | 1 || 0xFFBF |
-| STATE_EXIT2_DR         | 7 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || x | 0 | 0 | 0 || 1 | 1 | 1 | 1 || 0xFF0F |
-| STATE_UPDATE_DR        | 8 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | x || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFEFD |
-| STATE_SELECT_IR_SCAN   | 9 || 0 | 0 | 0 | 0 || 0 | 0 | x | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x01FF |
-| STATE_CAPTURE_IR       | A || 1 | 1 | 1 | 1 || 0 | x | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF3FF |
-| STATE_SHIFT_IR         | B || 1 | 1 | 1 | 1 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF7FF |
-| STATE_EXIT1_IR         | C || 1 | 0 | 0 | x || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
-| STATE_PAUSE_IR         | D || 1 | 1 | 0 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xDFFF |
-| STATE_EXIT2_IR         | E || 1 | x | 0 | 0 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF |
-| STATE_UPDATE_IR        | F || x | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0x7FFD |
-------------------------------------------------------------------------------------------------------------
-
-*/
-static const uint16_t tms_map[] = {
-/* STATE_TEST_LOGIC_RESET */ BITSTR(  0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 1  ),
-/* STATE_RUN_TEST_IDLE    */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 0, 1  ),
-/* STATE_SELECT_DR_SCAN   */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 0,   0, 0, 0, 0,   0, 0, 1, 1  ),
-/* STATE_CAPTURE_DR       */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 0,   0, 1, 1, 1  ),
-/* STATE_SHIFT_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 0,   1, 1, 1, 1  ),
-/* STATE_EXIT1_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 1  ),
-/* STATE_PAUSE_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   1, 0, 1, 1,   1, 1, 1, 1  ),
-/* STATE_EXIT2_DR         */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 1  ),
-/* STATE_UPDATE_DR        */ BITSTR(  1, 1, 1, 1,   1, 1, 1, 0,   1, 1, 1, 1,   1, 1, 0, 1  ),
-/* STATE_SELECT_IR_SCAN   */ BITSTR(  0, 0, 0, 0,   0, 0, 0, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_CAPTURE_IR       */ BITSTR(  1, 1, 1, 1,   0, 0, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_SHIFT_IR         */ BITSTR(  1, 1, 1, 1,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_EXIT1_IR         */ BITSTR(  1, 0, 0, 0,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_PAUSE_IR         */ BITSTR(  1, 1, 0, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_EXIT2_IR         */ BITSTR(  1, 0, 0, 0,   0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1  ),
-/* STATE_UPDATE_IR        */ BITSTR(  0, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 0, 1  ),
-};
-
-static uint8_t current_state;
-
-uint8_t jtag_current_state(void)
-{
-       return current_state;
-}
-
-void jtag_set_current_state(uint8_t state)
-{
-       current_state = state;
-}
-
-void jtag_error(int status){
-       mpsse_error(status);
-}
-
-void jtag_deinit(){
-       mpsse_close();
-}
-
-/**
- * Performs any start-of-day tasks necessary to talk JTAG to our FPGA.
- */
-void jtag_init(int ifnum, const char *devstr, bool slow_clock)
-{
-       mpsse_init(ifnum, devstr, slow_clock);
-
-       jtag_set_current_state(STATE_TEST_LOGIC_RESET);
-    jtag_go_to_state(STATE_TEST_LOGIC_RESET);
-}
-
-uint8_t data[32*1024];
-uint8_t* ptr;
-uint16_t rx_cnt;
-
-extern struct ftdi_context mpsse_ftdic;
-
-static inline void jtag_pulse_clock_and_read_tdo(bool tms, bool tdi)
-{
-    *ptr++ = MC_DATA_TMS | MC_DATA_IN | MC_DATA_LSB | MC_DATA_BITS;
-       *ptr++ =  0;        
-    *ptr++ = (tdi ? 0x80 : 0) | (tms ? 0x01 : 0);
-       rx_cnt++;
-}
-
-static void _jtag_tap_shift(
-       uint8_t *input_data,
-       uint8_t *output_data,
-       uint32_t data_bits,
-       bool must_end)
-{
-
-       //printf("_jtag_tap_shift(0x%08x,0x%08x,%u,%s);\n",input_data, output_data, data_bits, must_end ? "true" : "false");
-       uint32_t bit_count = data_bits;
-       uint32_t byte_count = (data_bits + 7) / 8;
-       rx_cnt = 0;
-       ptr = data;
-
-       for (uint32_t i = 0; i < byte_count; ++i) {
-               uint8_t byte_out = input_data[i];
-               for (int j = 0; j < 8 && bit_count-- > 0; ++j) {
-            bool tms = false;
-                       if (bit_count == 0 && must_end) {
-                tms = true;
-                               jtag_state_ack(1);
-                       }
-                       jtag_pulse_clock_and_read_tdo(tms, byte_out & 1);
-                       byte_out >>= 1;
-               }
-       }
-
-       mpsse_xfer(data, ptr-data, rx_cnt);
-       
-       /* Data out from the FTDI is actually from an internal shift register
-        * Instead of reconstructing the bitpattern, we can just take every 8th byte.*/
-       for(int i = 0; i < rx_cnt/8; i++)
-               output_data[i] = data[7+i*8];
-}
-
-#define MIN(a,b) (a < b) ? a : b
-
-void jtag_tap_shift(
-       uint8_t *input_data,
-       uint8_t *output_data,
-       uint32_t data_bits,
-       bool must_end)
-{
-       uint32_t data_bits_sent = 0;
-       while(data_bits_sent != data_bits){
-
-               uint32_t _data_bits = MIN(256, data_bits);
-               bool last = (data_bits_sent + _data_bits) == data_bits;
-
-               _jtag_tap_shift(
-                       input_data + data_bits_sent/8,
-                       output_data + data_bits_sent/8,
-                       _data_bits,
-                       last & must_end
-               );
-               data_bits_sent += _data_bits;
-       }
-}
-
-void jtag_state_ack(bool tms)
-{
-       if (tms) {
-               jtag_set_current_state((tms_transitions[jtag_current_state()] >> 4) & 0xf);
-       } else {
-               jtag_set_current_state(tms_transitions[jtag_current_state()] & 0xf);
-       }
-}
-
-void jtag_go_to_state(unsigned state)
-{
-
-       if (state == STATE_TEST_LOGIC_RESET) {
-               for (int i = 0; i < 5; ++i) {
-                       jtag_state_ack(true);
-               }
-
-               uint8_t data[3] = { 
-                       MC_DATA_TMS | MC_DATA_LSB | MC_DATA_BITS,
-                       5 - 1,
-                       0b11111
-               };
-               mpsse_xfer(data, 3, 0);
-               
-       } else {
-               while (jtag_current_state() != state) {
-                       uint8_t data[3] = {
-                               MC_DATA_TMS | MC_DATA_LSB | MC_DATA_ICN | MC_DATA_BITS,
-                               0,
-                               (tms_map[jtag_current_state()] >> state) & 1
-                       };
-
-                       jtag_state_ack((tms_map[jtag_current_state()] >> state) & 1);
-                       mpsse_xfer(data, 3, 0);
-               }
-       }
-}
-
-void jtag_wait_time(uint32_t microseconds)
-{
-       uint16_t bytes = microseconds / 8;
-       uint8_t remain = microseconds % 8;
-
-       uint8_t data[3] = {
-               MC_CLK_N8,
-               bytes & 0xFF,
-               (bytes >> 8) & 0xFF
-       };
-       mpsse_xfer(data, 3, 0);
-
-       if(remain){
-               data[0] = MC_CLK_N;
-               data[1] = remain;
-               mpsse_xfer(data, 2, 0);
-       }
-}
-
diff --git a/lattice_cmds.h b/lattice_cmds.h
deleted file mode 100644 (file)
index 5e42d6c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-
-#include <stdint.h>
-
-/* Not sure if all of these are applicable to the JTAG interface */
-enum lattice_cmd
-{
-       ISC_NOOP = 0xFF, /* 0 bits - Non-operation */
-       READ_ID = 0xE0, /* 24 bits - Read out the 32-bit IDCODE of the device */
-       USERCODE = 0xC0, /* 24 bits - Read 32-bit usercode */
-       LSC_READ_STATUS = 0x3C, /* 24 bits - Read out internal status */
-       LSC_CHECK_BUSY = 0xF0, /* 24 bits - Read 1 bit busy flag to check the command execution status */
-       LSC_REFRESH = 0x79, /* 24 bits - Equivalent to toggle PROGRAMN pin */
-       ISC_ENABLE = 0xC6, /* 24 bits - Enable the Offline configuration mode */
-       ISC_ENABLE_X = 0x74, /* 24 bits - Enable the Transparent configuration mode */
-       ISC_DISABLE = 0x26, /* 24 bits - Disable the configuration operation */
-       ISC_PROGRAM_USERCODE = 0xC2, /* 24 bits - Write the 32-bit new USERCODE data to USERCODE register */
-       ISC_ERASE = 0x0E, /* 24 bits - Bulk erase the memory array base on the access mode and array selection */
-       ISC_PROGRAM_DONE = 0x5E, /* 24 bits - Program the DONE bit if the device is in Configuration state. */
-       ISC_PROGRAM_SECURITY = 0xCE, /* 24 bits - Program the Security bit if the device is in Configuration state */
-       LSC_INIT_ADDRESS = 0x46, /* 24 bits - Initialize the Address Shift Register */
-       LSC_WRITE_ADDRESS = 0xB4, /* 24 bits - Write the 16 bit Address Register to move the address quickly */
-       LSC_BITSTREAM_BURST = 0x7A, /* 24 bits - Program the device the whole bitstream sent in as the command operand */
-       LSC_PROG_INCR_RTI = 0x82, /* 24 bits - Write configuration data to the configuration memory frame at current address and post increment the address, Byte 2~0 of the opcode indicate number of the frames included in the operand field */
-       LSC_PROG_INCR_ENC = 0xB6, /* 24 bits - Encrypt the configuration data then write */
-       LSC_PROG_INCR_CMP = 0xB8, /* 24 bits - Decompress the configuration data, then write */
-       LSC_PROG_INCR_CNE = 0xBA, /* 24 bits - Decompress and Encrypt the configuration data, then write */
-       LSC_VERIFY_INCR_RTI = 0x6A, /* 24 bits - Read back the configuration memory frame selected by the address register and post increment the address */
-       LSC_PROG_CTRL0 = 0x22, /* 24 bits - Modify the Control Register 0 */
-       LSC_READ_CTRL0 = 0x20, /* 24 bits - Read the Control Register 0 */
-       LSC_RESET_CRC = 0x3B, /* 24 bits - Reset 16-bit frame CRC register to 0x0000 */
-       LSC_READ_CRC = 0x60, /* 24 bits - Read 16-bit frame CRC register content */
-       LSC_PROG_SED_CRC = 0xA2, /* 24 bits - Program the calculated 32-bit CRC based on configuration bit values only into overall CRC register */
-       LSC_READ_SED_CRC = 0xA4, /* 24 bits - Read the 32-bit SED CRC */
-       LSC_PROG_PASSWORD = 0xF1, /* 24 bits - Program 64-bit password into the non-volatile memory (Efuse) */
-       LSC_READ_PASSWORD = 0xF2, /* 24 bits - Read out the 64-bit password before activated for verification */
-       LSC_SHIFT_PASSWORD = 0xBC, /* 24 bits - Shift in the password to unlock for re-configuration (necessary when password protection feature is active). */
-       LSC_PROG_CIPHER_KEY = 0xF3, /* 24 bits - Program the 128-bit cipher key into Efuse */
-       LSC_READ_CIPHER_KEY = 0xF4, /* 24 bits - Read out the 128-bit cipher key before activated for verification */
-       LSC_PROG_FEATURE = 0xE4, /* 24 bits - Program User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */
-       LSC_READ_FEATURE = 0xE7, /* 24 bits - Read User Feature, such as Customer ID, I2C Slave Address, Unique ID Header */
-       LSC_PROG_FEABITS = 0xF8, /* 24 bits - Program User Feature Bits, such as CFG port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */
-       LSC_READ_FEABITS = 0xFB, /* 24 bits - Read User Feature Bits, such as CFH port and pin persistence, PWD_EN, PWD_ALL, DEC_ONLY, Feature Row Lock etc. */
-       LSC_PROG_OTP = 0xF9, /* 24 bits - Program OTP bits, to set Memory Sectors One Time Programmable */
-       LSC_READ_OTP = 0xFA, /* 24 bits - Read OTP bits setting */
-};
-
-
-struct ecp_device_id {
-       const char* device_name;
-       uint32_t    device_id;
-};
-
-const struct ecp_device_id ecp_devices[] =
-{
-       {"LFE5U-12"   , 0x21111043 },
-       {"LFE5U-25"   , 0x41111043 },
-       {"LFE5U-45"   , 0x41112043 },
-       {"LFE5U-85"   , 0x41113043 },
-       {"LFE5UM-25"  , 0x01111043 },
-       {"LFE5UM-45"  , 0x01112043 },
-       {"LFE5UM-85"  , 0x01113043 },
-       {"LFE5UM5G-25", 0x81111043 },
-       {"LFE5UM5G-45", 0x81112043 },
-       {"LFE5UM5G-85", 0x81113043 }
-};
diff --git a/mpsse.c b/mpsse.c
deleted file mode 100644 (file)
index 5833c65..0000000
--- a/mpsse.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- *  iceprog -- simple programming tool for FTDI-based Lattice iCE programmers
- *
- *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
- *  Copyright (C) 2018  Piotr Esden-Tempski <piotr@esden.net>
- *
- *  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.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
- */
-
-#define _GNU_SOURCE
-
-#include <ftdi.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "mpsse.h"
-
-// ---------------------------------------------------------
-// MPSSE / FTDI definitions
-// ---------------------------------------------------------
-
-/* FTDI bank pinout typically used for iCE dev boards
- * BUS IO | Signal | Control
- * -------+--------+--------------
- * xDBUS0 |    SCK | MPSSE
- * xDBUS1 |   MOSI | MPSSE
- * xDBUS2 |   MISO | MPSSE
- * xDBUS3 |     nc |
- * xDBUS4 |     CS | GPIO
- * xDBUS5 |     nc |
- * xDBUS6 |  CDONE | GPIO
- * xDBUS7 | CRESET | GPIO
- */
-
-struct ftdi_context mpsse_ftdic;
-bool mpsse_ftdic_open = false;
-bool mpsse_ftdic_latency_set = false;
-unsigned char mpsse_ftdi_latency;
-
-
-// ---------------------------------------------------------
-// MPSSE / FTDI function implementations
-// ---------------------------------------------------------
-
-void mpsse_check_rx()
-{
-       uint8_t cnt = 0;
-       while (1) {
-               uint8_t data;
-               int rc = ftdi_read_data(&mpsse_ftdic, &data, 1);
-               if (rc <= 0)
-                       break;
-               fprintf(stderr, "unexpected rx byte: %02X\n", data);
-               cnt++;
-
-               if(cnt > 32)
-                       break;
-       }
-}
-
-void mpsse_error(int status)
-{
-       //mpsse_check_rx();
-       fprintf(stderr, "ABORT.\n");
-       if (mpsse_ftdic_open) {
-               if (mpsse_ftdic_latency_set)
-                       ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency);
-               ftdi_usb_close(&mpsse_ftdic);
-       }
-       ftdi_deinit(&mpsse_ftdic);
-       exit(status);
-}
-
-uint8_t mpsse_recv_byte()
-{
-       uint8_t data;
-       while (1) {
-               int rc = ftdi_read_data(&mpsse_ftdic, &data, 1);
-               if (rc < 0) {
-                       fprintf(stderr, "Read error.\n");
-                       mpsse_error(2);
-               }
-               if (rc == 1)
-                       break;
-               usleep(100);
-       }
-       return data;
-}
-
-void mpsse_send_byte(uint8_t data)
-{
-       int rc = ftdi_write_data(&mpsse_ftdic, &data, 1);
-       if (rc != 1) {
-               fprintf(stderr, "Write error (single byte, rc=%d, expected %d)(%s).\n", rc, 1, ftdi_get_error_string(&mpsse_ftdic));
-               mpsse_error(2);
-       }
-}
-
-void mpsse_purge(void){
-       int rc = ftdi_usb_purge_buffers(&mpsse_ftdic);
-       if (rc != 0) {
-               fprintf(stderr, "Purge error.\n");
-               mpsse_error(2);
-       }
-}
-
-void mpsse_xfer(uint8_t* data_buffer, uint16_t send_length, uint16_t receive_length)
-{
-       if(send_length){
-               int rc = ftdi_write_data(&mpsse_ftdic, data_buffer, send_length);
-               if (rc != send_length) {
-                       fprintf(stderr, "Write error (rc=%d, expected %d)[%s]\n", rc, 1, ftdi_get_error_string(&mpsse_ftdic));
-                       mpsse_error(2);
-               }
-       }
-
-       if(receive_length){
-               /* Calls to ftdi_read_data may return with less data than requested if it wasn't ready. 
-                * We stay in this while loop to collect all the data that we expect. */
-               uint16_t rx_len = 0;
-               while(rx_len != receive_length){
-                       int rc = ftdi_read_data(&mpsse_ftdic, data_buffer + rx_len, receive_length - rx_len);
-                       if (rc < 0) {
-                               fprintf(stderr, "Read error (rc=%d)[%s]\n", rc, ftdi_get_error_string(&mpsse_ftdic));
-                               mpsse_error(2);
-                       }else{
-                               rx_len += rc;
-                       }
-               }
-       }
-}
-
-void mpsse_init(int ifnum, const char *devstr, bool slow_clock)
-{
-       enum ftdi_interface ftdi_ifnum = INTERFACE_A;
-
-       switch (ifnum) {
-               case 0:
-                       ftdi_ifnum = INTERFACE_A;
-                       break;
-               case 1:
-                       ftdi_ifnum = INTERFACE_B;
-                       break;
-               case 2:
-                       ftdi_ifnum = INTERFACE_C;
-                       break;
-               case 3:
-                       ftdi_ifnum = INTERFACE_D;
-                       break;
-               default:
-                       ftdi_ifnum = INTERFACE_A;
-                       break;
-       }
-
-       ftdi_init(&mpsse_ftdic);
-       ftdi_set_interface(&mpsse_ftdic, ftdi_ifnum);
-
-       if (devstr != NULL) {
-               if (ftdi_usb_open_string(&mpsse_ftdic, devstr)) {
-                       fprintf(stderr, "Can't find iCE FTDI USB device (device string %s).\n", devstr);
-                       mpsse_error(2);
-               }
-       } else {
-               if (ftdi_usb_open(&mpsse_ftdic, 0x0403, 0x6010) && ftdi_usb_open(&mpsse_ftdic, 0x0403, 0x6014)) {
-                       fprintf(stderr, "Can't find iCE FTDI USB device (vendor_id 0x0403, device_id 0x6010 or 0x6014).\n");
-                       mpsse_error(2);
-               }
-       }
-
-       mpsse_ftdic_open = true;
-
-       if (ftdi_usb_reset(&mpsse_ftdic)) {
-               fprintf(stderr, "Failed to reset iCE FTDI USB device.\n");
-               mpsse_error(2);
-       }
-
-       if (ftdi_usb_purge_buffers(&mpsse_ftdic)) {
-               fprintf(stderr, "Failed to purge buffers on iCE FTDI USB device.\n");
-               mpsse_error(2);
-       }
-
-       if (ftdi_get_latency_timer(&mpsse_ftdic, &mpsse_ftdi_latency) < 0) {
-               fprintf(stderr, "Failed to get latency timer (%s).\n", ftdi_get_error_string(&mpsse_ftdic));
-               mpsse_error(2);
-       }
-
-       /* 1 is the fastest polling, it means 1 kHz polling */
-       if (ftdi_set_latency_timer(&mpsse_ftdic, 1) < 0) {
-               fprintf(stderr, "Failed to set latency timer (%s).\n", ftdi_get_error_string(&mpsse_ftdic));
-               mpsse_error(2);
-       }
-
-       mpsse_ftdic_latency_set = true;
-
-       /* Enter MPSSE (Multi-Protocol Synchronous Serial Engine) mode. Set all pins to output. */
-       if (ftdi_set_bitmode(&mpsse_ftdic, 0xff, BITMODE_MPSSE) < 0) {
-               fprintf(stderr, "Failed to set BITMODE_MPSSE on FTDI USB device.\n");
-               mpsse_error(2);
-       }
-
-       int rc = ftdi_usb_purge_buffers(&mpsse_ftdic);
-       if (rc != 0) {
-               fprintf(stderr, "Purge error.\n");
-               mpsse_error(2);
-       }
-
-       if (slow_clock) {
-               // set 50 kHz clock
-               mpsse_send_byte(MC_SET_CLK_DIV);
-               mpsse_send_byte(119);
-               mpsse_send_byte(0x00);
-       } else {
-               // set 6 MHz clock
-               mpsse_send_byte(MC_SET_CLK_DIV);
-               mpsse_send_byte(4);
-               mpsse_send_byte(0x00);
-       }
-
-       mpsse_send_byte(MC_SETB_LOW);
-       mpsse_send_byte(0x08); /* Value */
-       mpsse_send_byte(0x0B); /* Direction */
-}
-
-void mpsse_close(void)
-{
-       ftdi_set_latency_timer(&mpsse_ftdic, mpsse_ftdi_latency);
-       ftdi_disable_bitbang(&mpsse_ftdic);
-       ftdi_usb_close(&mpsse_ftdic);
-       ftdi_deinit(&mpsse_ftdic);
-}
\ No newline at end of file
diff --git a/mpsse.h b/mpsse.h
deleted file mode 100644 (file)
index e10601a..0000000
--- a/mpsse.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *  iceprog -- simple programming tool for FTDI-based Lattice iCE programmers
- *
- *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
- *  Copyright (C) 2018  Piotr Esden-Tempski <piotr@esden.net>
- *
- *  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.
- */
-
-#ifndef MPSSE_H
-#define MPSSE_H
-
-#include <stdint.h>
-
-
-
-/* MPSSE engine command definitions */
-enum mpsse_cmd
-{
-       /* Mode commands */
-       MC_SETB_LOW = 0x80, /* Set Data bits LowByte */
-       MC_READB_LOW = 0x81, /* Read Data bits LowByte */
-       MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */
-       MC_READB_HIGH = 0x83, /* Read data bits HighByte */
-       MC_LOOPBACK_EN = 0x84, /* Enable loopback */
-       MC_LOOPBACK_DIS = 0x85, /* Disable loopback */
-       MC_SET_CLK_DIV = 0x86, /* Set clock divisor */
-       MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */
-       MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */
-       MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */
-       MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */
-       MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */
-       MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */
-       MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */
-       MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */
-       MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */
-       MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */
-       MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */
-       MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */
-       MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */
-       MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */
-       MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */
-       MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */
-       /* CPU mode commands */
-       MC_CPU_RS = 0x90, /* CPUMode read short address */
-       MC_CPU_RE = 0x91, /* CPUMode read extended address */
-       MC_CPU_WS = 0x92, /* CPUMode write short address */
-       MC_CPU_WE = 0x93, /* CPUMode write extended address */
-};
-
-
-/* Transfer Command bits */
-
-/* All byte based commands consist of:
- * - Command byte
- * - Length lsb
- * - Length msb
- *
- * If data out is enabled the data follows after the above command bytes,
- * otherwise no additional data is needed.
- * - Data * n
- *
- * All bit based commands consist of:
- * - Command byte
- * - Length
- *
- * If data out is enabled a byte containing bitst to transfer follows.
- * Otherwise no additional data is needed. Only up to 8 bits can be transferred
- * per transaction when in bit mode.
- */
-
-/* b 0000 0000
- *   |||| |||`- Data out negative enable. Update DO on negative clock edge.
- *   |||| ||`-- Bit count enable. When reset count represents bytes.
- *   |||| |`--- Data in negative enable. Latch DI on negative clock edge.
- *   |||| `---- LSB enable. When set clock data out LSB first.
- *   ||||
- *   |||`------ Data out enable
- *   ||`------- Data in enable
- *   |`-------- TMS mode enable
- *   `--------- Special command mode enable. See mpsse_cmd enum.
- */
-
-#define MC_DATA_TMS  (0x40) /* When set use TMS mode */
-#define MC_DATA_IN   (0x20) /* When set read data (Data IN) */
-#define MC_DATA_OUT  (0x10) /* When set write data (Data OUT) */
-#define MC_DATA_LSB  (0x08) /* When set input/output data LSB first. */
-#define MC_DATA_ICN  (0x04) /* When set receive data on negative clock edge */
-#define MC_DATA_BITS (0x02) /* When set count bits not bytes */
-#define MC_DATA_OCN  (0x01) /* When set update data on negative clock edge */
-
-
-void mpsse_check_rx(void);
-void mpsse_error(int status);
-uint8_t mpsse_recv_byte(void);
-void mpsse_xfer(uint8_t* data_buffer, uint16_t send_length, uint16_t receive_length);
-void mpsse_send_byte(uint8_t data);
-void mpsse_send_spi(uint8_t *data, int n);
-void mpsse_xfer_spi(uint8_t *data, int n);
-uint8_t mpsse_xfer_spi_bits(uint8_t data, int n);
-void mpsse_set_gpio(uint8_t gpio, uint8_t direction);
-int mpsse_readb_low(void);
-int mpsse_readb_high(void);
-void mpsse_send_dummy_bytes(uint8_t n);
-void mpsse_send_dummy_bit(void);
-void mpsse_init(int ifnum, const char *devstr, bool slow_clock);
-void mpsse_close(void);
-
-#endif /* MPSSE_H */