From 1575d4f53805f177474b5bb96daebede9b2dfb73 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 24 Feb 2021 23:45:58 +0000 Subject: base --- de1/fpga-flash-nor/de1flash.tcl | 423 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 de1/fpga-flash-nor/de1flash.tcl (limited to 'de1/fpga-flash-nor/de1flash.tcl') diff --git a/de1/fpga-flash-nor/de1flash.tcl b/de1/fpga-flash-nor/de1flash.tcl new file mode 100644 index 0000000..5556e3b --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.tcl @@ -0,0 +1,423 @@ +## ----------------------------------------------------------------------- +## +## 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. +## +## ----------------------------------------------------------------------- + +# Virtual JTAG instance index +set fl_instance 0 +# Current IR value +set fl_current_ir -1 +# Known space in the write FIFO +set fl_free_space 0 + +# Device parameters which really should come from reading the CFI data +set fl_device_size 0x400000 +proc fl_sector_size addr { + expr ($addr < 65536) ? 8192 : 65536 +} + +proc select_ir new_ir { + global fl_instance fl_current_ir + if { $new_ir != $fl_current_ir } { + device_virtual_ir_shift -instance_index $fl_instance \ + -ir_value $new_ir -no_captured_ir_value + set fl_current_ir $new_ir + } +} + +# Send a command (given as a 72-bit hex string) +proc fl_send cmd { + global fl_instance fl_free_space + + while { $fl_free_space < 1 } { + # Poll the free space register until nonzero + select_ir 2 + scan [device_virtual_dr_shift -instance_index $fl_instance \ + -length 8 -value_in_hex] "%x" fl_free_space + } + + select_ir 3 + device_virtual_dr_shift -instance_index $fl_instance \ + -dr_value $cmd -length 72 -value_in_hex -no_captured_dr_value + incr fl_free_space -1 +} + +# Receive a reply (returned as a 72-bit hex string) +proc fl_recv {} { + global fl_instance + + set status 0 + + select_ir 1 + while { ($status & 0x80) == 0 } { + set v [device_virtual_dr_shift -instance_index $fl_instance \ + -length 72 -value_in_hex] + scan $v "%2x" status + } + return $v +} + +# Receive bulk data (returned as a binary string) +proc fl_recv_bulk bytes { + global fl_instance + + select_ir 1 + + set qwords [expr ($bytes + 7) >> 3] + set outdata "" + + while { $qwords } { + set d [device_virtual_dr_shift -instance_index $fl_instance \ + -length [expr $qwords * 72] -value_in_hex] + + # The LSW is the first transaction, so we need to process + # the returned string backwards + for { set n [expr $qwords - 1] } { $n >= 0 } { incr n -1 } { + set ix [expr $n * 18] + set di [string range $d $ix [expr $ix + 17]] + scan $di "%2x%2x%2x%2x%2x%2x%2x%2x%2x" st d7 d6 d5 d4 d3 d2 d1 d0 + if { $st & 0x80 } { + set bd [binary format cccccccc $d0 $d1 $d2 $d3 $d4 $d5 $d6 $d7] + set nbytes 8 + if { $bytes < 8 } { + set bd [string range $bd 0 [expr $bytes - 1]] + set nbytes $bytes + } + append outdata $bd + incr qwords -1 + set bytes [expr $bytes - $nbytes] + } else { + # puts "Dropping non-data: $di" + } + } + } + return $outdata +} + +# Reset state machine +proc fl_reset {} { + global fl_instance + + puts -nonewline "Issuing reset... " + + select_ir 5 + device_virtual_dr_shift -instance_index $fl_instance \ + -dr_value 1 -length 1 -no_captured_dr_value + + select_ir 4 + set rdy 0 + while { !$rdy } { + set rdy [device_virtual_dr_shift -instance_index $fl_instance -length 1] + } + + puts "done." +} + +# Sector erase +proc fl_erase addr { + set secsize [fl_sector_size $addr] + set secaddr [expr $addr & ~($secsize - 1)] + + puts -nonewline [format "Erasing sector at 0x%x(0x%x)... " $secaddr $secsize] + + # Blank check the sector before erasing + fl_send [format "50%08X%08X" $secaddr $secsize] + set zc [fl_recv] + set ze [format "\[89ABCDEF\]5%08XFFFFFFFF" [expr $secaddr + $secsize]] + + if { ![string match $ze $zc] } { + # puts "\nNot blank, expected $ze got $zc" + + fl_send 81AAAAAAAA000000AA + fl_send 815555555500000055 + fl_send 81AAAAAAAA00000080 + fl_send 81AAAAAAAA000000AA + fl_send 815555555500000055 + fl_send [format "81%08X00000030" $secaddr] + + set read_cmd [format "D0%08X%08X" $secaddr 8] + + set done 0 + while { !$done } { + fl_send $read_cmd + set v [fl_recv] + set done [string match {[89ABCDEF]DFFFFFFFFFFFFFFFF} $v] + } + puts "done." + } else { + puts "already blank." + } +} + +# Read file +proc fl_read_file { file addr size } { + set f [open $file {WRONLY CREAT TRUNC BINARY}] + + 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... + set max_block 4096 + + # Read data + set left $size + fl_send [format "D0%08X%08X" $addr $size] + while { $left > 0 } { + set blk [expr ($left < $max_block) ? $left : $max_block] + puts -nonewline $f [fl_recv_bulk $blk] + set left [expr $left - $blk] + } + + close $f + puts "done." +} + +# Write file (without erase) +proc fl_write_file { file addr size } { + set f [open $file {RDONLY BINARY}] + + puts -nonewline [format "Writing file %s@0x%x,0x%x... " $file $addr $size] + + # Write data + set left $size + fl_send [format "D0%08X%08X" $addr 0] + while { $left > 0 } { + set blk [expr ($left < 8) ? $left : 8] + set d [read $f $blk] + append d [string repeat "\xff" [expr 8 - $blk]] + binary scan $d H2H2H2H2H2H2H2H2 d0 d1 d2 d3 d4 d5 d6 d7 + fl_send [format "B%X%s%s%s%s%s%s%s%s" $blk $d7 $d6 $d5 $d4 $d3 $d2 $d1 $d0] + set left [expr $left - $blk] + } + + # Synchronize + puts -nonewline "syncing... " + fl_send 6000000000AEAEAEAE + set v [fl_recv] + if { [string match $v [format "\[89ABCDEF\]6%08XAEAEAEAE" [expr $addr + $size]]] } { + puts "error!" + } else { + puts "done." + } + + 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 + + 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 equal $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 +} + +# 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 < $end } { + 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 + } + } +} + +# 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 +# --------------------------------------------------------------------------- + +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:" +#foreach hardware_name [get_hardware_names] { +# puts $hardware_name +# if { [string match "USB-Blaster*" $hardware_name] } { +# set usbblaster_name $hardware_name +# } +#} + +set hardwares [get_hardware_names] +set usbblaster_name [lindex $hardwares 0] + +puts "\nUsing programming cable \{$usbblaster_name\}.\n"; + +# List all devices on the chain, and select the first device on the +# chain. +puts "\nDevices on the JTAG chain:" +foreach device_name [get_device_names -hardware_name $usbblaster_name] { + puts $device_name + if { [string match "@1*" $device_name] } { + set test_device $device_name + } +} +puts "\nSelecting device: \{$test_device\}.\n"; + +# Open device +open_device -hardware_name $usbblaster_name -device_name $test_device + +device_lock -timeout 120000 + +fl_reset + +switch $fl_cmd { + 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 + } + crc32 + { + set fspec [fl_parse_files write $fl_fspec] + fl_crc32_files $fspec + } + eraseall + { + fl_erase_files [list [list "" 0 $fl_device_size]] + } + default + { + error "Unknown de1flash command" + } +} + +device_unlock +close_device -- cgit v1.2.3