aboutsummaryrefslogtreecommitdiffstats
path: root/iceprog
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2017-07-05 18:26:33 +0200
committerGitHub <noreply@github.com>2017-07-05 18:26:33 +0200
commit82f9fdb57598e652f73f5508eb0ea1544ce8c49f (patch)
tree084a6538bbe973154ebc8e0461be9c891a520848 /iceprog
parent832bcbe4a2a2733cd76d70805390cee55524b0bc (diff)
parent53a8bcce3532bd93b2cbb54a83767df34a28a907 (diff)
downloadicestorm-82f9fdb57598e652f73f5508eb0ea1544ce8c49f.tar.gz
icestorm-82f9fdb57598e652f73f5508eb0ea1544ce8c49f.tar.bz2
icestorm-82f9fdb57598e652f73f5508eb0ea1544ce8c49f.zip
Merge pull request #82 from rlutz/master
`iceprog' improvements, documentation fixes
Diffstat (limited to 'iceprog')
-rw-r--r--iceprog/Makefile3
-rw-r--r--iceprog/iceprog.1155
-rw-r--r--iceprog/iceprog.c523
3 files changed, 469 insertions, 212 deletions
diff --git a/iceprog/Makefile b/iceprog/Makefile
index 286460f..c61b470 100644
--- a/iceprog/Makefile
+++ b/iceprog/Makefile
@@ -24,9 +24,12 @@ iceprog$(EXE): iceprog.o
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp iceprog $(DESTDIR)$(PREFIX)/bin/iceprog
+ mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1
+ install -c -m 644 iceprog.1 $(DESTDIR)$(PREFIX)/share/man/man1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/iceprog
+ rm -f $(DESTDIR)$(PREFIX)/share/man/man1/iceprog.1
clean:
rm -f iceprog
diff --git a/iceprog/iceprog.1 b/iceprog/iceprog.1
new file mode 100644
index 0000000..22d3882
--- /dev/null
+++ b/iceprog/iceprog.1
@@ -0,0 +1,155 @@
+.\" Manpage for iceprog(1)
+.\" Copyright (C) 2017 Roland Lutz
+.\"
+.\" Permission is granted to copy, distribute and/or modify this document
+.\" under the terms of the GNU Free Documentation License, Version 1.3 or
+.\" any later version published by the Free Software Foundation; with no
+.\" Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+.\"
+.TH ICEPROG "1" "June 2017" "IceStorm" "User Commands"
+.SH NAME
+iceprog \- simple programming tool for FTDI\-based Lattice iCE programmers
+.SH SYNOPSIS
+.B iceprog
+[\-b|\-n|\-c] \fIINPUT\-FILE\fR
+
+.B iceprog
+\-r|\-R\fI\,BYTES\fR \fIOUTPUT\-FILE\fR
+
+.B iceprog
+\-S \fIINPUT\-FILE\fR
+
+.B iceprog
+\-t
+.SH DESCRIPTION
+The \fBiceprog\fR program is a simple programming tool for FTDI\-based
+Lattice iCE programmers which can read, write and erase the flash and
+write the SRAM of an FPGA. It is typically invoked after the
+bitstream has been converted by \fBicepack\fR to the iCE40 \fB.bin\fR
+format as the last step of the build process to transfer the bitstream
+to the FPGA.
+.SS Operation mode
+When no special option is given, \fBiceprog\fR erases all 64kB sectors
+which would be touched by the written data, writes the data to the
+flash, and then reads it back and verifies it.
+
+\fIPlease note:\fR If the data is not aligned to 64kB, some data
+before (if \fB\-o\fR is used) and after the written data may be erased
+as well.
+
+The way the flash is erased can be changed with the following options:
+.TP
+\fB\-b\fR
+Bulk erase the entire flash before writing. When using this option,
+\fBiceprog\fR can be invoked without an \fIINPUT\-FILE\fR; in this
+case, the flash is just bulk erased, and nothing is written.
+.TP
+\fB\-n\fR
+Don't erase the flash before writing.
+.PP
+Instead of the default erase/write/verify, \fBiceprog\fR can perform
+some other operations:
+.TP
+\fB\-c\fR
+Just read the data which would have been written from the flash and
+verify it (`check').
+.TP
+\fB\-r\fR
+Read the first 256 kB from flash and write them to a file.
+.TP
+\fB\-R\fR \fISIZE\-IN\-BYTES\fR
+Read the specified number of bytes from the flash and write them to a
+file. You can append `\fBk\fR' to the size to specify it in kilobytes
+and `\fBM\fR' to specify it in megabytes.
+.TP
+\fB\-S\fR
+Perform SRAM programming.
+.TP
+\fB\-t\fR
+Just read the flash ID sequence.
+.PP
+All of the above options are mutually exclusive.
+.SS General options
+.TP
+\fB\-d\fR \fIDEVICE\-STRING\fR
+Use the specified USB device instead of the default one (which is
+vendor ID 0x0403 and device ID 0x6010). The supported notations for
+\fIDEVICE\-STRING\fR are:
+
+\fBd:\,\f(BIdevicenode\fR \- path of the bus and device node within
+USB device tree (usually at /proc/bus/usb/); e.g., `d:002/005'
+
+\fBi:\,\f(BIvendor\/\fB:\,\f(BIproduct\fR \- first device with given
+vendor and product ID. IDs can be decimal, octal (preceded by
+`\fB0\fR'), or hex (preceded by `\fB0x\fR'); e.g., `i:0x0403:0x6010'
+
+\fBi:\,\f(BIvendor\/\fB:\,\f(BIproduct\/\fB:\,\f(BIindex\fR \- same as
+above, with index being the number of the device (starting with 0) if
+there is more than one device with this vendor and product ID; e.g.,
+`i:0x0403:0x6010:0'
+
+\fBs:\,\f(BIvendor\/\fB:\,\f(BIproduct\/\fB:\,\f(BIserial\-string\fR
+\- first device with given vendor ID, product ID and serial string.
+.TP
+\fB\-I\fR A|B|C|D
+Connect to the specified interface on the FTDI chip. If this option
+is omitted, interface A is used.
+.TP
+\fB\-o\fR \fIOFFSET\-IN\-BYTES\fR
+Start reading/writing at address \fIOFFSET\-IN\-BYTES\fR instead of the
+beginning of the memory. You can append `\fBk\fR' to the offset to
+specify it in kilobytes and `\fBM\fR' to specify it in megabytes.
+.TP
+\fB\-v\fR
+Write more verbose messages.
+.TP
+\fB\-\-help\fR
+Display a help text and exit.
+.SS Exit status
+.TP
+.B 0
+on success,
+.TP
+.B 1
+if a non\-hardware error occurred (e.g., failure to read from or write
+to a file, or invoked with invalid options),
+.TP
+.B 2
+if communication with the hardware failed (e.g., cannot find the iCE
+FTDI USB device),
+.TP
+.B 3
+if verification of the data failed.
+.SS Notes for iCEstick (iCE40HX\-1k devel board)
+An unmodified iCEstick can only be programmed via the serial flash.
+Direct programming of the SRAM is not supported. For direct SRAM
+programming the flash chip and one zero ohm resistor must be
+desoldered and the FT2232H SI pin must be connected to the iCE SPI_SI
+pin, as shown in this picture:
+<http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838>
+.SS Notes for the iCE40\-HX8K Breakout Board
+Make sure that the jumper settings on the board match the selected
+mode (SRAM or FLASH). See the iCE40\-HX8K user manual for details.
+.SH AUTHOR
+Written by Clifford Wolf.
+.SH REPORTING BUGS
+If you have a bug report, please file an issue on github:
+<https://github.com/cliffordwolf/icestorm/issues>
+.SH COPYRIGHT
+Most of Project IceStorm is licensed under the ISC license:
+
+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.
+.SH SEE ALSO
+Full documentation at: <http://hedmen.org/icestorm-doc/>
+.br
+or available locally via: info \(aq(icestorm) iceprog invocation\(aq
diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c
index 5db6dc9..9dd9f17 100644
--- a/iceprog/iceprog.c
+++ b/iceprog/iceprog.c
@@ -31,27 +31,30 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <getopt.h>
#include <errno.h>
+#include <err.h>
#include <sys/types.h>
#include <sys/stat.h>
-struct ftdi_context ftdic;
-bool ftdic_open = false;
-bool verbose = false;
-bool ftdic_latency_set = false;
-unsigned char ftdi_latency;
+static struct ftdi_context ftdic;
+static bool ftdic_open = false;
+static bool verbose = false;
+static bool ftdic_latency_set = false;
+static unsigned char ftdi_latency;
-void check_rx()
+static void check_rx()
{
while (1) {
uint8_t data;
int rc = ftdi_read_data(&ftdic, &data, 1);
- if (rc <= 0) break;
+ if (rc <= 0)
+ break;
fprintf(stderr, "unexpected rx byte: %02X\n", data);
}
}
-void error()
+static void error(int status)
{
check_rx();
fprintf(stderr, "ABORT.\n");
@@ -61,17 +64,17 @@ void error()
ftdi_usb_close(&ftdic);
}
ftdi_deinit(&ftdic);
- exit(1);
+ exit(status);
}
-uint8_t recv_byte()
+static uint8_t recv_byte()
{
uint8_t data;
while (1) {
int rc = ftdi_read_data(&ftdic, &data, 1);
if (rc < 0) {
fprintf(stderr, "Read error.\n");
- error();
+ error(2);
}
if (rc == 1)
break;
@@ -80,51 +83,54 @@ uint8_t recv_byte()
return data;
}
-void send_byte(uint8_t data)
+static void send_byte(uint8_t data)
{
int rc = ftdi_write_data(&ftdic, &data, 1);
if (rc != 1) {
- fprintf(stderr, "Write error (single byte, rc=%d, expected %d).\n", rc, 1);
- error();
+ fprintf(stderr, "Write error (single byte, "
+ "rc=%d, expected %d).\n", rc, 1);
+ error(2);
}
}
-void send_spi(uint8_t *data, int n)
+static void send_spi(uint8_t *data, int n)
{
if (n < 1)
return;
send_byte(0x11);
- send_byte(n-1);
- send_byte((n-1) >> 8);
+ send_byte(n - 1);
+ send_byte((n - 1) >> 8);
int rc = ftdi_write_data(&ftdic, data, n);
if (rc != n) {
- fprintf(stderr, "Write error (chunk, rc=%d, expected %d).\n", rc, n);
- error();
+ fprintf(stderr, "Write error (chunk, "
+ "rc=%d, expected %d).\n", rc, n);
+ error(2);
}
}
-void xfer_spi(uint8_t *data, int n)
+static void xfer_spi(uint8_t *data, int n)
{
if (n < 1)
return;
send_byte(0x31);
- send_byte(n-1);
- send_byte((n-1) >> 8);
+ send_byte(n - 1);
+ send_byte((n - 1) >> 8);
int rc = ftdi_write_data(&ftdic, data, n);
if (rc != n) {
- fprintf(stderr, "Write error (chunk, rc=%d, expected %d).\n", rc, n);
- error();
+ fprintf(stderr, "Write error (chunk, "
+ "rc=%d, expected %d).\n", rc, n);
+ error(2);
}
for (int i = 0; i < n; i++)
data[i] = recv_byte();
}
-void set_gpio(int slavesel_b, int creset_b)
+static void set_gpio(int slavesel_b, int creset_b)
{
uint8_t gpio = 1;
@@ -143,7 +149,7 @@ void set_gpio(int slavesel_b, int creset_b)
send_byte(0x93);
}
-int get_cdone()
+static int get_cdone()
{
uint8_t data;
send_byte(0x81);
@@ -152,7 +158,7 @@ int get_cdone()
return (data & 0x40) != 0;
}
-void flash_read_id()
+static void flash_read_id()
{
// fprintf(stderr, "read flash ID..\n");
@@ -167,7 +173,7 @@ void flash_read_id()
fprintf(stderr, "\n");
}
-void flash_power_up()
+static void flash_power_up()
{
uint8_t data[1] = { 0xAB };
set_gpio(0, 0);
@@ -175,7 +181,7 @@ void flash_power_up()
set_gpio(1, 0);
}
-void flash_power_down()
+static void flash_power_down()
{
uint8_t data[1] = { 0xB9 };
set_gpio(0, 0);
@@ -183,7 +189,7 @@ void flash_power_down()
set_gpio(1, 0);
}
-void flash_write_enable()
+static void flash_write_enable()
{
if (verbose)
fprintf(stderr, "write enable..\n");
@@ -194,7 +200,7 @@ void flash_write_enable()
set_gpio(1, 0);
}
-void flash_bulk_erase()
+static void flash_bulk_erase()
{
fprintf(stderr, "bulk erase..\n");
@@ -204,22 +210,26 @@ void flash_bulk_erase()
set_gpio(1, 0);
}
-void flash_64kB_sector_erase(int addr)
+static void flash_64kB_sector_erase(int addr)
{
fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr);
- uint8_t command[4] = { 0xd8, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+ uint8_t command[4] = { 0xd8, (uint8_t)(addr >> 16),
+ (uint8_t)(addr >> 8),
+ (uint8_t)addr };
set_gpio(0, 0);
send_spi(command, 4);
set_gpio(1, 0);
}
-void flash_prog(int addr, uint8_t *data, int n)
+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] = { 0x02, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+ uint8_t command[4] = { 0x02, (uint8_t)(addr >> 16),
+ (uint8_t)(addr >> 8),
+ (uint8_t)addr };
set_gpio(0, 0);
send_spi(command, 4);
send_spi(data, n);
@@ -227,15 +237,18 @@ void flash_prog(int addr, uint8_t *data, int n)
if (verbose)
for (int i = 0; i < n; i++)
- fprintf(stderr, "%02x%c", data[i], i == n-1 || i % 32 == 31 ? '\n' : ' ');
+ fprintf(stderr, "%02x%c", data[i],
+ i == n - 1 || i % 32 == 31 ? '\n' : ' ');
}
-void flash_read(int addr, uint8_t *data, int 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] = { 0x03, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr };
+ uint8_t command[4] = { 0x03, (uint8_t)(addr >> 16),
+ (uint8_t)(addr >> 8),
+ (uint8_t)addr };
set_gpio(0, 0);
send_spi(command, 4);
memset(data, 0, n);
@@ -244,16 +257,16 @@ void flash_read(int addr, uint8_t *data, int n)
if (verbose)
for (int i = 0; i < n; i++)
- fprintf(stderr, "%02x%c", data[i], i == n-1 || i % 32 == 31 ? '\n' : ' ');
+ fprintf(stderr, "%02x%c", data[i],
+ i == n - 1 || i % 32 == 31 ? '\n' : ' ');
}
-void flash_wait()
+static void flash_wait()
{
if (verbose)
fprintf(stderr, "waiting..");
- while (1)
- {
+ while (1) {
uint8_t data[2] = { 0x05 };
set_gpio(0, 0);
@@ -274,74 +287,70 @@ void flash_wait()
fprintf(stderr, "\n");
}
-void help(const char *progname)
+static void help(const char *progname)
{
+ fprintf(stderr, "Simple programming tool for FTDI-based Lattice iCE programmers.\n");
+ fprintf(stderr, "Usage: %s [-b|-n|-c] <input file>\n", progname);
+ fprintf(stderr, " %s -r|-R<bytes> <output file>\n", progname);
+ fprintf(stderr, " %s -S <input file>\n", progname);
+ fprintf(stderr, " %s -t\n", progname);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "General options:\n");
+ fprintf(stderr, " -d <device string> use the specified USB device [default: i:0x0403:0x6010]\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, " -v verbose output\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Mode of operation:\n");
+ fprintf(stderr, " [default] write file contents to flash, then verify\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, "iceprog -- simple programming tool for FTDI-based Lattice iCE programmers\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, " -n do not erase flash before writing\n");
fprintf(stderr, "\n");
+ fprintf(stderr, "Miscellaneous options:\n");
+ fprintf(stderr, " --help display this help and exit\n");
+ fprintf(stderr, " -- treat all remaining arguments as filenames\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Exit status:\n");
+ fprintf(stderr, " 0 on success,\n");
+ fprintf(stderr, " 1 if a non-hardware error occurred (e.g., failure to read from or\n");
+ fprintf(stderr, " write to a file, or invoked with invalid options),\n");
+ fprintf(stderr, " 2 if communication with the hardware failed (e.g., cannot find the\n");
+ fprintf(stderr, " iCE FTDI USB device),\n");
+ fprintf(stderr, " 3 if verification of the data failed.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Notes for iCEstick (iCE40HX-1k devel board):\n");
fprintf(stderr, " An unmodified iCEstick can only be programmed via the serial flash.\n");
fprintf(stderr, " Direct programming of the SRAM is not supported. For direct SRAM\n");
fprintf(stderr, " programming the flash chip and one zero ohm resistor must be desoldered\n");
fprintf(stderr, " and the FT2232H SI pin must be connected to the iCE SPI_SI pin, as shown\n");
- fprintf(stderr, " in this picture: http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838\n");
- fprintf(stderr, "\n");
+ fprintf(stderr, " in this picture:\n");
+ fprintf(stderr, " http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838\n");
fprintf(stderr, "\n");
fprintf(stderr, "Notes for the iCE40-HX8K Breakout Board:\n");
fprintf(stderr, " Make sure that the jumper settings on the board match the selected\n");
fprintf(stderr, " mode (SRAM or FLASH). See the iCE40-HX8K user manual for details.\n");
fprintf(stderr, "\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Usage: %s [options] <filename>\n", progname);
- fprintf(stderr, "\n");
- fprintf(stderr, " -d <device-string>\n");
- fprintf(stderr, " use the specified USB device:\n");
- fprintf(stderr, "\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, "\n");
- fprintf(stderr, " -I [ABCD]\n");
- fprintf(stderr, " connect to the specified interface on the FTDI chip\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -r\n");
- fprintf(stderr, " read first 256 kB from flash and write to file\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -R <size_in_bytes>\n");
- fprintf(stderr, " read the specified number of bytes from flash\n");
- fprintf(stderr, " (append 'k' to the argument for size in kilobytes, or\n");
- fprintf(stderr, " 'M' for size in megabytes)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -o <offset_in_bytes>\n");
- fprintf(stderr, " start address for read/write (instead of zero)\n");
- fprintf(stderr, " (append 'k' to the argument for size in kilobytes, or\n");
- fprintf(stderr, " 'M' for size in megabytes)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -c\n");
- fprintf(stderr, " do not write flash, only verify (check)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -b\n");
- fprintf(stderr, " bulk erase entire flash before writing\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -n\n");
- fprintf(stderr, " do not erase flash before writing\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -S\n");
- fprintf(stderr, " perform SRAM programming\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -t\n");
- fprintf(stderr, " just read the flash ID sequence\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -v\n");
- fprintf(stderr, " verbose output\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Without -b or -n, iceprog will erase aligned chunks of 64kB in write mode.\n");
- fprintf(stderr, "This means that some data after the written data (or even before when -o is\n");
- fprintf(stderr, "used) may be erased as well.\n");
- fprintf(stderr, "\n");
- exit(1);
+ fprintf(stderr, "If you have a bug report, please file an issue on github:\n");
+ fprintf(stderr, " https://github.com/cliffordwolf/icestorm/issues\n");
}
int main(int argc, char **argv)
@@ -359,21 +368,32 @@ int main(int argc, char **argv)
const char *devstr = NULL;
enum ftdi_interface ifnum = INTERFACE_A;
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, -2},
+ {NULL, 0, NULL, 0}
+ };
+
int opt;
char *endptr;
- while ((opt = getopt(argc, argv, "d:I:rR:o:cbnStv")) != -1)
- {
- switch (opt)
- {
+ while ((opt = getopt_long(argc, argv, "d:I:rR:o:cbnStv",
+ long_options, NULL)) != -1) {
+ switch (opt) {
case 'd':
devstr = optarg;
break;
case 'I':
- if (!strcmp(optarg, "A")) ifnum = INTERFACE_A;
- else if (!strcmp(optarg, "B")) ifnum = INTERFACE_B;
- else if (!strcmp(optarg, "C")) ifnum = INTERFACE_C;
- else if (!strcmp(optarg, "D")) ifnum = INTERFACE_D;
- else help(argv[0]);
+ if (!strcmp(optarg, "A"))
+ ifnum = INTERFACE_A;
+ else if (!strcmp(optarg, "B"))
+ ifnum = INTERFACE_B;
+ else if (!strcmp(optarg, "C"))
+ ifnum = INTERFACE_C;
+ else if (!strcmp(optarg, "D"))
+ ifnum = INTERFACE_D;
+ else
+ errx(EXIT_FAILURE,
+ "`%s' is not a valid interface (must be "
+ "`A', `B', `C', or `D')", optarg);
break;
case 'r':
read_mode = true;
@@ -381,13 +401,27 @@ int main(int argc, char **argv)
case 'R':
read_mode = true;
read_size = strtol(optarg, &endptr, 0);
- if (!strcmp(endptr, "k")) read_size *= 1024;
- if (!strcmp(endptr, "M")) read_size *= 1024 * 1024;
+ if (*endptr == '\0')
+ /* ok */;
+ else if (!strcmp(endptr, "k"))
+ read_size *= 1024;
+ else if (!strcmp(endptr, "M"))
+ read_size *= 1024 * 1024;
+ else
+ errx(EXIT_FAILURE,
+ "`%s' is not a valid size", optarg);
break;
case 'o':
rw_offset = strtol(optarg, &endptr, 0);
- if (!strcmp(endptr, "k")) rw_offset *= 1024;
- if (!strcmp(endptr, "M")) rw_offset *= 1024 * 1024;
+ if (*endptr == '\0')
+ /* ok */;
+ else if (!strcmp(endptr, "k"))
+ rw_offset *= 1024;
+ else if (!strcmp(endptr, "M"))
+ rw_offset *= 1024 * 1024;
+ else
+ errx(EXIT_FAILURE,
+ "`%s' is not a valid offset", optarg);
break;
case 'c':
check_mode = true;
@@ -407,24 +441,131 @@ int main(int argc, char **argv)
case 'v':
verbose = true;
break;
- default:
+ 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;
}
}
if (read_mode + check_mode + prog_sram + test_mode > 1)
- help(argv[0]);
+ errx(EXIT_FAILURE,
+ "options `-r'/`-R', `-c', `-S', and `-t' are mutually "
+ "exclusive");
if (bulk_erase && dont_erase)
- help(argv[0]);
-
- if (optind+1 != argc && !test_mode) {
- if (bulk_erase && optind == argc)
- filename = "/dev/null";
- else
- help(argv[0]);
- } else
+ errx(EXIT_FAILURE,
+ "options `-b' and `-n' are mutually exclusive");
+
+ if (bulk_erase && (read_mode || check_mode || prog_sram || test_mode))
+ errx(EXIT_FAILURE,
+ "option `-b' only valid in programming mode");
+ if (dont_erase && (read_mode || check_mode || prog_sram || test_mode))
+ errx(EXIT_FAILURE,
+ "option `-n' only valid in programming mode");
+
+ if (rw_offset != 0 && prog_sram)
+ errx(EXIT_FAILURE, "option `-o' not supported in SRAM mode");
+ if (rw_offset != 0 && test_mode)
+ errx(EXIT_FAILURE, "option `-o' not supported in test mode");
+
+ if (optind + 1 == argc) {
+ if (test_mode) {
+ warnx("test mode doesn't take a file name");
+ fprintf(stderr, "Try `%s --help' "
+ "for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
filename = argv[optind];
+ } else if (optind != argc) {
+ warnx("too many arguments");
+ fprintf(stderr, "Try `%s --help' "
+ "for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ } else if (bulk_erase) {
+ filename = "/dev/null";
+ } else if (!test_mode) {
+ warnx("missing argument");
+ 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 (read_mode) {
+ f = (strcmp(filename, "-") == 0) ? stdout
+ : fopen(filename, "wb");
+ if (f == NULL)
+ err(EXIT_FAILURE,
+ "can't open '%s' for writing", filename);
+ } else {
+ f = (strcmp(filename, "-") == 0) ? stdin
+ : fopen(filename, "rb");
+ if (f == NULL)
+ err(EXIT_FAILURE,
+ "can't open '%s' for reading", filename);
+
+ /* 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)
+ err(EXIT_FAILURE,
+ "%s: ftell", filename);
+ if (fseek(f, 0L, SEEK_SET) == -1)
+ err(EXIT_FAILURE,
+ "%s: fseek", filename);
+ } else {
+ FILE *pipe = f;
+
+ f = tmpfile();
+ if (f == NULL)
+ errx(EXIT_FAILURE,
+ "can't open temporary file");
+ 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)
+ errx(EXIT_FAILURE,
+ "can't write to "
+ "temporary file");
+ 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
@@ -437,13 +578,16 @@ int main(int argc, char **argv)
if (devstr != NULL) {
if (ftdi_usb_open_string(&ftdic, devstr)) {
- fprintf(stderr, "Can't find iCE FTDI USB device (device string %s).\n", devstr);
- error();
+ fprintf(stderr, "Can't find iCE FTDI USB device "
+ "(device string %s).\n", devstr);
+ error(2);
}
} else {
if (ftdi_usb_open(&ftdic, 0x0403, 0x6010)) {
- fprintf(stderr, "Can't find iCE FTDI USB device (vedor_id 0x0403, device_id 0x6010).\n");
- error();
+ fprintf(stderr, "Can't find iCE FTDI USB device "
+ "(vendor_id 0x0403, "
+ "device_id 0x6010).\n");
+ error(2);
}
}
@@ -451,30 +595,34 @@ int main(int argc, char **argv)
if (ftdi_usb_reset(&ftdic)) {
fprintf(stderr, "Failed to reset iCE FTDI USB device.\n");
- error();
+ error(2);
}
if (ftdi_usb_purge_buffers(&ftdic)) {
- fprintf(stderr, "Failed to purge buffers on iCE FTDI USB device.\n");
- error();
+ fprintf(stderr, "Failed to purge buffers "
+ "on iCE FTDI USB device.\n");
+ error(2);
}
if (ftdi_get_latency_timer(&ftdic, &ftdi_latency) < 0) {
- fprintf(stderr, "Failed to get latency timer (%s).\n", ftdi_get_error_string(&ftdic));
- error();
+ fprintf(stderr, "Failed to get latency timer (%s).\n",
+ ftdi_get_error_string(&ftdic));
+ error(2);
}
/* 1 is the fastest polling, it means 1 kHz polling */
if (ftdi_set_latency_timer(&ftdic, 1) < 0) {
- fprintf(stderr, "Failed to set latency timer (%s).\n", ftdi_get_error_string(&ftdic));
- error();
+ fprintf(stderr, "Failed to set latency timer (%s).\n",
+ ftdi_get_error_string(&ftdic));
+ error(2);
}
ftdic_latency_set = true;
if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_MPSSE) < 0) {
- fprintf(stderr, "Failed set BITMODE_MPSSE on iCE FTDI USB device.\n");
- error();
+ fprintf(stderr, "Failed to set BITMODE_MPSSE "
+ "on iCE FTDI USB device.\n");
+ error(2);
}
// enable clock divide by 5
@@ -491,8 +639,7 @@ int main(int argc, char **argv)
usleep(100000);
- if (test_mode)
- {
+ if (test_mode) {
fprintf(stderr, "reset..\n");
set_gpio(1, 0);
@@ -510,9 +657,7 @@ int main(int argc, char **argv)
usleep(250000);
fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low");
- }
- else if (prog_sram)
- {
+ } else if (prog_sram) {
// ---------------------------------------------------------
// Reset
// ---------------------------------------------------------
@@ -532,27 +677,17 @@ int main(int argc, char **argv)
// Program
// ---------------------------------------------------------
- FILE *f = (strcmp(filename, "-") == 0) ? stdin :
- fopen(filename, "rb");
- if (f == NULL) {
- fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
- error();
- }
-
fprintf(stderr, "programming..\n");
- while (1)
- {
+ while (1) {
static unsigned char buffer[4096];
int rc = fread(buffer, 1, 4096, f);
- if (rc <= 0) break;
+ if (rc <= 0)
+ break;
if (verbose)
fprintf(stderr, "sending %d bytes.\n", rc);
send_spi(buffer, rc);
}
- if (f != stdin)
- fclose(f);
-
// add 48 dummy bits
send_byte(0x8f);
send_byte(0x05);
@@ -563,9 +698,7 @@ int main(int argc, char **argv)
send_byte(0x00);
fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low");
- }
- else
- {
+ } else {
// ---------------------------------------------------------
// Reset
// ---------------------------------------------------------
@@ -586,37 +719,22 @@ int main(int argc, char **argv)
// Program
// ---------------------------------------------------------
- if (!read_mode && !check_mode)
- {
- FILE *f = (strcmp(filename, "-") == 0) ? stdin :
- fopen(filename, "rb");
- if (f == NULL) {
- fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
- error();
- }
-
- if (!dont_erase)
- {
- if (bulk_erase)
- {
+ if (!read_mode && !check_mode) {
+ if (!dont_erase) {
+ if (bulk_erase) {
flash_write_enable();
flash_bulk_erase();
flash_wait();
- }
- else
- {
- struct stat st_buf;
- if (stat(filename, &st_buf)) {
- fprintf(stderr, "Error: Can't stat '%s': %s\n", filename, strerror(errno));
- error();
- }
-
- fprintf(stderr, "file size: %d\n", (int)st_buf.st_size);
+ } else {
+ fprintf(stderr, "file size: %ld\n",
+ file_size);
int begin_addr = rw_offset & ~0xffff;
- int end_addr = (rw_offset + (int)st_buf.st_size + 0xffff) & ~0xffff;
+ int end_addr = (rw_offset + file_size
+ + 0xffff) & ~0xffff;
- for (int addr = begin_addr; addr < end_addr; addr += 0x10000) {
+ for (int addr = begin_addr;
+ addr < end_addr; addr += 0x10000) {
flash_write_enable();
flash_64kB_sector_erase(addr);
flash_wait();
@@ -630,65 +748,45 @@ int main(int argc, char **argv)
uint8_t buffer[256];
int page_size = 256 - (rw_offset + addr) % 256;
rc = fread(buffer, 1, page_size, f);
- if (rc <= 0) break;
+ if (rc <= 0)
+ break;
flash_write_enable();
flash_prog(rw_offset + addr, buffer, rc);
flash_wait();
}
- if (f != stdin)
- fclose(f);
+ /* seek to the beginning for second pass */
+ fseek(f, 0, SEEK_SET);
}
-
// ---------------------------------------------------------
// Read/Verify
// ---------------------------------------------------------
- if (read_mode)
- {
- FILE *f = (strcmp(filename, "-") == 0) ? stdout :
- fopen(filename, "wb");
- if (f == NULL) {
- fprintf(stderr, "Error: Can't open '%s' for writing: %s\n", filename, strerror(errno));
- error();
- }
-
+ 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, 256, 1, f);
- }
-
- if (f != stdout)
- fclose(f);
- }
- else
- {
- FILE *f = (strcmp(filename, "-") == 0) ? stdin :
- fopen(filename, "rb");
- if (f == NULL) {
- fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
- error();
+ fwrite(buffer, read_size - addr > 256 ? 256 :
+ read_size - addr, 1, f);
}
-
+ } else {
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;
+ 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");
- error();
+ fprintf(stderr, "Found difference "
+ "between flash and file!\n");
+ error(3);
}
}
fprintf(stderr, "VERIFY OK\n");
-
- if (f != stdin)
- fclose(f);
}
@@ -704,6 +802,8 @@ int main(int argc, char **argv)
fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low");
}
+ if (f != NULL && f != stdin && f != stdout)
+ fclose(f);
// ---------------------------------------------------------
// Exit
@@ -716,4 +816,3 @@ int main(int argc, char **argv)
ftdi_deinit(&ftdic);
return 0;
}
-