openocd/jtag: Add JTAG-UART/JTABBone support to Zynq7000/ZynqMPSoC and define all Xilinx IRs for USERX.
Thanks @smunaut for the initial investigation/implementation. The changes have been minimized to: - Adding an optional delay in TDI: On Zynq devices, TDI is delayed by 1 TCK to bypass the PS tap. - Avoiding OpenOCD's -endstate DRPAUSE on Xilinx that does not seem required.
This commit is contained in:
parent
be43ef6424
commit
0a738002e0
|
@ -40,19 +40,42 @@ class OpenOCD(GenericProgrammer):
|
|||
self.call(["openocd", "-f", config, "-c", script])
|
||||
|
||||
def get_ir(self, chain, config):
|
||||
# On ECP5, force IR to 0x32.
|
||||
cfg_str = open(config).read()
|
||||
ecp5 = "ecp5" in cfg_str
|
||||
altera = "10m50" in cfg_str # TODO: or cyclone 10
|
||||
if ecp5:
|
||||
# Lattice ECP5.
|
||||
if "ecp5" in cfg_str:
|
||||
chain = 0x32
|
||||
elif altera:
|
||||
chain = 0xC
|
||||
# Else IR = 1 + CHAIN.
|
||||
# Intel Max10.
|
||||
elif "10m50" in cfg_str:
|
||||
chain = 0xc
|
||||
# Xilinx ZynqMP.
|
||||
elif "zynqmp" in cfg_str:
|
||||
chain = {
|
||||
1: 0x902, # USER1.
|
||||
2: 0x903, # USER2.
|
||||
3: 0x922, # USER3.
|
||||
4: 0x923, # USER4.
|
||||
}[chain]
|
||||
# Xilinx 7-Series.
|
||||
else:
|
||||
chain = 0x1 + chain
|
||||
chain = {
|
||||
1: 0x02, # USER1.
|
||||
2: 0x03, # USER2.
|
||||
3: 0x22, # USER3.
|
||||
4: 0x23, # USER4.
|
||||
}[chain]
|
||||
return chain
|
||||
|
||||
def get_endstate(self, config):
|
||||
cfg_str = open(config).read()
|
||||
# Lattice ECP5.
|
||||
if "ecp5" in cfg_str:
|
||||
return "-endstate DRPAUSE" # CHECKME: Can we avoid it?
|
||||
# Intel Max10.
|
||||
elif "10m50" in cfg_str:
|
||||
return "-endstate DRPAUSE" # CHECKME: Is it required on Intel?
|
||||
else:
|
||||
return ""
|
||||
|
||||
def stream(self, port=20000, chain=1):
|
||||
"""
|
||||
Create a TCP server to stream data to/from the internal JTAG TAP of the FPGA
|
||||
|
@ -68,7 +91,9 @@ class OpenOCD(GenericProgrammer):
|
|||
- TX data : bit 1 to 8
|
||||
- TX valid : bit 9
|
||||
"""
|
||||
config = self.find_config()
|
||||
config = self.find_config()
|
||||
ir = self.get_ir(chain, config)
|
||||
endstate = self.get_endstate(config)
|
||||
cfg = """
|
||||
proc jtagstream_poll {tap tx n} {
|
||||
set m [string length $tx]
|
||||
|
@ -81,7 +106,11 @@ proc jtagstream_poll {tap tx n} {
|
|||
#echo tx[scan $txj %c]
|
||||
}
|
||||
set txi [concat {*}$txi]
|
||||
set rxi [split [drscan $tap {*}$txi -endstate DRPAUSE] " "]
|
||||
"""
|
||||
cfg += f"""
|
||||
set rxi [split [drscan $tap {{*}}$txi {endstate}] " "]
|
||||
"""
|
||||
cfg += """
|
||||
#echo $txi:$rxi
|
||||
set rx ""
|
||||
set writable 1
|
||||
|
@ -153,7 +182,7 @@ proc jtagstream_serve {tap port} {
|
|||
write_to_file("stream.cfg", cfg)
|
||||
script = "; ".join([
|
||||
"init",
|
||||
"irscan $_CHIPNAME.tap {:d}".format(self.get_ir(chain, config)),
|
||||
"irscan $_CHIPNAME.tap {:d}".format(ir),
|
||||
"jtagstream_serve $_CHIPNAME.tap {:d}".format(port),
|
||||
"exit",
|
||||
])
|
||||
|
|
|
@ -304,11 +304,10 @@ class XilinxJTAG(Module):
|
|||
|
||||
@staticmethod
|
||||
def get_primitive(device):
|
||||
# TODO: Add support for all devices.
|
||||
prim_dict = {
|
||||
# Primitive Name Ðevice (startswith)
|
||||
"BSCAN_SPARTAN6" : ["xc6"],
|
||||
"BSCANE2" : ["xc7", "xcku", "xcvu", "xczu"],
|
||||
"BSCANE2" : ["xc7a", "xc7k", "xc7v", "xc7z"] + ["xcku", "xcvu", "xczu"],
|
||||
}
|
||||
for prim, prim_devs in prim_dict.items():
|
||||
for prim_dev in prim_devs:
|
||||
|
@ -316,6 +315,15 @@ class XilinxJTAG(Module):
|
|||
return prim
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_tdi_delay(device):
|
||||
# Input delay if 1 TCK on TDI on Zynq/ZynqMPSoC devices.
|
||||
delay_dict = {"xc7z" : 1, "xczu" : 1}
|
||||
for dev, delay in delay_dict.items():
|
||||
if device.lower().startswith(dev):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ECP5 JTAG ----------------------------------------------------------------------------------------
|
||||
|
||||
class ECP5JTAG(Module):
|
||||
|
@ -393,15 +401,14 @@ class JTAGPHY(Module):
|
|||
|
||||
# # #
|
||||
|
||||
valid = Signal()
|
||||
data = Signal(data_width)
|
||||
count = Signal(max=data_width)
|
||||
|
||||
# JTAG TAP ---------------------------------------------------------------------------------
|
||||
if jtag is None:
|
||||
jtag_tdi_delay = 0
|
||||
# Xilinx.
|
||||
if XilinxJTAG.get_primitive(device) is not None:
|
||||
jtag = XilinxJTAG(primitive=XilinxJTAG.get_primitive(device), chain=chain)
|
||||
jtag_tdi_delay = XilinxJTAG.get_tdi_delay(device)
|
||||
# Lattice.
|
||||
elif device[:5] == "LFE5U":
|
||||
jtag = ECP5JTAG()
|
||||
|
@ -436,16 +443,29 @@ class JTAGPHY(Module):
|
|||
]
|
||||
sink, source = tx_cdc.source, rx_cdc.sink
|
||||
|
||||
# JTAG TDI/TDO Delay -----------------------------------------------------------------------
|
||||
jtag_tdi = jtag.tdi
|
||||
jtag_tdo = jtag.tdo
|
||||
if jtag_tdi_delay:
|
||||
jtag_tdi_sr = Signal(data_width + 2 - jtag_tdi_delay)
|
||||
self.sync.jtag += If(jtag.shift, jtag_tdi_sr.eq(Cat(jtag.tdi, jtag_tdi_sr)))
|
||||
jtag_tdi = jtag_tdi_sr[-1]
|
||||
|
||||
# JTAG Xfer FSM ----------------------------------------------------------------------------
|
||||
valid = Signal()
|
||||
ready = Signal()
|
||||
data = Signal(data_width)
|
||||
count = Signal(max=data_width)
|
||||
|
||||
fsm = FSM(reset_state="XFER-READY")
|
||||
fsm = ClockDomainsRenamer("jtag")(fsm)
|
||||
fsm = ResetInserter()(fsm)
|
||||
self.submodules += fsm
|
||||
self.comb += fsm.reset.eq(jtag.reset | jtag.capture)
|
||||
fsm.act("XFER-READY",
|
||||
jtag.tdo.eq(source.ready),
|
||||
jtag_tdo.eq(ready),
|
||||
If(jtag.shift,
|
||||
sink.ready.eq(jtag.tdi),
|
||||
sink.ready.eq(jtag_tdi),
|
||||
NextValue(valid, sink.valid),
|
||||
NextValue(data, sink.data),
|
||||
NextValue(count, 0),
|
||||
|
@ -453,20 +473,21 @@ class JTAGPHY(Module):
|
|||
)
|
||||
)
|
||||
fsm.act("XFER-DATA",
|
||||
jtag.tdo.eq(data),
|
||||
jtag_tdo.eq(data),
|
||||
If(jtag.shift,
|
||||
NextValue(count, count + 1),
|
||||
NextValue(data, Cat(data[1:], jtag.tdi)),
|
||||
NextValue(data, Cat(data[1:], jtag_tdi)),
|
||||
If(count == (data_width - 1),
|
||||
NextState("XFER-VALID")
|
||||
)
|
||||
)
|
||||
)
|
||||
fsm.act("XFER-VALID",
|
||||
jtag.tdo.eq(valid),
|
||||
jtag_tdo.eq(valid),
|
||||
If(jtag.shift,
|
||||
source.valid.eq(jtag.tdi),
|
||||
source.valid.eq(jtag_tdi),
|
||||
source.data.eq(data),
|
||||
NextValue(ready, source.ready),
|
||||
NextState("XFER-READY")
|
||||
)
|
||||
)
|
||||
self.comb += source.data.eq(data)
|
||||
|
|
Loading…
Reference in New Issue