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.

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