diff options
Diffstat (limited to 'iceprog')
-rw-r--r-- | iceprog/Makefile | 3 | ||||
-rw-r--r-- | iceprog/iceprog.1 | 155 | ||||
-rw-r--r-- | iceprog/iceprog.c | 523 |
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; } - |