summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2011-06-07 01:31:10 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2011-06-07 01:31:10 (GMT)
commitf3b69de7fe8b1634bb160c7f4646d7033d84e554 (patch)
tree17ad8f9928b7dca403742487cab8cbbd19decceb
parent9d7b6fe03c1a121aee32e2ac7e4627f212997d5e (diff)
downloadde1flash-f3b69de7fe8b1634bb160c7f4646d7033d84e554.zip
de1flash-f3b69de7fe8b1634bb160c7f4646d7033d84e554.tar.gz
de1flash-f3b69de7fe8b1634bb160c7f4646d7033d84e554.tar.bz2
de1flash-f3b69de7fe8b1634bb160c7f4646d7033d84e554.tar.xz
de1flash.tcl: implement the full intended feature set
Implement the full intended feature sets, driven by "filespecs", allowing specifying the ranges interested. The commands implemented are: read, write, writeonly, erase, eraseall. This still hard-codes the device geometry rather than using CFI.
-rw-r--r--de1flash.tcl173
1 files changed, 129 insertions, 44 deletions
diff --git a/de1flash.tcl b/de1flash.tcl
index ef7e062..feb983d 100644
--- a/de1flash.tcl
+++ b/de1flash.tcl
@@ -172,16 +172,12 @@ proc fl_erase addr {
}
# Read file
-proc fl_read_file { file size } {
+proc fl_read_file { file addr size } {
global fl_device_size
set f [open $file {WRONLY CREAT TRUNC BINARY}]
- if { $size < 0 || $size > $fl_device_size } {
- set size $fl_device_size
- }
- # XXX: obviously wrong...
- set addr 0
+ puts -nonewline [format "Reading file %s@0x%x,0x%x... " $file $addr $size]
# This is an arbitrary tunable, but at least for Quartus 11 is doesn't
# seem to get any better with a larger block size...
@@ -197,36 +193,16 @@ proc fl_read_file { file size } {
}
close $f
+ puts "done."
}
-# Erase a region
-proc fl_erase_range {addr size} {
- set xptr $addr
- set left $size
- while { $left > 0 } {
- set secleft [fl_sector_size $xptr]
- fl_erase $xptr
- set left [expr ($secleft >= $left) ? 0 : ($left - $secleft)]
- incr xptr $secleft
- }
-}
-
-# Write file
-proc fl_write_file { file size } {
+# Write file (without erase)
+proc fl_write_file { file addr size } {
set f [open $file {RDONLY BINARY}]
- set fsize [file size $file]
- if { $size < 0 || $fsize > $size } {
- set size $fsize
- }
-
- # XXX: obviously wrong...
- set addr 0
-
- # First, erase...
- fl_erase_range $addr $size
+ puts -nonewline [format "Writing file %s@0x%x,0x%x... " $file $addr $size]
- # Then, program
+ # Write data
set left $size
fl_send [format "C0%08X%08X" $addr 0]
while { $left > 0 } {
@@ -239,7 +215,7 @@ proc fl_write_file { file size } {
}
# Synchronize
- puts -nonewline "Sending sync... "
+ puts -nonewline "syncing... "
fl_send 6000000000AEAEAEAE
set v [fl_recv]
if { [string match $v [format "\[89ABCDEF\]6%08XAEAEAEAE" [expr $addr + $size]]] } {
@@ -251,18 +227,102 @@ proc fl_write_file { file size } {
close $f
}
-if {$argc < 1} {
- error "Usage: quartus_stp -t de1flash.tcl command"
+# Parse a list of filespecs
+proc fl_parse_files { mode files } {
+ set last_address 0
+ set file_list {}
+
+ foreach file $files {
+ regexp {^(.*?)(\@([0-9a-fA-FxX]+|)(,([0-9a-fA-FxX]+)|)|)$} $file \
+ junk0 filename junk1 address junk2 len
+ if { [string equal $address ""] } {
+ set address $last_address
+ }
+ if { [string match $len ""] } {
+ switch $mode {
+ read { set len [expr $fl_device_size - $address] }
+ write {
+ if { [string equal $filename ""] } {
+ set len [expr $fl_device_size - $address]
+ } else {
+ set len [file size $filename]
+ }
+ }
+ }
+ }
+
+ lappend $file_list [list $filename $address $len]
+ }
+
+ return $file_list
}
-set fl_cmd [lindex $argv 0]
-set fl_file [lindex $argv 1]
-if {$argc > 2} {
- set fl_size [lindex $argv 2]
-} else {
- set fl_size -1
+# Produce a list of erase blocks from a filespec list
+proc fl_get_eraseblocks flist {
+ set erase_list {}
+
+ foreach fspec $flist {
+ set addr [lindex $fspec 1]
+ set len [lindex $fspec 2]
+
+ set end [expr $addr + $len]
+
+ while { $addr < $len } {
+ set secsize [fl_sector_size $addr]
+ set secaddr [expr $addr & ~($secsize - 1)]
+
+ lappend erase_list $secaddr
+ set addr [expr $secaddr + $secsize]
+ }
+ }
+
+ return [lsort -integer -unique $erase_list]
}
+# Erase per filespec
+proc fl_erase_files flist {
+ foreach eb [fl_get_eraseblocks $flist] {
+ fl_erase $eb
+ }
+}
+
+# Read per filespec
+proc fl_read_files flist {
+ foreach fspec $flist {
+ set file [lindex $fspec 0]
+ set addr [lindex $fspec 1]
+ set len [lindex $fspec 2]
+
+ if { ![string equal $file ""] } {
+ fl_read_file $file $addr $len
+ }
+ }
+}
+
+# Write per filespec
+proc fl_write_files flist {
+ foreach fspec $flist {
+ set file [lindex $fspec 0]
+ set addr [lindex $fspec 1]
+ set len [lindex $fspec 2]
+
+ if { ![string equal $file ""] } {
+ fl_write_file $file $addr $len
+ }
+ }
+}
+
+# ---------------------------------------------------------------------------
+# Start of main program
+# ---------------------------------------------------------------------------
+
+if {$argc < 1} {
+ error "Usage: quartus_stp -t de1flash.tcl command [filespec...]"
+}
+
+set fl_cmd [lindex $argv 0]
+set fl_fspec [lrange $argv 1 end]
+
# List all available programming hardwares, and select the USBBlaster.
# (Note: this example assumes only one USBBlaster connected.)
puts "Programming Hardwares:"
@@ -293,10 +353,35 @@ device_lock -timeout 120000
fl_reset
switch $fl_cmd {
- write { fl_write_file $fl_file $fl_size }
- read { fl_read_file $fl_file $fl_size }
- eraseall { fl_erase_range 0 $fl_device_size }
- default { error "Unknown de1flash command" }
+ write
+ {
+ set fspec [fl_parse_files write $fl_fspec]
+ fl_erase_files $fspec
+ fl_write_files $fspec
+ }
+ writeonly
+ {
+ set fspec [fl_parse_files write $fl_fspec]
+ fl_write_files $fspec
+ }
+ erase
+ {
+ set fspec [fl_parse_files write $fl_fspec]
+ fl_erase_files $fspec
+ }
+ read
+ {
+ set fspec [fl_parse_files read $fl_fspec]
+ fl_read_files $fspec
+ }
+ eraseall
+ {
+ fl_erase_files [list [list "" 0 $fl_device_size]]
+ }
+ default
+ {
+ error "Unknown de1flash command"
+ }
}
device_unlock