diff --git a/docs/io_tile.html b/docs/io_tile.html
index c683ff7..82cf65b 100644
--- a/docs/io_tile.html
+++ b/docs/io_tile.html
@@ -47,9 +47,9 @@ to span12_horz_23.
-A top/bottom io cell has 16 connections named span4_vert_l_0 to span4_vert_l_15 on its top edge and
-16 connections named span4_vert_r_0 to span4_vert_r_15 on its bottom edge. The nets span4_vert_l_0
-to span4_vert_l_11 are connected to span4_vert_r_4 to span4_vert_r_15. The span-4 and span-12 wires
+A top/bottom io cell has 16 connections named span4_horz_l_0 to span4_horz_l_15 on its left edge and
+16 connections named span4_horz_r_0 to span4_horz_r_15 on its right edge. The nets span4_horz_l_0
+to span4_horz_l_11 are connected to span4_horz_r_4 to span4_horz_r_15. The span-4 and span-12 wires
of the adjacent logic cell are connected to the nets span4_vert_0 to span4_vert_47 and span12_vert_0
to span12_vert_23.
@@ -489,9 +489,9 @@ of the 1k chip:
1 0
fabout
BYPASS
2 0
fabout
RESETB
5 0
fabout
LATCHINPUTVALUE
-
12 1
neigh_op_bnl_1
SDO
+
12 1
neigh_op_bnr_3
SDO
4 0
fabout
SDI
-
5 0
fabout
SCLK
+
3 0
fabout
SCLK
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:
+
+.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:
+
+.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:
+.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
#include
#include
+#include
#include
+#include
#include
#include
-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] \n", progname);
+ fprintf(stderr, " %s -r|-R