soc/cores/jtag: add Xilinx JTAG TAPs support and simple JTAG PHY (can be used for JTAG UART)
This commit is contained in:
parent
2638393b53
commit
d0ebbda4b3
|
@ -1,8 +1,10 @@
|
|||
# This file is Copyright (c) 2019 Antti Lukats <antti.lukats@gmail.com>$
|
||||
# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# This file is Copyright (c) 2019 Antti Lukats <antti.lukats@gmail.com>
|
||||
# This file is Copyright (c) 2017 Robert Jordens <jordens@gmail.com>
|
||||
# License: BSD
|
||||
|
||||
from migen import *
|
||||
from migen.genlib.cdc import AsyncResetSynchronizer
|
||||
|
||||
from litex.soc.interconnect import stream
|
||||
|
||||
|
@ -32,3 +34,143 @@ class JTAGAtlantic(Module):
|
|||
i_t_dav=source.ready,
|
||||
o_t_ena=source.valid,
|
||||
)
|
||||
|
||||
# Xilinx JTAG --------------------------------------------------------------------------------------
|
||||
|
||||
class XilinxJTAG(Module):
|
||||
def __init__(self, primitive, chain=1):
|
||||
self.reset = Signal()
|
||||
self.capture = Signal()
|
||||
self.shift = Signal()
|
||||
self.update = Signal()
|
||||
|
||||
self.tck = Signal()
|
||||
self.tms = Signal()
|
||||
self.tdi = Signal()
|
||||
self.tdo = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
self.specials += \
|
||||
Instance(primitive,
|
||||
p_JTAG_CHAIN=chain,
|
||||
|
||||
o_RESET=self.reset,
|
||||
o_CAPTURE=self.capture,
|
||||
o_SHIFT=self.shift,
|
||||
o_UPDATE=self.update,
|
||||
|
||||
o_TCK=self.tck,
|
||||
o_TMS=self.tms,
|
||||
o_TDI=self.tdi,
|
||||
i_TDO=self.tdo,
|
||||
)
|
||||
|
||||
class S6JTAG(XilinxJTAG):
|
||||
def __init__(self, *args, **kwargs):
|
||||
XilinxJTAG.__init__(self, primitive="BSCAN_SPARTAN6", *args, **kwargs)
|
||||
|
||||
|
||||
class S7JTAG(XilinxJTAG):
|
||||
def __init__(self, *args, **kwargs):
|
||||
XilinxJTAG.__init__(self, primitive="BSCANE2", *args, **kwargs)
|
||||
|
||||
|
||||
class USJTAG(XilinxJTAG):
|
||||
def __init__(self, *args, **kwargs):
|
||||
XilinxJTAG.__init__(self, primitive="BSCANE2", *args, **kwargs)
|
||||
|
||||
# JTAG PHY -----------------------------------------------------------------------------------------
|
||||
|
||||
class JTAGPHY(Module):
|
||||
def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys"):
|
||||
"""JTAG PHY
|
||||
|
||||
Provides a simple JTAG to LiteX stream module to easily stream data to/from the FPGA
|
||||
over JTAG.
|
||||
|
||||
Wire format: data_width + 2 bits, LSB first.
|
||||
|
||||
Host to Target:
|
||||
- TX ready : bit 0
|
||||
- RX data: : bit 1 to data_width
|
||||
- RX valid : bit data_width + 1
|
||||
|
||||
Target to Host:
|
||||
- RX ready : bit 0
|
||||
- TX data : bit 1 to data_width
|
||||
- TX valid : bit data_width + 1
|
||||
"""
|
||||
self.sink = sink = stream.Endpoint([("data", data_width)])
|
||||
self.source = source = stream.Endpoint([("data", data_width)])
|
||||
|
||||
# # #
|
||||
|
||||
valid = Signal()
|
||||
data = Signal(data_width)
|
||||
count = Signal(max=data_width)
|
||||
|
||||
# JTAG TAP ---------------------------------------------------------------------------------
|
||||
if jtag is None:
|
||||
if device[:3] == "xc6":
|
||||
jtag = S6JTAG()
|
||||
elif device[:3] == "xc7":
|
||||
jtag = S7JTAG()
|
||||
elif device[:4] in ["xcku", "xcvu"]:
|
||||
jtag = USJTAG()
|
||||
else:
|
||||
raise NotImplementedError
|
||||
self.submodules += jtag
|
||||
|
||||
# JTAG clock domain ------------------------------------------------------------------------
|
||||
self.clock_domains.cd_jtag = ClockDomain()
|
||||
self.comb += ClockSignal("jtag").eq(jtag.tck)
|
||||
self.specials += AsyncResetSynchronizer(self.cd_jtag, ResetSignal("sys"))
|
||||
|
||||
# JTAG clock domain crossing ---------------------------------------------------------------
|
||||
if clock_domain != "jtag":
|
||||
tx_cdc = stream.AsyncFIFO([("data", data_width)], 4)
|
||||
tx_cdc = ClockDomainsRenamer({"write": clock_domain, "read": "jtag"})(tx_cdc)
|
||||
rx_cdc = stream.AsyncFIFO([("data", data_width)], 4)
|
||||
rx_cdc = ClockDomainsRenamer({"write": "jtag", "read": clock_domain})(rx_cdc)
|
||||
self.submodules += tx_cdc, rx_cdc
|
||||
self.comb += [
|
||||
sink.connect(tx_cdc.sink),
|
||||
rx_cdc.source.connect(source)
|
||||
]
|
||||
sink, source = tx_cdc.source, rx_cdc.sink
|
||||
|
||||
# JTAG Xfer FSM ----------------------------------------------------------------------------
|
||||
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),
|
||||
If(jtag.shift,
|
||||
sink.ready.eq(jtag.tdi),
|
||||
NextValue(valid, sink.valid),
|
||||
NextValue(data, sink.data),
|
||||
NextValue(count, 0),
|
||||
NextState("XFER-DATA")
|
||||
)
|
||||
)
|
||||
fsm.act("XFER-DATA",
|
||||
jtag.tdo.eq(data),
|
||||
If(jtag.shift,
|
||||
NextValue(count, count + 1),
|
||||
NextValue(data, Cat(data[1:], jtag.tdi)),
|
||||
If(count == (data_width - 1),
|
||||
NextState("XFER-VALID")
|
||||
)
|
||||
)
|
||||
)
|
||||
fsm.act("XFER-VALID",
|
||||
jtag.tdo.eq(valid),
|
||||
If(jtag.shift,
|
||||
source.valid.eq(jtag.tdi),
|
||||
NextState("XFER-READY")
|
||||
)
|
||||
)
|
||||
self.comb += source.data.eq(data)
|
||||
|
|
Loading…
Reference in New Issue