tools/lm32-ctl

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
permissions
-rw-r--r--

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.

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