Add Wesley Terpstra's GSI LM32 firmware loading tool.

Sun, 06 Mar 2011 21:04:06 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 06 Mar 2011 21:04:06 +0000
changeset 19
7483b57ce922
parent 18
cc945f778cd7
child 20
b6d814c2947c

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 --- /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