Sun, 06 Mar 2011 21:04:06 +0000
Add Wesley Terpstra's GSI LM32 firmware loading tool.
> I've also attached my firmware loading tool. It needs quartus to work with Altera FPGAs, though.
tools/lm32-ctl | file | annotate | diff | revisions |
1.1 diff -r cc945f778cd7 -r 7483b57ce922 tools/lm32-ctl 1.2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 +++ b/tools/lm32-ctl Sun Mar 06 21:04:06 2011 +0000 1.4 @@ -0,0 +1,525 @@ 1.5 +#! /bin/bash 1.6 +# \ 1.7 +export RLWRAP_ #\ 1.8 +exec rlwrap -C lm32-ctl -I /opt/quartus/quartus/bin/quartus_stp --64bit -t "$0" "$@" 1.9 + 1.10 +########################### LOW LEVEL ACCESS ######################### 1.11 +proc jtag_put {val} { 1.12 + device_virtual_dr_shift -instance_index 0 -length 11 -dr_value "[format %03X $val]" -value_in_hex -no_captured_dr_value 1.13 +} 1.14 + 1.15 +proc jtag_get {} { 1.16 + return 0x[device_virtual_dr_shift -instance_index 0 -length 11 -dr_value 000 -value_in_hex] 1.17 +} 1.18 + 1.19 +############################ SAFE-ISHL ACCESS ######################### 1.20 + 1.21 +proc jtag_val {idx val} { 1.22 + set v [expr {($val << 3) | $idx}] 1.23 + jtag_put "$v" 1.24 +} 1.25 + 1.26 +proc jtag_cmd {idx cmd} { 1.27 + set val [expr {$cmd << 4}] 1.28 + jtag_val "$idx" "$val" 1.29 +} 1.30 + 1.31 +proc jtag_low {i} { 1.32 + set high 1 1.33 + while {$high >= 1} { 1.34 + set val [jtag_get] 1.35 + set high [expr {($val >> $i) & 1}] 1.36 + } 1.37 + return [expr {$val >> 3}] 1.38 +} 1.39 + 1.40 +proc jtag_high {i} { 1.41 + set high 0 1.42 + while {$high < 1} { 1.43 + set val [jtag_get] 1.44 + set high [expr {($val >> $i) & 1}] 1.45 + } 1.46 + return [expr {$val >> 3}] 1.47 +} 1.48 + 1.49 +############################## COMMANDS ############################### 1.50 + 1.51 +proc jtag_read_addr {addr} { 1.52 + jtag_cmd 0 1 1.53 + jtag_val 0 "[expr {($addr >> 24) & 0xff}]" 1.54 + jtag_val 0 "[expr {($addr >> 16) & 0xff}]" 1.55 + jtag_val 0 "[expr {($addr >> 8) & 0xff}]" 1.56 + jtag_val 0 "[expr {($addr >> 0) & 0xff}]" 1.57 + 1.58 + return [jtag_low 2] 1.59 +} 1.60 + 1.61 +proc jtag_read_next {} { 1.62 + jtag_cmd 0 3 1.63 + return [jtag_low 2] 1.64 +} 1.65 + 1.66 +proc jtag_read_memory {addr len} { 1.67 + set out [list] 1.68 + 1.69 + if {$len > 0} { 1.70 + lappend out "[format %02X [jtag_read_addr $addr]]" 1.71 + } 1.72 + 1.73 + for {set i 1} {$i < $len} {incr i} { 1.74 + #set x [expr {$addr+$i}] 1.75 + #lappend out "[format %02X [jtag_read_addr $x]]" 1.76 + lappend out "[format %02X [jtag_read_next]]" 1.77 + } 1.78 + return "$out" 1.79 +} 1.80 + 1.81 +proc jtag_write_addr {addr val} { 1.82 + jtag_cmd 0 2 1.83 + jtag_val 0 "[expr {($addr >> 24) & 0xff}]" 1.84 + jtag_val 0 "[expr {($addr >> 16) & 0xff}]" 1.85 + jtag_val 0 "[expr {($addr >> 8) & 0xff}]" 1.86 + jtag_val 0 "[expr {($addr >> 0) & 0xff}]" 1.87 + jtag_val 0 "$val" 1.88 + 1.89 + return [jtag_low 2] 1.90 +} 1.91 + 1.92 +proc jtag_write_next {val} { 1.93 + jtag_cmd 0 4 1.94 + jtag_val 0 "$val" 1.95 + return [jtag_low 2] 1.96 +} 1.97 + 1.98 +proc jtag_write_memory {addr data} { 1.99 + set first 1 1.100 + foreach j $data { 1.101 + if {$first == 1} { 1.102 + set first 0 1.103 + jtag_write_addr "$addr" "$j" 1.104 + } else { 1.105 + jtag_write_next "$j" 1.106 + } 1.107 + } 1.108 +} 1.109 + 1.110 +proc jtag_uart_write {val} { 1.111 + jtag_low 1 1.112 + jtag_val 1 "$val" 1.113 +} 1.114 + 1.115 +proc jtag_uart_read {} { 1.116 + set val [jtag_get] 1.117 + while {($val & 1) == 1} { 1.118 + jtag_val 2 0 1.119 + set val [jtag_get] 1.120 + set inb [expr {$val >> 3}] 1.121 + puts -nonewline "[format %02X $inb] " 1.122 + } 1.123 + puts "." 1.124 +} 1.125 + 1.126 +proc jtag_write_csr {csr val} { 1.127 + jtag_cmd 0 5 1.128 + jtag_val 0 "[expr {($val >> 24) & 0xff}]" 1.129 + jtag_val 0 "[expr {($val >> 16) & 0xff}]" 1.130 + jtag_val 0 "[expr {($val >> 8) & 0xff}]" 1.131 + jtag_val 0 "[expr {($val >> 0) & 0xff}]" 1.132 + jtag_val 0 "$csr" 1.133 + 1.134 + return [jtag_low 2] 1.135 +} 1.136 + 1.137 +proc jtag_break {} { 1.138 + jtag_cmd 0 6 1.139 +} 1.140 + 1.141 +proc jtag_reset {} { 1.142 + jtag_cmd 0 7 1.143 +} 1.144 + 1.145 +# Move back to idle state 1.146 +proc jtag_sync {} { 1.147 + for {set i 0} {$i < 10} {incr i} { 1.148 + jtag_cmd 0 0 1.149 + after 20 1.150 + } 1.151 +} 1.152 + 1.153 +################################# ASM ################################# 1.154 + 1.155 +proc opcode {val} { 1.156 + switch $val { 1.157 + 0 { return "srui" } 1.158 + 1 { return "nori" } 1.159 + 2 { return "muli" } 1.160 + 3 { return "sh" } 1.161 + 4 { return "lb" } 1.162 + 5 { return "sri" } 1.163 + 6 { return "xori" } 1.164 + 7 { return "lh" } 1.165 + 8 { return "andi" } 1.166 + 9 { return "xnori" } 1.167 + 10 { return "lw" } 1.168 + 11 { return "lhu" } 1.169 + 12 { return "sb" } 1.170 + 13 { return "addi" } 1.171 + 14 { return "ori" } 1.172 + 15 { return "sli" } 1.173 + 16 { return "lbu" } 1.174 + 17 { return "be" } 1.175 + 18 { return "bg" } 1.176 + 19 { return "bge" } 1.177 + 20 { return "bgeu" } 1.178 + 21 { return "bgu" } 1.179 + 22 { return "sw" } 1.180 + 23 { return "bne" } 1.181 + 24 { return "andhi" } 1.182 + 25 { return "cmpei" } 1.183 + 26 { return "cmpgi" } 1.184 + 27 { return "cmpgei" } 1.185 + 28 { return "cmpgeui" } 1.186 + 29 { return "cmpgui" } 1.187 + 30 { return "orhi" } 1.188 + 31 { return "cmpnei" } 1.189 + 32 { return "sru" } 1.190 + 33 { return "nor" } 1.191 + 34 { return "mul" } 1.192 + 35 { return "divu" } 1.193 + 36 { return "rcsr" } 1.194 + 37 { return "sr" } 1.195 + 38 { return "xor" } 1.196 + 39 { return "div" } 1.197 + 40 { return "and" } 1.198 + 41 { return "xnor" } 1.199 + 42 { return "??" } 1.200 + 43 { return "raise" } 1.201 + 44 { return "sextb" } 1.202 + 45 { return "add" } 1.203 + 46 { return "or" } 1.204 + 47 { return "sl" } 1.205 + 48 { return "b" } 1.206 + 49 { return "modu" } 1.207 + 50 { return "sub" } 1.208 + 51 { return "??" } 1.209 + 52 { return "wcsr" } 1.210 + 53 { return "mod" } 1.211 + 54 { return "call" } 1.212 + 55 { return "sexth" } 1.213 + 56 { return "bi" } 1.214 + 57 { return "cmpe" } 1.215 + 58 { return "cmpg" } 1.216 + 59 { return "cmpge" } 1.217 + 60 { return "cmpgeu" } 1.218 + 61 { return "cmpgu" } 1.219 + 62 { return "calli" } 1.220 + 63 { return "cmpne" } 1.221 + } 1.222 +} 1.223 + 1.224 +proc reg {i} { 1.225 + switch $i { 1.226 + 26 { return "gp" } 1.227 + 27 { return "fp" } 1.228 + 28 { return "sp" } 1.229 + 29 { return "ra" } 1.230 + 30 { return "ea" } 1.231 + 31 { return "ba" } 1.232 + default { return "r$i" } 1.233 + } 1.234 +} 1.235 + 1.236 +proc csr {i} { 1.237 + switch $i { 1.238 + 0 { return "IE" } 1.239 + 1 { return "IM" } 1.240 + 2 { return "IP" } 1.241 + 3 { return "ICC" } 1.242 + 4 { return "DCC" } 1.243 + 5 { return "CC" } 1.244 + 6 { return "CFG" } 1.245 + 7 { return "EBA" } 1.246 + 8 { return "DC" } 1.247 + 9 { return "DEBA" } 1.248 + 14 { return "JTX" } 1.249 + 15 { return "JRX" } 1.250 + 16 { return "BP0" } 1.251 + 17 { return "BP1" } 1.252 + 18 { return "BP2" } 1.253 + 19 { return "BP3" } 1.254 + 24 { return "WP0" } 1.255 + 25 { return "WP1" } 1.256 + 26 { return "WP2" } 1.257 + 27 { return "WP3" } 1.258 + } 1.259 +} 1.260 + 1.261 +proc imm16 {i} { 1.262 + if {$i >= 32768} { 1.263 + return "-[expr {65536 - $i}]" 1.264 + } else { 1.265 + return "+$i" 1.266 + } 1.267 +} 1.268 + 1.269 +proc imm26 {i} { 1.270 + if {$i >= 33554432} { 1.271 + return "-[expr {67108864 - $i}]" 1.272 + } else { 1.273 + return "+$i" 1.274 + } 1.275 +} 1.276 + 1.277 +proc opfmt {op} { 1.278 + set code [expr {$op >> 26}] 1.279 + set r0 [expr {($op >> 21) & 31}] 1.280 + set r1 [expr {($op >> 16) & 31}] 1.281 + set r2 [expr {($op >> 11) & 31}] 1.282 + set i16 [expr {$op & 0xffff}] 1.283 + set i26 [expr {$op & 0x3ffffff}] 1.284 + 1.285 + if {$code == 4 || $code == 7 || $code == 10 || $code == 11 || $code == 16} { 1.286 + # lb, lh, lw, lhu, lbu 1.287 + return "[opcode $code] [reg $r1], ([reg $r0][imm16 $i16])" 1.288 + } elseif {$code == 3 || $code == 12 || $code == 22} { # sh, sb, sw 1.289 + return "[opcode $code] ([reg $r0][imm16 $i16]), [reg $r1]" 1.290 + } elseif {$code <= 32} { # (op, op, imm) instruction 1.291 + return "[opcode $code] [reg $r1], [reg $r0], [imm16 $i16]" 1.292 + } elseif {$code == 48 || $code == 54} { # b, call 1.293 + return "[opcode $code] [reg $r0]" 1.294 + } elseif {$code == 36} { # rcsr 1.295 + return "[opcode $code] [reg $r2], [csr $r0]" 1.296 + } elseif {$code == 52} { # wcsr 1.297 + return "[opcode $code] [csr $r0], [reg $r1]" 1.298 + } elseif {$code == 56 || $code == 62 || $code == 43} { # bi, calli, raise 1.299 + return "[opcode $code] [imm26 $i26]" 1.300 + } elseif {$code == 44 || $code == 55} { # sextb, sexth 1.301 + return "[opcode $code] [reg $r2], [reg $r0]" 1.302 + } else { 1.303 + return "[opcode $code] [reg $r2], [reg $r1], [reg $r0]" 1.304 + } 1.305 +} 1.306 + 1.307 +################################ CMDS ################################# 1.308 + 1.309 +proc read_memory {addr len} { 1.310 + if {$addr == ""} {set addr 0} 1.311 + if {$len == ""} {set len 64} 1.312 + 1.313 + # Align read to 16-byte boundary 1.314 + set a_addr [expr {$addr & ~0xf}] 1.315 + set a_len [expr {($len + 15) & ~0xf}] 1.316 + 1.317 + set vals [jtag_read_memory $a_addr $a_len] 1.318 + 1.319 + for {set i 0} {$i < $a_len} {set i [expr {$i + 16}]} { 1.320 + puts -nonewline [format %08X: $a_addr] 1.321 + set a_addr [expr {$a_addr + 16}] 1.322 + for {set j 0} {$j < 4} {incr j} { 1.323 + set vals [lassign $vals b0 b1 b2 b3] 1.324 + puts -nonewline " $b0$b1$b2$b3" 1.325 + } 1.326 + puts "" 1.327 + } 1.328 + 1.329 + set nextcmd [list] 1.330 + lappend nextcmd "read" 1.331 + lappend nextcmd $a_addr 1.332 + lappend nextcmd $a_len 1.333 +} 1.334 + 1.335 +proc write_memory {addr val} { 1.336 + set data [list] 1.337 + lappend data [expr {($val >> 24) & 0xff}] 1.338 + lappend data [expr {($val >> 16) & 0xff}] 1.339 + lappend data [expr {($val >> 8) & 0xff}] 1.340 + lappend data [expr {($val >> 0) & 0xff}] 1.341 + jtag_write_memory $addr $data 1.342 +} 1.343 + 1.344 +proc dump_memory {addr len} { 1.345 + if {$addr == ""} {set addr 0} 1.346 + if {$len == ""} {set len 16} 1.347 + 1.348 + # Align read to 4-byte boundary 1.349 + set a_addr [expr {$addr & ~0x3}] 1.350 + set a_len [expr {$len * 4}] 1.351 + set a_end [expr {$a_addr + $a_len}] 1.352 + 1.353 + set vals [jtag_read_memory $a_addr $a_len] 1.354 + 1.355 + for {set a $a_addr} {$a < $a_end} {set a [expr {$a + 4}]} { 1.356 + set vals [lassign $vals b0 b1 b2 b3] 1.357 + puts "[format %08X $a]: [opfmt 0x$b0$b1$b2$b3]" 1.358 + } 1.359 + 1.360 + set nextcmd [list] 1.361 + lappend nextcmd "dump" 1.362 + lappend nextcmd [expr {$a_addr + $a_len}] 1.363 + lappend nextcmd [expr {$a_len / 4}] 1.364 +} 1.365 + 1.366 +proc send {data} { 1.367 + foreach j $data { 1.368 + jtag_uart_write $j 1.369 + } 1.370 +} 1.371 + 1.372 +proc transfer {prompt file offset len target} { 1.373 + set data [open $file] 1.374 + fconfigure $data -translation binary 1.375 + seek $data $offset 1.376 + 1.377 + set progress 0 1.378 + for {set done 0} {$done < $len} {set done [expr {$done+$did}]} { 1.379 + puts -nonewline "\r$prompt$done bytes" 1.380 + 1.381 + set rest [expr {$len - $done}] 1.382 + if {$rest > 100} { set do 100 } else { set do $rest } 1.383 + 1.384 + set bytes [read $data $do] 1.385 + set chunk [list] 1.386 + for {set i 0} {$i < $do} {incr i} { 1.387 + scan [string index $bytes $i] %c v 1.388 + lappend chunk $v 1.389 + } 1.390 + 1.391 + #puts "$chunk = [llength $chunk]" 1.392 + set did [llength $chunk] 1.393 + if {$did != $do} { 1.394 + puts "\n -- Short transfer error!" 1.395 + break 1.396 + } 1.397 + 1.398 + jtag_write_memory $target $chunk 1.399 + set target [expr {$target+$did}] 1.400 + } 1.401 + 1.402 + if {$done == $len} { 1.403 + puts "\r$prompt[format %d $len] bytes - complete" 1.404 + } 1.405 + 1.406 + close $data 1.407 +} 1.408 + 1.409 +proc load {file} { 1.410 + if {$file == ""} { 1.411 + puts "Specify file to load!" 1.412 + return 1.413 + } 1.414 + 1.415 + puts -nonewline "Capturing the CPU at address 0x0: " 1.416 + for {set i 0} {$i < 20} {incr i} { 1.417 + # bi +0 (CPU trap) 1.418 + write_memory 0x0 0xE0000000 1.419 + # flush instruction cache 1.420 + jtag_write_csr 0x3 0x0 1.421 + # Position CPU on this trap 1.422 + jtag_reset 1.423 + } 1.424 + # Wait a bit to be sure the CPU has the trap good and cached 1.425 + after 20 1.426 + puts "done" 1.427 + 1.428 + set sections [list] 1.429 + set sf [open "| readelf -S $file" "r"] 1.430 + while {[gets $sf line] >= 0} { 1.431 + if {[regexp {^\s+\[..\]\s+(\.\w+)\s+[^0-9a-f]*\s[0-9a-f]{4,}\s+([0-9a-f]{4,})\s+([0-9a-f]{4,})\s} $line nil section offset size] == 0} continue 1.432 + lappend sections "$section 0x$offset 0x$size" 1.433 + } 1.434 + close $sf 1.435 + 1.436 + # We can safely overwrite all of the instruction bus (even 0x0) now. 1.437 + # The trap is certainly cached and the CPU will not see the new values. 1.438 + set lf [open "| readelf -l $file" "r"] 1.439 + while {[gets $lf line] >= 0} { 1.440 + if {[regexp {^\s*LOAD\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+} $line nil offset vaddr paddr len] == 0} continue 1.441 + puts "Loading $offset+$len to $paddr" 1.442 + if {$paddr != $vaddr} { 1.443 + puts " Physical and virtual address mismatch! - Skipping" 1.444 + continue 1.445 + } 1.446 + foreach j $sections { 1.447 + lassign [split $j " "] section off size 1.448 + if {$offset <= $off && $off+$size <= $offset+$len} { 1.449 + transfer " section $section: " $file $off $size [expr {$paddr+$off-$offset}] 1.450 + } elseif {$offset <= $off && $off < $offset+$len} { 1.451 + puts " section $section: only half contained??" 1.452 + } 1.453 + } 1.454 + } 1.455 + close $lf 1.456 + 1.457 + # The CPU is spinning at address 0, so no need to reset it. 1.458 + # First flush the dcache and then release the CPU by flushing the icache 1.459 + puts -nonewline "Releasing CPU: " 1.460 + jtag_write_csr 0x4 0x0 1.461 + after 20 1.462 + jtag_write_csr 0x3 0x0 1.463 + puts done 1.464 +} 1.465 + 1.466 +################################ MAIN ################################# 1.467 + 1.468 + 1.469 +# List all available programming hardwares, and select the USBBlaster. 1.470 +# (Note: this example assumes only one USBBlaster connected.) 1.471 +puts "Programming Hardwares:" 1.472 +foreach hardware_name [get_hardware_names] { 1.473 + puts $hardware_name 1.474 + if { [string match "USB_Blaster*" $hardware_name] } { 1.475 + set usbblaster_name $hardware_name 1.476 + } 1.477 +} 1.478 +puts "\nSelect JTAG chain connected to $usbblaster_name.\n"; 1.479 + 1.480 +# List all devices on the chain, and select the first device on the chain. 1.481 +puts "\nDevices on the JTAG chain:" 1.482 +foreach device_name [get_device_names -hardware_name $usbblaster_name] { 1.483 + puts $device_name 1.484 + if { [string match "@1*" $device_name] } { 1.485 + set test_device $device_name 1.486 + } 1.487 +} 1.488 +puts "\nSelect device: $test_device.\n"; 1.489 + 1.490 +# Open device 1.491 +open_device -hardware_name $usbblaster_name -device_name $test_device 1.492 + 1.493 +device_lock -timeout 10000 1.494 +device_virtual_ir_shift -instance_index 0 -ir_value 1 -no_captured_ir_value 1.495 + 1.496 +jtag_sync 1.497 +while {$cmd != "quit"} { 1.498 + puts -nonewline "\nlm32> " 1.499 + 1.500 + if {[gets stdin line] < 0} break 1.501 + 1.502 + if {$line eq ""} { set line $nextcmd } 1.503 + 1.504 + set parts [split $line " "] 1.505 + set args [lassign $parts cmd] 1.506 + set tail [lassign $args arg1 arg2 arg3 arg4] 1.507 + 1.508 + set nextcmd "" 1.509 + switch $cmd { 1.510 + "" { } 1.511 + "break" { jtag_break } 1.512 + "reset" { jtag_reset } 1.513 + "sync" { jtag_sync } 1.514 + "read" { set nextcmd [read_memory $arg1 $arg2] } 1.515 + "dump" { set nextcmd [dump_memory $arg1 $arg2] } 1.516 + "write" { write_memory $arg1 $arg2 } 1.517 + "csr" { jtag_write_csr $arg1 $arg2 } 1.518 + "recv" { jtag_uart_read } 1.519 + "send" { send $args } 1.520 + "load" { load $arg1 } 1.521 + "quit" { } 1.522 + default { puts "Unknown command" } 1.523 + } 1.524 +} 1.525 + 1.526 +# Close device 1.527 +device_unlock 1.528 +puts "Bye!" 1.529 +close_device