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.
philpem@19 | 1 | #! /bin/bash |
philpem@19 | 2 | # \ |
philpem@19 | 3 | export RLWRAP_ #\ |
philpem@19 | 4 | exec rlwrap -C lm32-ctl -I /opt/quartus/quartus/bin/quartus_stp --64bit -t "$0" "$@" |
philpem@19 | 5 | |
philpem@19 | 6 | ########################### LOW LEVEL ACCESS ######################### |
philpem@19 | 7 | proc jtag_put {val} { |
philpem@19 | 8 | device_virtual_dr_shift -instance_index 0 -length 11 -dr_value "[format %03X $val]" -value_in_hex -no_captured_dr_value |
philpem@19 | 9 | } |
philpem@19 | 10 | |
philpem@19 | 11 | proc jtag_get {} { |
philpem@19 | 12 | return 0x[device_virtual_dr_shift -instance_index 0 -length 11 -dr_value 000 -value_in_hex] |
philpem@19 | 13 | } |
philpem@19 | 14 | |
philpem@19 | 15 | ############################ SAFE-ISHL ACCESS ######################### |
philpem@19 | 16 | |
philpem@19 | 17 | proc jtag_val {idx val} { |
philpem@19 | 18 | set v [expr {($val << 3) | $idx}] |
philpem@19 | 19 | jtag_put "$v" |
philpem@19 | 20 | } |
philpem@19 | 21 | |
philpem@19 | 22 | proc jtag_cmd {idx cmd} { |
philpem@19 | 23 | set val [expr {$cmd << 4}] |
philpem@19 | 24 | jtag_val "$idx" "$val" |
philpem@19 | 25 | } |
philpem@19 | 26 | |
philpem@19 | 27 | proc jtag_low {i} { |
philpem@19 | 28 | set high 1 |
philpem@19 | 29 | while {$high >= 1} { |
philpem@19 | 30 | set val [jtag_get] |
philpem@19 | 31 | set high [expr {($val >> $i) & 1}] |
philpem@19 | 32 | } |
philpem@19 | 33 | return [expr {$val >> 3}] |
philpem@19 | 34 | } |
philpem@19 | 35 | |
philpem@19 | 36 | proc jtag_high {i} { |
philpem@19 | 37 | set high 0 |
philpem@19 | 38 | while {$high < 1} { |
philpem@19 | 39 | set val [jtag_get] |
philpem@19 | 40 | set high [expr {($val >> $i) & 1}] |
philpem@19 | 41 | } |
philpem@19 | 42 | return [expr {$val >> 3}] |
philpem@19 | 43 | } |
philpem@19 | 44 | |
philpem@19 | 45 | ############################## COMMANDS ############################### |
philpem@19 | 46 | |
philpem@19 | 47 | proc jtag_read_addr {addr} { |
philpem@19 | 48 | jtag_cmd 0 1 |
philpem@19 | 49 | jtag_val 0 "[expr {($addr >> 24) & 0xff}]" |
philpem@19 | 50 | jtag_val 0 "[expr {($addr >> 16) & 0xff}]" |
philpem@19 | 51 | jtag_val 0 "[expr {($addr >> 8) & 0xff}]" |
philpem@19 | 52 | jtag_val 0 "[expr {($addr >> 0) & 0xff}]" |
philpem@19 | 53 | |
philpem@19 | 54 | return [jtag_low 2] |
philpem@19 | 55 | } |
philpem@19 | 56 | |
philpem@19 | 57 | proc jtag_read_next {} { |
philpem@19 | 58 | jtag_cmd 0 3 |
philpem@19 | 59 | return [jtag_low 2] |
philpem@19 | 60 | } |
philpem@19 | 61 | |
philpem@19 | 62 | proc jtag_read_memory {addr len} { |
philpem@19 | 63 | set out [list] |
philpem@19 | 64 | |
philpem@19 | 65 | if {$len > 0} { |
philpem@19 | 66 | lappend out "[format %02X [jtag_read_addr $addr]]" |
philpem@19 | 67 | } |
philpem@19 | 68 | |
philpem@19 | 69 | for {set i 1} {$i < $len} {incr i} { |
philpem@19 | 70 | #set x [expr {$addr+$i}] |
philpem@19 | 71 | #lappend out "[format %02X [jtag_read_addr $x]]" |
philpem@19 | 72 | lappend out "[format %02X [jtag_read_next]]" |
philpem@19 | 73 | } |
philpem@19 | 74 | return "$out" |
philpem@19 | 75 | } |
philpem@19 | 76 | |
philpem@19 | 77 | proc jtag_write_addr {addr val} { |
philpem@19 | 78 | jtag_cmd 0 2 |
philpem@19 | 79 | jtag_val 0 "[expr {($addr >> 24) & 0xff}]" |
philpem@19 | 80 | jtag_val 0 "[expr {($addr >> 16) & 0xff}]" |
philpem@19 | 81 | jtag_val 0 "[expr {($addr >> 8) & 0xff}]" |
philpem@19 | 82 | jtag_val 0 "[expr {($addr >> 0) & 0xff}]" |
philpem@19 | 83 | jtag_val 0 "$val" |
philpem@19 | 84 | |
philpem@19 | 85 | return [jtag_low 2] |
philpem@19 | 86 | } |
philpem@19 | 87 | |
philpem@19 | 88 | proc jtag_write_next {val} { |
philpem@19 | 89 | jtag_cmd 0 4 |
philpem@19 | 90 | jtag_val 0 "$val" |
philpem@19 | 91 | return [jtag_low 2] |
philpem@19 | 92 | } |
philpem@19 | 93 | |
philpem@19 | 94 | proc jtag_write_memory {addr data} { |
philpem@19 | 95 | set first 1 |
philpem@19 | 96 | foreach j $data { |
philpem@19 | 97 | if {$first == 1} { |
philpem@19 | 98 | set first 0 |
philpem@19 | 99 | jtag_write_addr "$addr" "$j" |
philpem@19 | 100 | } else { |
philpem@19 | 101 | jtag_write_next "$j" |
philpem@19 | 102 | } |
philpem@19 | 103 | } |
philpem@19 | 104 | } |
philpem@19 | 105 | |
philpem@19 | 106 | proc jtag_uart_write {val} { |
philpem@19 | 107 | jtag_low 1 |
philpem@19 | 108 | jtag_val 1 "$val" |
philpem@19 | 109 | } |
philpem@19 | 110 | |
philpem@19 | 111 | proc jtag_uart_read {} { |
philpem@19 | 112 | set val [jtag_get] |
philpem@19 | 113 | while {($val & 1) == 1} { |
philpem@19 | 114 | jtag_val 2 0 |
philpem@19 | 115 | set val [jtag_get] |
philpem@19 | 116 | set inb [expr {$val >> 3}] |
philpem@19 | 117 | puts -nonewline "[format %02X $inb] " |
philpem@19 | 118 | } |
philpem@19 | 119 | puts "." |
philpem@19 | 120 | } |
philpem@19 | 121 | |
philpem@19 | 122 | proc jtag_write_csr {csr val} { |
philpem@19 | 123 | jtag_cmd 0 5 |
philpem@19 | 124 | jtag_val 0 "[expr {($val >> 24) & 0xff}]" |
philpem@19 | 125 | jtag_val 0 "[expr {($val >> 16) & 0xff}]" |
philpem@19 | 126 | jtag_val 0 "[expr {($val >> 8) & 0xff}]" |
philpem@19 | 127 | jtag_val 0 "[expr {($val >> 0) & 0xff}]" |
philpem@19 | 128 | jtag_val 0 "$csr" |
philpem@19 | 129 | |
philpem@19 | 130 | return [jtag_low 2] |
philpem@19 | 131 | } |
philpem@19 | 132 | |
philpem@19 | 133 | proc jtag_break {} { |
philpem@19 | 134 | jtag_cmd 0 6 |
philpem@19 | 135 | } |
philpem@19 | 136 | |
philpem@19 | 137 | proc jtag_reset {} { |
philpem@19 | 138 | jtag_cmd 0 7 |
philpem@19 | 139 | } |
philpem@19 | 140 | |
philpem@19 | 141 | # Move back to idle state |
philpem@19 | 142 | proc jtag_sync {} { |
philpem@19 | 143 | for {set i 0} {$i < 10} {incr i} { |
philpem@19 | 144 | jtag_cmd 0 0 |
philpem@19 | 145 | after 20 |
philpem@19 | 146 | } |
philpem@19 | 147 | } |
philpem@19 | 148 | |
philpem@19 | 149 | ################################# ASM ################################# |
philpem@19 | 150 | |
philpem@19 | 151 | proc opcode {val} { |
philpem@19 | 152 | switch $val { |
philpem@19 | 153 | 0 { return "srui" } |
philpem@19 | 154 | 1 { return "nori" } |
philpem@19 | 155 | 2 { return "muli" } |
philpem@19 | 156 | 3 { return "sh" } |
philpem@19 | 157 | 4 { return "lb" } |
philpem@19 | 158 | 5 { return "sri" } |
philpem@19 | 159 | 6 { return "xori" } |
philpem@19 | 160 | 7 { return "lh" } |
philpem@19 | 161 | 8 { return "andi" } |
philpem@19 | 162 | 9 { return "xnori" } |
philpem@19 | 163 | 10 { return "lw" } |
philpem@19 | 164 | 11 { return "lhu" } |
philpem@19 | 165 | 12 { return "sb" } |
philpem@19 | 166 | 13 { return "addi" } |
philpem@19 | 167 | 14 { return "ori" } |
philpem@19 | 168 | 15 { return "sli" } |
philpem@19 | 169 | 16 { return "lbu" } |
philpem@19 | 170 | 17 { return "be" } |
philpem@19 | 171 | 18 { return "bg" } |
philpem@19 | 172 | 19 { return "bge" } |
philpem@19 | 173 | 20 { return "bgeu" } |
philpem@19 | 174 | 21 { return "bgu" } |
philpem@19 | 175 | 22 { return "sw" } |
philpem@19 | 176 | 23 { return "bne" } |
philpem@19 | 177 | 24 { return "andhi" } |
philpem@19 | 178 | 25 { return "cmpei" } |
philpem@19 | 179 | 26 { return "cmpgi" } |
philpem@19 | 180 | 27 { return "cmpgei" } |
philpem@19 | 181 | 28 { return "cmpgeui" } |
philpem@19 | 182 | 29 { return "cmpgui" } |
philpem@19 | 183 | 30 { return "orhi" } |
philpem@19 | 184 | 31 { return "cmpnei" } |
philpem@19 | 185 | 32 { return "sru" } |
philpem@19 | 186 | 33 { return "nor" } |
philpem@19 | 187 | 34 { return "mul" } |
philpem@19 | 188 | 35 { return "divu" } |
philpem@19 | 189 | 36 { return "rcsr" } |
philpem@19 | 190 | 37 { return "sr" } |
philpem@19 | 191 | 38 { return "xor" } |
philpem@19 | 192 | 39 { return "div" } |
philpem@19 | 193 | 40 { return "and" } |
philpem@19 | 194 | 41 { return "xnor" } |
philpem@19 | 195 | 42 { return "??" } |
philpem@19 | 196 | 43 { return "raise" } |
philpem@19 | 197 | 44 { return "sextb" } |
philpem@19 | 198 | 45 { return "add" } |
philpem@19 | 199 | 46 { return "or" } |
philpem@19 | 200 | 47 { return "sl" } |
philpem@19 | 201 | 48 { return "b" } |
philpem@19 | 202 | 49 { return "modu" } |
philpem@19 | 203 | 50 { return "sub" } |
philpem@19 | 204 | 51 { return "??" } |
philpem@19 | 205 | 52 { return "wcsr" } |
philpem@19 | 206 | 53 { return "mod" } |
philpem@19 | 207 | 54 { return "call" } |
philpem@19 | 208 | 55 { return "sexth" } |
philpem@19 | 209 | 56 { return "bi" } |
philpem@19 | 210 | 57 { return "cmpe" } |
philpem@19 | 211 | 58 { return "cmpg" } |
philpem@19 | 212 | 59 { return "cmpge" } |
philpem@19 | 213 | 60 { return "cmpgeu" } |
philpem@19 | 214 | 61 { return "cmpgu" } |
philpem@19 | 215 | 62 { return "calli" } |
philpem@19 | 216 | 63 { return "cmpne" } |
philpem@19 | 217 | } |
philpem@19 | 218 | } |
philpem@19 | 219 | |
philpem@19 | 220 | proc reg {i} { |
philpem@19 | 221 | switch $i { |
philpem@19 | 222 | 26 { return "gp" } |
philpem@19 | 223 | 27 { return "fp" } |
philpem@19 | 224 | 28 { return "sp" } |
philpem@19 | 225 | 29 { return "ra" } |
philpem@19 | 226 | 30 { return "ea" } |
philpem@19 | 227 | 31 { return "ba" } |
philpem@19 | 228 | default { return "r$i" } |
philpem@19 | 229 | } |
philpem@19 | 230 | } |
philpem@19 | 231 | |
philpem@19 | 232 | proc csr {i} { |
philpem@19 | 233 | switch $i { |
philpem@19 | 234 | 0 { return "IE" } |
philpem@19 | 235 | 1 { return "IM" } |
philpem@19 | 236 | 2 { return "IP" } |
philpem@19 | 237 | 3 { return "ICC" } |
philpem@19 | 238 | 4 { return "DCC" } |
philpem@19 | 239 | 5 { return "CC" } |
philpem@19 | 240 | 6 { return "CFG" } |
philpem@19 | 241 | 7 { return "EBA" } |
philpem@19 | 242 | 8 { return "DC" } |
philpem@19 | 243 | 9 { return "DEBA" } |
philpem@19 | 244 | 14 { return "JTX" } |
philpem@19 | 245 | 15 { return "JRX" } |
philpem@19 | 246 | 16 { return "BP0" } |
philpem@19 | 247 | 17 { return "BP1" } |
philpem@19 | 248 | 18 { return "BP2" } |
philpem@19 | 249 | 19 { return "BP3" } |
philpem@19 | 250 | 24 { return "WP0" } |
philpem@19 | 251 | 25 { return "WP1" } |
philpem@19 | 252 | 26 { return "WP2" } |
philpem@19 | 253 | 27 { return "WP3" } |
philpem@19 | 254 | } |
philpem@19 | 255 | } |
philpem@19 | 256 | |
philpem@19 | 257 | proc imm16 {i} { |
philpem@19 | 258 | if {$i >= 32768} { |
philpem@19 | 259 | return "-[expr {65536 - $i}]" |
philpem@19 | 260 | } else { |
philpem@19 | 261 | return "+$i" |
philpem@19 | 262 | } |
philpem@19 | 263 | } |
philpem@19 | 264 | |
philpem@19 | 265 | proc imm26 {i} { |
philpem@19 | 266 | if {$i >= 33554432} { |
philpem@19 | 267 | return "-[expr {67108864 - $i}]" |
philpem@19 | 268 | } else { |
philpem@19 | 269 | return "+$i" |
philpem@19 | 270 | } |
philpem@19 | 271 | } |
philpem@19 | 272 | |
philpem@19 | 273 | proc opfmt {op} { |
philpem@19 | 274 | set code [expr {$op >> 26}] |
philpem@19 | 275 | set r0 [expr {($op >> 21) & 31}] |
philpem@19 | 276 | set r1 [expr {($op >> 16) & 31}] |
philpem@19 | 277 | set r2 [expr {($op >> 11) & 31}] |
philpem@19 | 278 | set i16 [expr {$op & 0xffff}] |
philpem@19 | 279 | set i26 [expr {$op & 0x3ffffff}] |
philpem@19 | 280 | |
philpem@19 | 281 | if {$code == 4 || $code == 7 || $code == 10 || $code == 11 || $code == 16} { |
philpem@19 | 282 | # lb, lh, lw, lhu, lbu |
philpem@19 | 283 | return "[opcode $code] [reg $r1], ([reg $r0][imm16 $i16])" |
philpem@19 | 284 | } elseif {$code == 3 || $code == 12 || $code == 22} { # sh, sb, sw |
philpem@19 | 285 | return "[opcode $code] ([reg $r0][imm16 $i16]), [reg $r1]" |
philpem@19 | 286 | } elseif {$code <= 32} { # (op, op, imm) instruction |
philpem@19 | 287 | return "[opcode $code] [reg $r1], [reg $r0], [imm16 $i16]" |
philpem@19 | 288 | } elseif {$code == 48 || $code == 54} { # b, call |
philpem@19 | 289 | return "[opcode $code] [reg $r0]" |
philpem@19 | 290 | } elseif {$code == 36} { # rcsr |
philpem@19 | 291 | return "[opcode $code] [reg $r2], [csr $r0]" |
philpem@19 | 292 | } elseif {$code == 52} { # wcsr |
philpem@19 | 293 | return "[opcode $code] [csr $r0], [reg $r1]" |
philpem@19 | 294 | } elseif {$code == 56 || $code == 62 || $code == 43} { # bi, calli, raise |
philpem@19 | 295 | return "[opcode $code] [imm26 $i26]" |
philpem@19 | 296 | } elseif {$code == 44 || $code == 55} { # sextb, sexth |
philpem@19 | 297 | return "[opcode $code] [reg $r2], [reg $r0]" |
philpem@19 | 298 | } else { |
philpem@19 | 299 | return "[opcode $code] [reg $r2], [reg $r1], [reg $r0]" |
philpem@19 | 300 | } |
philpem@19 | 301 | } |
philpem@19 | 302 | |
philpem@19 | 303 | ################################ CMDS ################################# |
philpem@19 | 304 | |
philpem@19 | 305 | proc read_memory {addr len} { |
philpem@19 | 306 | if {$addr == ""} {set addr 0} |
philpem@19 | 307 | if {$len == ""} {set len 64} |
philpem@19 | 308 | |
philpem@19 | 309 | # Align read to 16-byte boundary |
philpem@19 | 310 | set a_addr [expr {$addr & ~0xf}] |
philpem@19 | 311 | set a_len [expr {($len + 15) & ~0xf}] |
philpem@19 | 312 | |
philpem@19 | 313 | set vals [jtag_read_memory $a_addr $a_len] |
philpem@19 | 314 | |
philpem@19 | 315 | for {set i 0} {$i < $a_len} {set i [expr {$i + 16}]} { |
philpem@19 | 316 | puts -nonewline [format %08X: $a_addr] |
philpem@19 | 317 | set a_addr [expr {$a_addr + 16}] |
philpem@19 | 318 | for {set j 0} {$j < 4} {incr j} { |
philpem@19 | 319 | set vals [lassign $vals b0 b1 b2 b3] |
philpem@19 | 320 | puts -nonewline " $b0$b1$b2$b3" |
philpem@19 | 321 | } |
philpem@19 | 322 | puts "" |
philpem@19 | 323 | } |
philpem@19 | 324 | |
philpem@19 | 325 | set nextcmd [list] |
philpem@19 | 326 | lappend nextcmd "read" |
philpem@19 | 327 | lappend nextcmd $a_addr |
philpem@19 | 328 | lappend nextcmd $a_len |
philpem@19 | 329 | } |
philpem@19 | 330 | |
philpem@19 | 331 | proc write_memory {addr val} { |
philpem@19 | 332 | set data [list] |
philpem@19 | 333 | lappend data [expr {($val >> 24) & 0xff}] |
philpem@19 | 334 | lappend data [expr {($val >> 16) & 0xff}] |
philpem@19 | 335 | lappend data [expr {($val >> 8) & 0xff}] |
philpem@19 | 336 | lappend data [expr {($val >> 0) & 0xff}] |
philpem@19 | 337 | jtag_write_memory $addr $data |
philpem@19 | 338 | } |
philpem@19 | 339 | |
philpem@19 | 340 | proc dump_memory {addr len} { |
philpem@19 | 341 | if {$addr == ""} {set addr 0} |
philpem@19 | 342 | if {$len == ""} {set len 16} |
philpem@19 | 343 | |
philpem@19 | 344 | # Align read to 4-byte boundary |
philpem@19 | 345 | set a_addr [expr {$addr & ~0x3}] |
philpem@19 | 346 | set a_len [expr {$len * 4}] |
philpem@19 | 347 | set a_end [expr {$a_addr + $a_len}] |
philpem@19 | 348 | |
philpem@19 | 349 | set vals [jtag_read_memory $a_addr $a_len] |
philpem@19 | 350 | |
philpem@19 | 351 | for {set a $a_addr} {$a < $a_end} {set a [expr {$a + 4}]} { |
philpem@19 | 352 | set vals [lassign $vals b0 b1 b2 b3] |
philpem@19 | 353 | puts "[format %08X $a]: [opfmt 0x$b0$b1$b2$b3]" |
philpem@19 | 354 | } |
philpem@19 | 355 | |
philpem@19 | 356 | set nextcmd [list] |
philpem@19 | 357 | lappend nextcmd "dump" |
philpem@19 | 358 | lappend nextcmd [expr {$a_addr + $a_len}] |
philpem@19 | 359 | lappend nextcmd [expr {$a_len / 4}] |
philpem@19 | 360 | } |
philpem@19 | 361 | |
philpem@19 | 362 | proc send {data} { |
philpem@19 | 363 | foreach j $data { |
philpem@19 | 364 | jtag_uart_write $j |
philpem@19 | 365 | } |
philpem@19 | 366 | } |
philpem@19 | 367 | |
philpem@19 | 368 | proc transfer {prompt file offset len target} { |
philpem@19 | 369 | set data [open $file] |
philpem@19 | 370 | fconfigure $data -translation binary |
philpem@19 | 371 | seek $data $offset |
philpem@19 | 372 | |
philpem@19 | 373 | set progress 0 |
philpem@19 | 374 | for {set done 0} {$done < $len} {set done [expr {$done+$did}]} { |
philpem@19 | 375 | puts -nonewline "\r$prompt$done bytes" |
philpem@19 | 376 | |
philpem@19 | 377 | set rest [expr {$len - $done}] |
philpem@19 | 378 | if {$rest > 100} { set do 100 } else { set do $rest } |
philpem@19 | 379 | |
philpem@19 | 380 | set bytes [read $data $do] |
philpem@19 | 381 | set chunk [list] |
philpem@19 | 382 | for {set i 0} {$i < $do} {incr i} { |
philpem@19 | 383 | scan [string index $bytes $i] %c v |
philpem@19 | 384 | lappend chunk $v |
philpem@19 | 385 | } |
philpem@19 | 386 | |
philpem@19 | 387 | #puts "$chunk = [llength $chunk]" |
philpem@19 | 388 | set did [llength $chunk] |
philpem@19 | 389 | if {$did != $do} { |
philpem@19 | 390 | puts "\n -- Short transfer error!" |
philpem@19 | 391 | break |
philpem@19 | 392 | } |
philpem@19 | 393 | |
philpem@19 | 394 | jtag_write_memory $target $chunk |
philpem@19 | 395 | set target [expr {$target+$did}] |
philpem@19 | 396 | } |
philpem@19 | 397 | |
philpem@19 | 398 | if {$done == $len} { |
philpem@19 | 399 | puts "\r$prompt[format %d $len] bytes - complete" |
philpem@19 | 400 | } |
philpem@19 | 401 | |
philpem@19 | 402 | close $data |
philpem@19 | 403 | } |
philpem@19 | 404 | |
philpem@19 | 405 | proc load {file} { |
philpem@19 | 406 | if {$file == ""} { |
philpem@19 | 407 | puts "Specify file to load!" |
philpem@19 | 408 | return |
philpem@19 | 409 | } |
philpem@19 | 410 | |
philpem@19 | 411 | puts -nonewline "Capturing the CPU at address 0x0: " |
philpem@19 | 412 | for {set i 0} {$i < 20} {incr i} { |
philpem@19 | 413 | # bi +0 (CPU trap) |
philpem@19 | 414 | write_memory 0x0 0xE0000000 |
philpem@19 | 415 | # flush instruction cache |
philpem@19 | 416 | jtag_write_csr 0x3 0x0 |
philpem@19 | 417 | # Position CPU on this trap |
philpem@19 | 418 | jtag_reset |
philpem@19 | 419 | } |
philpem@19 | 420 | # Wait a bit to be sure the CPU has the trap good and cached |
philpem@19 | 421 | after 20 |
philpem@19 | 422 | puts "done" |
philpem@19 | 423 | |
philpem@19 | 424 | set sections [list] |
philpem@19 | 425 | set sf [open "| readelf -S $file" "r"] |
philpem@19 | 426 | while {[gets $sf line] >= 0} { |
philpem@19 | 427 | 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 |
philpem@19 | 428 | lappend sections "$section 0x$offset 0x$size" |
philpem@19 | 429 | } |
philpem@19 | 430 | close $sf |
philpem@19 | 431 | |
philpem@19 | 432 | # We can safely overwrite all of the instruction bus (even 0x0) now. |
philpem@19 | 433 | # The trap is certainly cached and the CPU will not see the new values. |
philpem@19 | 434 | set lf [open "| readelf -l $file" "r"] |
philpem@19 | 435 | while {[gets $lf line] >= 0} { |
philpem@19 | 436 | if {[regexp {^\s*LOAD\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+} $line nil offset vaddr paddr len] == 0} continue |
philpem@19 | 437 | puts "Loading $offset+$len to $paddr" |
philpem@19 | 438 | if {$paddr != $vaddr} { |
philpem@19 | 439 | puts " Physical and virtual address mismatch! - Skipping" |
philpem@19 | 440 | continue |
philpem@19 | 441 | } |
philpem@19 | 442 | foreach j $sections { |
philpem@19 | 443 | lassign [split $j " "] section off size |
philpem@19 | 444 | if {$offset <= $off && $off+$size <= $offset+$len} { |
philpem@19 | 445 | transfer " section $section: " $file $off $size [expr {$paddr+$off-$offset}] |
philpem@19 | 446 | } elseif {$offset <= $off && $off < $offset+$len} { |
philpem@19 | 447 | puts " section $section: only half contained??" |
philpem@19 | 448 | } |
philpem@19 | 449 | } |
philpem@19 | 450 | } |
philpem@19 | 451 | close $lf |
philpem@19 | 452 | |
philpem@19 | 453 | # The CPU is spinning at address 0, so no need to reset it. |
philpem@19 | 454 | # First flush the dcache and then release the CPU by flushing the icache |
philpem@19 | 455 | puts -nonewline "Releasing CPU: " |
philpem@19 | 456 | jtag_write_csr 0x4 0x0 |
philpem@19 | 457 | after 20 |
philpem@19 | 458 | jtag_write_csr 0x3 0x0 |
philpem@19 | 459 | puts done |
philpem@19 | 460 | } |
philpem@19 | 461 | |
philpem@19 | 462 | ################################ MAIN ################################# |
philpem@19 | 463 | |
philpem@19 | 464 | |
philpem@19 | 465 | # List all available programming hardwares, and select the USBBlaster. |
philpem@19 | 466 | # (Note: this example assumes only one USBBlaster connected.) |
philpem@19 | 467 | puts "Programming Hardwares:" |
philpem@19 | 468 | foreach hardware_name [get_hardware_names] { |
philpem@19 | 469 | puts $hardware_name |
philpem@19 | 470 | if { [string match "USB_Blaster*" $hardware_name] } { |
philpem@19 | 471 | set usbblaster_name $hardware_name |
philpem@19 | 472 | } |
philpem@19 | 473 | } |
philpem@19 | 474 | puts "\nSelect JTAG chain connected to $usbblaster_name.\n"; |
philpem@19 | 475 | |
philpem@19 | 476 | # List all devices on the chain, and select the first device on the chain. |
philpem@19 | 477 | puts "\nDevices on the JTAG chain:" |
philpem@19 | 478 | foreach device_name [get_device_names -hardware_name $usbblaster_name] { |
philpem@19 | 479 | puts $device_name |
philpem@19 | 480 | if { [string match "@1*" $device_name] } { |
philpem@19 | 481 | set test_device $device_name |
philpem@19 | 482 | } |
philpem@19 | 483 | } |
philpem@19 | 484 | puts "\nSelect device: $test_device.\n"; |
philpem@19 | 485 | |
philpem@19 | 486 | # Open device |
philpem@19 | 487 | open_device -hardware_name $usbblaster_name -device_name $test_device |
philpem@19 | 488 | |
philpem@19 | 489 | device_lock -timeout 10000 |
philpem@19 | 490 | device_virtual_ir_shift -instance_index 0 -ir_value 1 -no_captured_ir_value |
philpem@19 | 491 | |
philpem@19 | 492 | jtag_sync |
philpem@19 | 493 | while {$cmd != "quit"} { |
philpem@19 | 494 | puts -nonewline "\nlm32> " |
philpem@19 | 495 | |
philpem@19 | 496 | if {[gets stdin line] < 0} break |
philpem@19 | 497 | |
philpem@19 | 498 | if {$line eq ""} { set line $nextcmd } |
philpem@19 | 499 | |
philpem@19 | 500 | set parts [split $line " "] |
philpem@19 | 501 | set args [lassign $parts cmd] |
philpem@19 | 502 | set tail [lassign $args arg1 arg2 arg3 arg4] |
philpem@19 | 503 | |
philpem@19 | 504 | set nextcmd "" |
philpem@19 | 505 | switch $cmd { |
philpem@19 | 506 | "" { } |
philpem@19 | 507 | "break" { jtag_break } |
philpem@19 | 508 | "reset" { jtag_reset } |
philpem@19 | 509 | "sync" { jtag_sync } |
philpem@19 | 510 | "read" { set nextcmd [read_memory $arg1 $arg2] } |
philpem@19 | 511 | "dump" { set nextcmd [dump_memory $arg1 $arg2] } |
philpem@19 | 512 | "write" { write_memory $arg1 $arg2 } |
philpem@19 | 513 | "csr" { jtag_write_csr $arg1 $arg2 } |
philpem@19 | 514 | "recv" { jtag_uart_read } |
philpem@19 | 515 | "send" { send $args } |
philpem@19 | 516 | "load" { load $arg1 } |
philpem@19 | 517 | "quit" { } |
philpem@19 | 518 | default { puts "Unknown command" } |
philpem@19 | 519 | } |
philpem@19 | 520 | } |
philpem@19 | 521 | |
philpem@19 | 522 | # Close device |
philpem@19 | 523 | device_unlock |
philpem@19 | 524 | puts "Bye!" |
philpem@19 | 525 | close_device |