diff options
-rw-r--r-- | config.mk | 4 | ||||
-rw-r--r-- | docs/index.html | 1 | ||||
-rw-r--r-- | docs/io_tile.html | 10 | ||||
-rw-r--r-- | examples/icestick/.gitignore | 14 | ||||
-rw-r--r-- | examples/icestick/Makefile | 16 | ||||
-rw-r--r-- | examples/icestick/checker.v | 55 | ||||
-rw-r--r-- | examples/icestick/checker_tb.v | 40 | ||||
-rw-r--r-- | examples/icestick/rs232demo.v | 8 | ||||
-rw-r--r-- | examples/icestick/rs232demo_tb.v | 74 | ||||
-rw-r--r-- | icebox/Makefile | 32 | ||||
-rw-r--r-- | icebram/Makefile | 4 | ||||
-rw-r--r-- | icemulti/Makefile | 4 | ||||
-rw-r--r-- | icepack/Makefile | 8 | ||||
-rw-r--r-- | icepll/Makefile | 4 | ||||
-rw-r--r-- | iceprog/Makefile | 7 | ||||
-rw-r--r-- | iceprog/iceprog.1 | 155 | ||||
-rw-r--r-- | iceprog/iceprog.c | 470 | ||||
-rw-r--r-- | icetime/Makefile | 4 |
18 files changed, 691 insertions, 219 deletions
@@ -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: |