Merge branch 'master' into ice5k

This commit is contained in:
Clifford Wolf 2017-07-31 14:57:24 +02:00
commit 872e333cf7
18 changed files with 691 additions and 219 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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 $<

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

155
iceprog/iceprog.1 Normal file
View File

@ -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

View File

@ -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, "iceprog -- simple programming tool for FTDI-based Lattice iCE programmers\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, "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);
fwrite(buffer, read_size - addr > 256 ? 256 : read_size - addr, 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();
}
} 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;
}

View File

@ -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: