build/openocd: add stream method for JTAG UART

This commit is contained in:
Florent Kermarrec 2019-09-06 11:57:18 +02:00
parent b356204f95
commit bd6ec63be4
1 changed files with 107 additions and 1 deletions

View File

@ -1,9 +1,11 @@
# This file is Copyright (c) 2015 Robert Jordens <jordens@gmail.com>
# This file is Copyright (c) 2015-2017 Robert Jordens <jordens@gmail.com>
# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import subprocess
from litex.build.tools import write_to_file
from litex.build.generic_programmer import GenericProgrammer
@ -32,3 +34,107 @@ class OpenOCD(GenericProgrammer):
"exit"
])
subprocess.call(["openocd", "-f", self.config, "-c", script])
def stream(self, port=20000):
"""
Create a Telnet server to stream data to/from the internal JTAG TAP of the FPGA
Wire format: 10 bits LSB first
Host to Target:
- TX ready : bit 0
- RX data: : bit 1 to 8
- RX valid : bit 9
Target to Host:
- RX ready : bit 0
- TX data : bit 1 to 8
- TX valid : bit 9
"""
cfg = """
proc jtagstream_poll {tap tx n} {
set m [string length $tx]
set n [expr ($m>$n)?$m:$n]
set txi [lrepeat $n {10 0x001}]
set i 0
foreach txj [split $tx ""] {
lset txi $i 1 [format 0x%4.4X [expr 0x201 | ([scan $txj %c] << 1)]]
incr i
}
set txi [concat {*}$txi]
set rxi [split [drscan $tap {*}$txi -endstate DRPAUSE] " "]
#echo $txi:$rxi
set rx ""
set writable 1
foreach {rxj} $rxi {
set readable [expr 0x$rxj & 0x200]
set writable [expr 0x$rxj & $writable]
if {$readable} {
append rx [format %c [expr (0x$rxj >> 1) & 0xff]]
}
}
return [list $rx $readable $writable]
}
proc jtagstream_drain {tap tx chunk_rx max_rx} {
lassign [jtagstream_poll $tap $tx $chunk_rx] rx readable writable
while {[expr $writable && ($readable > 0) && ([string length $rx] < $max_rx)]} {
lassign [jtagstream_poll $tap "" $chunk_rx] rxi readable writable
append rx $rxi
}
if {!$writable} {
echo "write overflow"
}
return $rx
}
proc jtagstream_rxtx {tap client is_poll} {
if {![$client eof]} {
if {!$is_poll} {
set tx [$client gets]
} else {
set tx ""
}
set rx [jtagstream_drain $tap $tx 64 4096]
if {[string length $rx]} {
$client puts -nonewline $rx
}
if {$is_poll} {
after 1 [list jtagstream_rxtx $tap $client 1]
}
} else {
$client readable {}
$client onexception {}
$client close
}
}
proc jtagstream_client {tap sock} {
set client [$sock accept]
fconfigure $client -buffering none
$client readable [list jtagstream_rxtx $tap $client 0]
$client onexception [list $client close]
after 1 [list jtagstream_rxtx $tap $client 1]
}
proc jtagstream_exit {sock} {
stdin readable {}
$sock readable {}
}
proc jtagstream_serve {tap port} {
set sock [socket stream.server $port]
$sock readable [list jtagstream_client $tap $sock]
stdin readable [list jtagstream_exit $sock]
vwait forever
$sock close
}
"""
write_to_file("stream.cfg", cfg)
script = "; ".join([
"init",
"irscan $_CHIPNAME.tap $_USER1",
"jtagstream_serve $_CHIPNAME.tap {:d}".format(port),
"exit",
])
subprocess.call(["openocd", "-f", self.config, "-f", "stream.cfg", "-c", script])