summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2011-08-01 00:31:23 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2011-08-01 00:31:23 (GMT)
commit1a884591c49cd39ab85cca7ac1b67405b05b19db (patch)
tree3ba54f5039c6c9a53fbb7fb5a81277d654835134
parent58cb650d586b305f4d5a1bf6630fc4755e3c1d63 (diff)
downloadde1flash-1a884591c49cd39ab85cca7ac1b67405b05b19db.zip
de1flash-1a884591c49cd39ab85cca7ac1b67405b05b19db.tar.gz
de1flash-1a884591c49cd39ab85cca7ac1b67405b05b19db.tar.bz2
de1flash-1a884591c49cd39ab85cca7ac1b67405b05b19db.tar.xz
Add the ability to do a CRC32 on an arbitrary flash region
Since reading over the Altera JTAG interface is so slow, give ourselves the ability to verify a particular region by getting a CRC32 of that region. This can be done extremely quickly (less than two seconds for the entire flash, including startup overhead) since it can be done entirely in hardware on the remote side. The CRC32 used is the same as used by the zip data format. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--crc32_d8.v96
-rw-r--r--de1flash.qsf1
-rw-r--r--de1flash.tcl30
-rw-r--r--de1flash.v92
-rw-r--r--protocol.txt18
5 files changed, 209 insertions, 28 deletions
diff --git a/crc32_d8.v b/crc32_d8.v
new file mode 100644
index 0000000..4721eb5
--- /dev/null
+++ b/crc32_d8.v
@@ -0,0 +1,96 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2011 H. Peter Anvin - All Rights Reserved
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom
+// the Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall
+// be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// -----------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 1999-2008 Easics NV.
+// This source file may be used and distributed without restriction
+// provided that this copyright statement is not removed from the file
+// and that any derivative work contains the original copyright notice
+// and the associated disclaimer.
+//
+// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Purpose : synthesizable CRC function
+// * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32)
+// * data width: 8
+//
+// Info : tools@easics.be
+// http://www.easics.com
+////////////////////////////////////////////////////////////////////////////////
+
+module crc_32_d8 (
+ input [ 7:0] data,
+ input [31:0] in,
+ output [31:0] out
+ );
+
+ // Note the bit ordering and the polarity of the inputs and outputs...
+ wire [0: 7] d = data;
+ wire [0:31] c = ~in;
+ reg [0:31] newcrc;
+
+ assign out = ~newcrc;
+
+ always @(d, c)
+ begin
+ newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
+ newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
+ newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
+ newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
+ newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
+ newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
+ newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
+ newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
+ newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
+ newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
+ newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
+ newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
+ newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
+ newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
+ newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
+ newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
+ newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
+ newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
+ newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
+ newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
+ newcrc[20] = d[4] ^ c[12] ^ c[28];
+ newcrc[21] = d[5] ^ c[13] ^ c[29];
+ newcrc[22] = d[0] ^ c[14] ^ c[24];
+ newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
+ newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
+ newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
+ newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
+ newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
+ newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
+ newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
+ newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
+ newcrc[31] = d[5] ^ c[23] ^ c[29];
+ end // always @ (d, c)
+
+endmodule // crc_32_d8
diff --git a/de1flash.qsf b/de1flash.qsf
index f1bbf50..f99a854 100644
--- a/de1flash.qsf
+++ b/de1flash.qsf
@@ -338,6 +338,7 @@ set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS R
set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
+set_global_assignment -name VERILOG_FILE crc32_d8.v
set_global_assignment -name VERILOG_FILE hexled.v
set_global_assignment -name VERILOG_FILE de1flash.v
set_global_assignment -name QIP_FILE vjtag_mega.qip
diff --git a/de1flash.tcl b/de1flash.tcl
index 45c5d11..8af5318 100644
--- a/de1flash.tcl
+++ b/de1flash.tcl
@@ -202,7 +202,7 @@ proc fl_write_file { file addr size } {
# Write data
set left $size
- fl_send [format "C0%08X%08X" $addr 0]
+ fl_send [format "D0%08X%08X" $addr 0]
while { $left > 0 } {
set blk [expr ($left < 8) ? $left : 8]
set d [read $f $blk]
@@ -225,6 +225,18 @@ proc fl_write_file { file addr size } {
close $f
}
+# Checksum (CRC32) a region
+proc fl_crc32_file { file addr size } {
+ fl_send [format "70%08X%08X" $addr $size]
+ set v [fl_recv]
+ scan $v "%1x%1x%8x%8x" ctr type end crc
+ if { $type != 7 || $end != $addr + $size } {
+ puts "$file: checksumming failure"
+ } else {
+ puts [format "%08x %s@0x%x,0x%x" $crc $file $addr $size]
+ }
+}
+
# Parse a list of filespecs
proc fl_parse_files { mode files } {
global fl_device_size
@@ -315,6 +327,17 @@ proc fl_write_files flist {
}
}
+# Checksum per filespec
+proc fl_crc32_files flist {
+ foreach fspec $flist {
+ set file [lindex $fspec 0]
+ set addr [lindex $fspec 1]
+ set len [lindex $fspec 2]
+
+ fl_crc32_file $file $addr $len
+ }
+}
+
# ---------------------------------------------------------------------------
# Start of main program
# ---------------------------------------------------------------------------
@@ -377,6 +400,11 @@ switch $fl_cmd {
set fspec [fl_parse_files read $fl_fspec]
fl_read_files $fspec
}
+ crc32
+ {
+ set fspec [fl_parse_files write $fl_fspec]
+ fl_crc32_files $fspec
+ }
eraseall
{
fl_erase_files [list [list "" 0 $fl_device_size]]
diff --git a/de1flash.v b/de1flash.v
index a1de450..57cd5ec 100644
--- a/de1flash.v
+++ b/de1flash.v
@@ -311,7 +311,6 @@ module de1flash (
reg [31:0] fl_bytectr; // Byte counter
reg [ 2:0] fl_rbctr; // Read bytes in shift register
reg [ 3:0] fl_rbcmd; // Command code
- reg fl_incaddr; // Increment between bytes
reg [31:0] fl_addr;
reg fl_ce_q;
@@ -338,9 +337,12 @@ module de1flash (
parameter pst_readpad = 5'h07;
parameter pst_write0 = 5'h08;
parameter pst_write1 = 5'h09;
- parameter pst_zchk0 = 5'h0C;
- parameter pst_zchk1 = 5'h0D;
- parameter pst_zchk2 = 5'h0E;
+ parameter pst_zchk0 = 5'h0A;
+ parameter pst_zchk1 = 5'h0B;
+ parameter pst_zchk2 = 5'h0C;
+ parameter pst_crc0 = 5'h0D;
+ parameter pst_crc1 = 5'h0E;
+ parameter pst_crc2 = 5'h0F;
parameter pst_program0 = 5'h10;
parameter pst_program1 = 5'h11;
parameter pst_program2 = 5'h12;
@@ -433,10 +435,20 @@ module de1flash (
wire bump_addr =
(prog_state == pst_read2) |
(prog_state == pst_zchk2) |
+ (prog_state == pst_crc2) |
(prog_state == pst_write1) |
((prog_state == pst_program3) & ~|(tst_data & ~fl_data[7:0])) |
((prog_state == pst_program14) & (tst_data == pgm_data));
+ wire [31:0] tst_crc;
+ crc_32_d8 crcgen
+ (
+ .data ( tst_data ),
+ .in ( fl_data[31:0] ),
+ .out ( tst_crc )
+ );
+ reg bump_crc;
+
always @(negedge fl_reset_n or posedge fl_clk)
if (~fl_reset_n)
begin
@@ -452,10 +464,10 @@ module de1flash (
fl_bytectr <= 32'h0;
fl_rbctr <= 3'h0;
fl_rbcmd <= 4'bx;
- fl_incaddr <= 1'b0;
prog_state <= pst_idle;
rd_ack <= 1'b0;
+ bump_crc <= 1'b0;
pgm_data <= 8'hxx;
tst_data <= 8'hff;
@@ -468,9 +480,9 @@ module de1flash (
fl_d_en <= 1'b0;
rd_ack <= 1'b0;
+ bump_crc <= 1'b0;
- if ( bump_addr )
- fl_addr <= fl_addr + fl_incaddr;
+ fl_addr <= fl_addr + bump_addr;
case ( prog_state )
pst_idle:
@@ -480,42 +492,46 @@ module de1flash (
tst_data <= 8'hff;
if ( ~prog_wr_empty )
- case ( prog_wr_q[71:69] )
- 3'b001: // Delay command
+ casez ( prog_wr_q[71:68] )
+ 4'b0010: // Delay command
begin
fl_bytectr <= prog_wr_q[31:0];
prog_state <= pst_delay;
end
- 3'b010: // Zero check
+ 4'b0101: // Zero check
begin
- fl_incaddr <= prog_wr_q[68];
fl_addr <= prog_wr_q[63:32];
fl_bytectr <= prog_wr_q[31:0];
prog_state <= pst_zchk0;
end
- 3'b011: // Read back address, token
+ 4'b0110: // Read back address, token
begin
fl_data <= { fl_addr, prog_wr_q[31:0] };
prog_state <= pst_status;
end
- 3'b100: // Write bytes command
+ 4'b0111: // CRC32
+ begin
+ fl_addr <= prog_wr_q[63:32];
+ fl_bytectr <= prog_wr_q[31:0];
+ fl_data[63:32] <= 32'hxxxxxxxx;
+ fl_data[31: 0] <= 32'h00000000;
+ prog_state <= pst_crc0;
+ end
+ 4'b100z: // Write bytes command
begin
- fl_incaddr <= prog_wr_q[68];
fl_data <= prog_wr_q[63:0];
if ( prog_wr_q[68] )
fl_addr <= prog_wr_q[63:32];
prog_state <= pst_write0;
end
- 3'b101: // Program bytes command
+ 4'b1011: // Program bytes command
begin
- fl_incaddr <= prog_wr_q[68];
fl_bytectr <= { 28'b0, prog_wr_q[67:64] };
fl_data <= prog_wr_q[63:0];
prog_state <= pst_program0;
end
- 3'b110: // Set address register/read command
+ 4'b1101: // Set address register/read command
begin
- fl_incaddr <= prog_wr_q[68];
fl_addr <= prog_wr_q[63:32];
fl_bytectr <= prog_wr_q[31:0];
prog_state <= pst_read0;
@@ -588,11 +604,13 @@ module de1flash (
pst_zchk0: // Zero check
begin
- fl_a_q <= fl_addr;
+ fl_a_q <= fl_addr;
if ( (&tst_data) & (|fl_bytectr) )
begin
fl_ce_q <= 1'b1;
fl_oe_q <= 1'b1;
+ fl_data[63:32] <= 32'hxxxxxxxx;
+ fl_data[31: 0] <= 32'hxxxxxxxx;
prog_state <= pst_zchk1;
end
else if ( ~prog_rd_full )
@@ -620,6 +638,42 @@ module de1flash (
prog_state <= pst_zchk0;
end
+ pst_crc0: // CRC32
+ begin
+ fl_a_q <= fl_addr;
+ if ( bump_crc )
+ fl_data[31: 0] <= tst_crc;
+ if ( |fl_bytectr )
+ begin
+ fl_ce_q <= 1'b1;
+ fl_oe_q <= 1'b1;
+ fl_data[63:32] <= 32'hxxxxxxxx;
+ prog_state <= pst_crc1;
+ end
+ else if ( ~prog_rd_full )
+ begin
+ fl_data[63:32] <= fl_addr;
+ rd_ack <= 1'b1;
+ prog_state <= pst_idle;
+ end // else: !if( |fl_bytectr )
+ end // case: pst_crc0
+
+ pst_crc1:
+ begin
+ fl_ce_q <= 1'b1;
+ fl_oe_q <= 1'b1;
+ prog_state <= pst_crc2;
+ end
+
+ pst_crc2:
+ begin
+ fl_ce_q <= 1'b1;
+ tst_data <= fl_dq;
+ fl_bytectr <= fl_bytectr - 1'b1;
+ bump_crc <= 1'b1;
+ prog_state <= pst_crc0;
+ end
+
pst_write0:
begin
fl_ce_q <= 1'b1;
diff --git a/protocol.txt b/protocol.txt
index 892b21d..d7a1968 100644
--- a/protocol.txt
+++ b/protocol.txt
@@ -31,30 +31,32 @@ WRITE FIFO
72 bits:
-binary- -------hex-------
+
000XXXXX XXXXXXXX XXXXXXXX - noop
-001XXXXX XXXXXXXX CCCCCCCC - delay for C cycles @ 20 MHz
+0010XXXX XXXXXXXX CCCCCCCC - delay for C cycles @ 20 MHz
-010IXXXX AAAAAAAA CCCCCCCC - zero check
+0101XXXX AAAAAAAA CCCCCCCC - zero check
Returns last address read in [63:32]
Returns last datum 1's extended in [31:0] - FFFFFFFF on success
-011XXXXX XXXXXXXX TTTTTTTT - read back address register, token
+0110XXXX XXXXXXXX TTTTTTTT - read back address register, token
Returns address register in [63:32]
Returns token in [31:0]
+0111XXXX AAAAAAAA CCCCCCCC - compute CRC32
+ Returns last address read in [63:32]
+ Returns Ethernet CRC32 of the region in [31:0]
+
100SEEEE AAAAAAAA DDDDDDDD - write cycle (address, data)
address register set to A if S=1
E is byte enables; for a byte flash
E should be set to 0001
-101ICCCC DDDDDDDD DDDDDDDD - program bytes (C = byte count)
- address register incremented if I=1
- (this should always be the case)
+1011CCCC DDDDDDDD DDDDDDDD - program bytes (C = byte count)
-110IXXXX AAAAAAAA CCCCCCCC - set address register to A
+1101XXXX AAAAAAAA CCCCCCCC - set address register to A
read C bytes (pad output to 64 bits)
- address register incremented if I=1
if C=0 no read is done
111XXXXX XXXXXXXX XXXXXXXX - noop