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/examples/icestick/.gitignore b/examples/icestick/.gitignore
index 539898f..c854ccc 100644
--- a/examples/icestick/.gitignore
+++ b/examples/icestick/.gitignore
@@ -6,3 +6,17 @@ rs232demo.bin
rs232demo.blif
rs232demo.asc
rs232demo.rpt
+rs232demo_tb
+rs232demo_tb.vcd
+rs232demo_syn.v
+rs232demo_syntb
+rs232demo_syntb.vcd
+checker.bin
+checker.blif
+checker.asc
+checker.rpt
+checker_tb
+checker_tb.vcd
+checker_syn.v
+checker_syntb
+checker_syntb.vcd
diff --git a/examples/icestick/Makefile b/examples/icestick/Makefile
index 9294608..8b8e741 100644
--- a/examples/icestick/Makefile
+++ b/examples/icestick/Makefile
@@ -1,5 +1,6 @@
PROJ = example
# PROJ = rs232demo
+# PROJ = checker
PIN_DEF = icestick.pcf
DEVICE = hx1k
@@ -18,6 +19,21 @@ all: $(PROJ).rpt $(PROJ).bin
%.rpt: %.asc
icetime -d $(DEVICE) -mtr $@ $<
+%_tb: %_tb.v %.v
+ iverilog -o $@ $^
+
+%_tb.vcd: %_tb
+ vvp -N $< +vcd=$@
+
+%_syn.v: %.blif
+ yosys -p 'read_blif -wideports $^; write_verilog $@'
+
+%_syntb: %_tb.v %_syn.v
+ iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
+
+%_syntb.vcd: %_syntb
+ vvp -N $< +vcd=$@
+
prog: $(PROJ).bin
iceprog $<
diff --git a/examples/icestick/checker.v b/examples/icestick/checker.v
new file mode 100644
index 0000000..a441845
--- /dev/null
+++ b/examples/icestick/checker.v
@@ -0,0 +1,55 @@
+// A simple circuit that can be used to detect brownouts and other hardware issues
+
+module top (
+ input clk,
+ output LED1,
+ output LED2,
+ output LED3,
+ output LED4,
+ output LED5
+);
+ reg [7:0] reset_counter = 0;
+ reg resetn = 0;
+
+ always @(posedge clk) begin
+ reset_counter <= reset_counter + 1;
+ resetn <= resetn | &reset_counter;
+ end
+
+ reg error, rdmode, rdfin;
+
+ reg [31:0] scratchpad [0:1023];
+ reg [31:0] xorshift32_state;
+ reg [9:0] index;
+
+ reg [31:0] next_xorshift32_state;
+
+ always @* begin
+ next_xorshift32_state = xorshift32_state ^ ( xorshift32_state << 13);
+ next_xorshift32_state = next_xorshift32_state ^ (next_xorshift32_state >> 17);
+ next_xorshift32_state = next_xorshift32_state ^ (next_xorshift32_state << 5);
+ end
+
+ always @(posedge clk) begin
+ xorshift32_state <= &index ? 123456789 : next_xorshift32_state;
+ index <= index + 1;
+
+ if (!resetn) begin
+ xorshift32_state <= 123456789;
+ index <= 0;
+ error <= 0;
+ rdmode <= 0;
+ rdfin <= 0;
+ end else
+ if (!rdmode) begin
+ scratchpad[index] <= xorshift32_state;
+ rdmode <= &index;
+ end else begin
+ if (scratchpad[index] != xorshift32_state) error <= 1;
+ rdfin <= rdfin || &index;
+ end
+ end
+
+ wire ok = resetn && rdfin && !error;
+ assign LED1 = 0, LED2 = error, LED3 = 0, LED4 = error, LED5 = ok;
+endmodule
diff --git a/examples/icestick/checker_tb.v b/examples/icestick/checker_tb.v
new file mode 100644
index 0000000..241c89e
--- /dev/null
+++ b/examples/icestick/checker_tb.v
@@ -0,0 +1,40 @@
+module testbench;
+ reg clk;
+ always #5 clk = (clk === 1'b0);
+
+ wire ok;
+
+ top uut (
+ .clk(clk),
+ .LED5(ok)
+ );
+
+ reg [4095:0] vcdfile;
+
+ initial begin
+ if ($value$plusargs("vcd=%s", vcdfile)) begin
+ $dumpfile(vcdfile);
+ $dumpvars(0, testbench);
+ end
+ end
+
+ initial begin
+ @(posedge ok);
+ @(negedge ok);
+ $display("ERROR: detected falling edge on OK pin!");
+ $stop;
+ end
+
+ initial begin
+ repeat (3000) @(posedge clk);
+
+ if (!ok) begin
+ $display("ERROR: OK pin not asserted after 3000 cycles!");
+ $stop;
+ end
+
+ repeat (10000) @(posedge clk);
+ $display("SUCCESS: OK pin still asserted after 10000 cycles.");
+ $finish;
+ end
+endmodule
diff --git a/examples/icestick/rs232demo.v b/examples/icestick/rs232demo.v
index f9e7546..40347e8 100644
--- a/examples/icestick/rs232demo.v
+++ b/examples/icestick/rs232demo.v
@@ -19,6 +19,14 @@ module top (
reg [3:0] bit_cnt = 0;
reg recv = 0;
+ initial begin
+ LED1 = 0;
+ LED2 = 0;
+ LED3 = 0;
+ LED4 = 0;
+ LED5 = 0;
+ end
+
always @(posedge clk) begin
buffer_valid <= 0;
if (!recv) begin
diff --git a/examples/icestick/rs232demo_tb.v b/examples/icestick/rs232demo_tb.v
new file mode 100644
index 0000000..5b9aee1
--- /dev/null
+++ b/examples/icestick/rs232demo_tb.v
@@ -0,0 +1,74 @@
+module testbench;
+ localparam integer PERIOD = 12000000 / 9600;
+
+ // reg clk = 0;
+ // initial #10 forever #5 clk = ~clk;
+
+ reg clk;
+ always #5 clk = (clk === 1'b0);
+
+ reg RX = 1;
+ wire TX;
+ wire LED1;
+ wire LED2;
+ wire LED3;
+ wire LED4;
+ wire LED5;
+
+ top uut (
+ .clk (clk ),
+ .RX (RX ),
+ .TX (TX ),
+ .LED1(LED1),
+ .LED2(LED2),
+ .LED3(LED3),
+ .LED4(LED4),
+ .LED5(LED5)
+ );
+
+ task send_byte;
+ input [7:0] c;
+ integer i;
+ begin
+ RX <= 0;
+ repeat (PERIOD) @(posedge clk);
+
+ for (i = 0; i < 8; i = i+1) begin
+ RX <= c[i];
+ repeat (PERIOD) @(posedge clk);
+ end
+
+ RX <= 1;
+ repeat (PERIOD) @(posedge clk);
+ end
+ endtask
+
+ reg [4095:0] vcdfile;
+
+ initial begin
+ if ($value$plusargs("vcd=%s", vcdfile)) begin
+ $dumpfile(vcdfile);
+ $dumpvars(0, testbench);
+ end
+
+ repeat (10 * PERIOD) @(posedge clk);
+
+ // turn all LEDs on
+ send_byte("1");
+ send_byte("2");
+ send_byte("3");
+ send_byte("4");
+ send_byte("5");
+
+ // turn all LEDs off
+ send_byte("1");
+ send_byte("2");
+ send_byte("3");
+ send_byte("4");
+ send_byte("5");
+
+ repeat (10 * PERIOD) @(posedge clk);
+
+ $finish;
+ end
+endmodule
diff --git a/icebox/Makefile b/icebox/Makefile
index fed3d6d..b352c9b 100644
--- a/icebox/Makefile
+++ b/icebox/Makefile
@@ -30,26 +30,26 @@ install: all
cp chipdb-8k.txt $(DESTDIR)$(PREFIX)/share/icebox/
cp icebox.py $(DESTDIR)$(PREFIX)/bin/icebox.py
cp iceboxdb.py $(DESTDIR)$(PREFIX)/bin/iceboxdb.py
- cp icebox_chipdb.py $(DESTDIR)$(PREFIX)/bin/icebox_chipdb
- cp icebox_diff.py $(DESTDIR)$(PREFIX)/bin/icebox_diff
- cp icebox_explain.py $(DESTDIR)$(PREFIX)/bin/icebox_explain
- cp icebox_colbuf.py $(DESTDIR)$(PREFIX)/bin/icebox_colbuf
- cp icebox_html.py $(DESTDIR)$(PREFIX)/bin/icebox_html
- cp icebox_maps.py $(DESTDIR)$(PREFIX)/bin/icebox_maps
- cp icebox_vlog.py $(DESTDIR)$(PREFIX)/bin/icebox_vlog
- cp icebox_stat.py $(DESTDIR)$(PREFIX)/bin/icebox_stat
+ cp icebox_chipdb.py $(DESTDIR)$(PREFIX)/bin/icebox_chipdb$(PY_EXE)
+ cp icebox_diff.py $(DESTDIR)$(PREFIX)/bin/icebox_diff$(PY_EXE)
+ cp icebox_explain.py $(DESTDIR)$(PREFIX)/bin/icebox_explain$(PY_EXE)
+ cp icebox_colbuf.py $(DESTDIR)$(PREFIX)/bin/icebox_colbuf$(PY_EXE)
+ cp icebox_html.py $(DESTDIR)$(PREFIX)/bin/icebox_html$(PY_EXE)
+ cp icebox_maps.py $(DESTDIR)$(PREFIX)/bin/icebox_maps$(PY_EXE)
+ cp icebox_vlog.py $(DESTDIR)$(PREFIX)/bin/icebox_vlog$(PY_EXE)
+ cp icebox_stat.py $(DESTDIR)$(PREFIX)/bin/icebox_stat$(PY_EXE)
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/icebox.py
rm -f $(DESTDIR)$(PREFIX)/bin/iceboxdb.py
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_chipdb
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_diff
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_explain
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_colbuf
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_html
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_maps
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_vlog
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_stat
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_chipdb$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_diff$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_explain$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_colbuf$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_html$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_maps$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_vlog$(PY_EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebox_stat$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-384.txt
rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-1k.txt
rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-8k.txt
diff --git a/icebram/Makefile b/icebram/Makefile
index d16b80b..3904926 100644
--- a/icebram/Makefile
+++ b/icebram/Makefile
@@ -14,10 +14,10 @@ test: icebram
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp icebram $(DESTDIR)$(PREFIX)/bin/icebram
+ cp icebram$(EXE) $(DESTDIR)$(PREFIX)/bin/icebram$(EXE)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/icebram
+ rm -f $(DESTDIR)$(PREFIX)/bin/icebram$(EXE)
clean:
rm -f icebram
diff --git a/icemulti/Makefile b/icemulti/Makefile
index a168bac..5302158 100644
--- a/icemulti/Makefile
+++ b/icemulti/Makefile
@@ -11,10 +11,10 @@ icemulti$(EXE): icemulti.o
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp icemulti $(DESTDIR)$(PREFIX)/bin/icemulti
+ cp icemulti$(EXE) $(DESTDIR)$(PREFIX)/bin/icemulti$(EXE)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/icemulti
+ rm -f $(DESTDIR)$(PREFIX)/bin/icemulti$(EXE)
clean:
rm -f icemulti
diff --git a/icepack/Makefile b/icepack/Makefile
index 2578fe0..65d4c9a 100644
--- a/icepack/Makefile
+++ b/icepack/Makefile
@@ -18,12 +18,12 @@ iceunpack.exe:
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp icepack $(DESTDIR)$(PREFIX)/bin/icepack
- ln -sf icepack $(DESTDIR)$(PREFIX)/bin/iceunpack
+ cp icepack$(EXE) $(DESTDIR)$(PREFIX)/bin/icepack$(EXE)
+ ln -sf icepack$(EXE) $(DESTDIR)$(PREFIX)/bin/iceunpack$(EXE)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/icepack
- rm -f $(DESTDIR)$(PREFIX)/bin/iceunpack
+ rm -f $(DESTDIR)$(PREFIX)/bin/icepack$(EXE)
+ rm -f $(DESTDIR)$(PREFIX)/bin/iceunpack$(EXE)
clean:
rm -f icepack
diff --git a/icepll/Makefile b/icepll/Makefile
index 4efa4e1..87eabfa 100644
--- a/icepll/Makefile
+++ b/icepll/Makefile
@@ -11,10 +11,10 @@ icepll$(EXE): icepll.o
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp icepll $(DESTDIR)$(PREFIX)/bin/icepll
+ cp icepll$(EXE) $(DESTDIR)$(PREFIX)/bin/icepll$(EXE)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/icepll
+ rm -f $(DESTDIR)$(PREFIX)/bin/icepll$(EXE)
clean:
rm -f icepll
diff --git a/iceprog/Makefile b/iceprog/Makefile
index 286460f..d71a9b7 100644
--- a/iceprog/Makefile
+++ b/iceprog/Makefile
@@ -23,10 +23,13 @@ iceprog$(EXE): iceprog.o
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp iceprog $(DESTDIR)$(PREFIX)/bin/iceprog
+ cp iceprog$(EXE) $(DESTDIR)$(PREFIX)/bin/iceprog$(EXE)
+ 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)/bin/iceprog$(EXE)
+ 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..eca9496 100644
--- a/iceprog/iceprog.c
+++ b/iceprog/iceprog.c
@@ -31,27 +31,29 @@
#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 +63,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 +82,51 @@ 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();
+ 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();
+ 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();
+ 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 +145,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 +154,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 +169,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 +177,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 +185,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 +196,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 +206,24 @@ 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 };
+
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 };
+
set_gpio(0, 0);
send_spi(command, 4);
send_spi(data, n);
@@ -227,15 +231,16 @@ 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 };
+
set_gpio(0, 0);
send_spi(command, 4);
memset(data, 0, n);
@@ -244,10 +249,10 @@ 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..");
@@ -274,78 +279,80 @@ 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