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