aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.mk4
-rw-r--r--docs/index.html1
-rw-r--r--docs/io_tile.html10
-rw-r--r--examples/icestick/.gitignore14
-rw-r--r--examples/icestick/Makefile16
-rw-r--r--examples/icestick/checker.v55
-rw-r--r--examples/icestick/checker_tb.v40
-rw-r--r--examples/icestick/rs232demo.v8
-rw-r--r--examples/icestick/rs232demo_tb.v74
-rw-r--r--icebox/Makefile32
-rw-r--r--icebram/Makefile4
-rw-r--r--icemulti/Makefile4
-rw-r--r--icepack/Makefile8
-rw-r--r--icepll/Makefile4
-rw-r--r--iceprog/Makefile7
-rw-r--r--iceprog/iceprog.1155
-rw-r--r--iceprog/iceprog.c470
-rw-r--r--icetime/Makefile4
18 files changed, 691 insertions, 219 deletions
diff --git a/config.mk b/config.mk
index aeb525f..364f8bc 100644
--- a/config.mk
+++ b/config.mk
@@ -1,8 +1,8 @@
CXX ?= clang++
CC ?= clang
LDLIBS = -lm -lstdc++
-CFLAGS = -MD -O0 -ggdb -Wall -std=c99 -I/usr/local/include
-CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11 -I/usr/local/include
+CFLAGS += -MD -O0 -ggdb -Wall -std=c99 -I/usr/local/include
+CXXFLAGS += -MD -O0 -ggdb -Wall -std=c++11 -I/usr/local/include
PKG_CONFIG ?= pkg-config
DESTDIR ?=
PREFIX ?= /usr/local
diff --git a/docs/index.html b/docs/index.html
index ebf424d..be02756 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -515,6 +515,7 @@ Links to related projects. Contact me at clifford@clifford.at if you have an int
<li><a href="http://opencores.org/project,ecowlogic-pico">eCow-Logic pico-ITX Lattice ICE40 board</a>
<li><a href="https://www.nandland.com/blog/go-board-introduction.html">Nandland Go Board</a>
<li><a href="https://folknologylabs.wordpress.com/2016/08/17/the-lull-before-the-storm/">myStorm board (iCE40 + STM32)</a>
+<li><a href="https://github.com/tvelliott/dsp_ice">DSP iCE board (another iCE40 + STM32 board)</a>
</ul>
<h3>Lectures and Tutorials</h3>
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 <span style="font-family:monospace">span12_horz_23</span>.
</p>
<p>
-A top/bottom io cell has 16 connections named <span style="font-family:monospace">span4_vert_l_0</span> to <span style="font-family:monospace">span4_vert_l_15</span> on its top edge and
-16 connections named <span style="font-family:monospace">span4_vert_r_0</span> to <span style="font-family:monospace">span4_vert_r_15</span> on its bottom edge. The nets <span style="font-family:monospace">span4_vert_l_0</span>
-to <span style="font-family:monospace">span4_vert_l_11</span> are connected to <span style="font-family:monospace">span4_vert_r_4</span> to <span style="font-family:monospace">span4_vert_r_15</span>. The span-4 and span-12 wires
+A top/bottom io cell has 16 connections named <span style="font-family:monospace">span4_horz_l_0</span> to <span style="font-family:monospace">span4_horz_l_15</span> on its left edge and
+16 connections named <span style="font-family:monospace">span4_horz_r_0</span> to <span style="font-family:monospace">span4_horz_r_15</span> on its right edge. The nets <span style="font-family:monospace">span4_horz_l_0</span>
+to <span style="font-family:monospace">span4_horz_l_11</span> are connected to <span style="font-family:monospace">span4_horz_r_4</span> to <span style="font-family:monospace">span4_horz_r_15</span>. The span-4 and span-12 wires
of the adjacent logic cell are connected to the nets <span style="font-family:monospace">span4_vert_0</span> to <span style="font-family:monospace">span4_vert_47</span> and <span style="font-family:monospace">span12_vert_0</span>
to <span style="font-family:monospace">span12_vert_23</span>.
</p>
@@ -489,9 +489,9 @@ of the 1k chip:
<tr><td>1 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">BYPASS</span></td></tr>
<tr><td>2 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">RESETB</span></td></tr>
<tr><td>5 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">LATCHINPUTVALUE</span></td></tr>
-<tr><td>12 1</td><td><span style="font-family:monospace">neigh_op_bnl_1</span></td><td rowspan="1"><span style="font-family:monospace">SDO</span></td></tr>
+<tr><td>12 1</td><td><span style="font-family:monospace">neigh_op_bnr_3</span></td><td rowspan="1"><span style="font-family:monospace">SDO</span></td></tr>
<tr><td>4 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">SDI</span></td></tr>
-<tr><td>5 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">SCLK</span></td></tr>
+<tr><td>3 0</td><td><span style="font-family:monospace">fabout</span></td><td rowspan="1"><span style="font-family:monospace">SCLK</span></td></tr>
</table>
<p>
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:
+<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..eca9496 100644
--- a/iceprog/iceprog.c
+++ b/iceprog/iceprog.c
@@ -31,27 +31,29 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <getopt.h>
#include <errno.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 +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] <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)
{
+ /* used for error reporting */
+ const char *my_name = argv[0];
+ for (size_t i = 0; argv[0][i]; i++)
+ if (argv[0][i] == '/')
+ my_name = argv[0] + i + 1;
+
int read_size = 256 * 1024;
int rw_offset = 0;
@@ -359,21 +366,31 @@ 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 {
+ fprintf(stderr, "%s: `%s' is not a valid interface (must be `A', `B', `C', or `D')\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
break;
case 'r':
read_mode = true;
@@ -381,13 +398,29 @@ 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 {
+ fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
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 {
+ fprintf(stderr, "%s: `%s' is not a valid offset\n", my_name, optarg);
+ return EXIT_FAILURE;
+ }
break;
case 'c':
check_mode = true;
@@ -407,24 +440,141 @@ 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]);
+ if (read_mode + check_mode + prog_sram + test_mode > 1) {
+ fprintf(stderr, "%s: options `-r'/`-R', `-c', `-S', and `-t' are mutually exclusive\n", my_name);
+ return EXIT_FAILURE;
+ }
- if (bulk_erase && dont_erase)
- help(argv[0]);
+ if (bulk_erase && dont_erase) {
+ fprintf(stderr, "%s: options `-b' and `-n' are mutually exclusive\n", my_name);
+ return EXIT_FAILURE;
+ }
- if (optind+1 != argc && !test_mode) {
- if (bulk_erase && optind == argc)
- filename = "/dev/null";
- else
- help(argv[0]);
- } else
+ if (bulk_erase && (read_mode || check_mode || prog_sram || test_mode)) {
+ fprintf(stderr, "%s: option `-b' only valid in programming mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (dont_erase && (read_mode || check_mode || prog_sram || test_mode)) {
+ fprintf(stderr, "%s: option `-n' only valid in programming mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (rw_offset != 0 && prog_sram) {
+ fprintf(stderr, "%s: option `-o' not supported in SRAM mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (rw_offset != 0 && test_mode) {
+ fprintf(stderr, "%s: option `-o' not supported in test mode\n", my_name);
+ return EXIT_FAILURE;
+ }
+
+ if (optind + 1 == argc) {
+ if (test_mode) {
+ fprintf(stderr, "%s: test mode doesn't take a file name\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
filename = argv[optind];
+ } else if (optind != argc) {
+ fprintf(stderr, "%s: too many arguments\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ } else if (bulk_erase) {
+ filename = "/dev/null";
+ } else if (!test_mode) {
+ fprintf(stderr, "%s: missing argument\n", my_name);
+ fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ /* open input/output file in advance
+ so we can fail before initializing the hardware */
+
+ FILE *f = NULL;
+ long file_size = -1;
+
+ if (test_mode)
+ /* nop */;
+ else if (read_mode) {
+ f = (strcmp(filename, "-") == 0) ? stdout : fopen(filename, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open '%s' for writing: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ } else {
+ f = (strcmp(filename, "-") == 0) ? stdin : fopen(filename, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open '%s' for reading: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+
+ /* For regular programming, we need to read the file
+ twice--once for programming and once for verifying--and
+ need to know the file size in advance in order to erase
+ the correct amount of memory.
+
+ See if we can seek on the input file. Checking for "-"
+ as an argument isn't enough as we might be reading from a
+ named pipe, or contrarily, the standard input may be an
+ ordinary file. */
+
+ if (!prog_sram && !check_mode) {
+ if (fseek(f, 0L, SEEK_END) != -1) {
+ file_size = ftell(f);
+ if (file_size == -1) {
+ fprintf(stderr, "%s: %s: ftell: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ if (fseek(f, 0L, SEEK_SET) == -1) {
+ fprintf(stderr, "%s: %s: fseek: ", my_name, filename);
+ perror(0);
+ return EXIT_FAILURE;
+ }
+ } else {
+ FILE *pipe = f;
+
+ f = tmpfile();
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open temporary file\n", my_name);
+ return EXIT_FAILURE;
+ }
+ file_size = 0;
+
+ while (true) {
+ static unsigned char buffer[4096];
+ size_t rc = fread(buffer, 1, 4096, pipe);
+ if (rc <= 0)
+ break;
+ size_t wc = fwrite(buffer, 1, rc, f);
+ if (wc != rc) {
+ fprintf(stderr, "%s: can't write to temporary file\n", my_name);
+ return EXIT_FAILURE;
+ }
+ file_size += rc;
+ }
+ fclose(pipe);
+
+ /* now seek to the beginning so we can
+ start reading again */
+ fseek(f, 0, SEEK_SET);
+ }
+ }
+ }
// ---------------------------------------------------------
// Initialize USB connection to FT2232H
@@ -438,12 +588,12 @@ 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();
+ 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 +601,30 @@ 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();
+ 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();
+ 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();
+ 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
@@ -532,27 +682,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);
@@ -588,13 +728,6 @@ int main(int argc, char **argv)
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)
@@ -605,16 +738,10 @@ int main(int argc, char **argv)
}
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);
+ 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) {
flash_write_enable();
@@ -630,65 +757,43 @@ 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();
+ error(3);
}
}
fprintf(stderr, "VERIFY OK\n");
-
- if (f != stdin)
- fclose(f);
}
@@ -704,6 +809,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 +823,3 @@ int main(int argc, char **argv)
ftdi_deinit(&ftdic);
return 0;
}
-
diff --git a/icetime/Makefile b/icetime/Makefile
index f30a42a..5e959c7 100644
--- a/icetime/Makefile
+++ b/icetime/Makefile
@@ -19,10 +19,10 @@ timings.inc: timings.py ../icefuzz/timings_*.txt
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp icetime $(DESTDIR)$(PREFIX)/bin/icetime
+ cp icetime$(EXE) $(DESTDIR)$(PREFIX)/bin/icetime$(EXE)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/icetime
+ rm -f $(DESTDIR)$(PREFIX)/bin/icetime$(EXE)
# View timing netlist: