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 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
|
# License: BSD
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
from migen.genlib.cdc import AsyncResetSynchronizer
|
||||||
|
|
||||||
from litex.soc.interconnect import stream
|
from litex.soc.interconnect import stream
|
||||||
|
|
||||||
|
@ -10,7 +12,7 @@ from litex.soc.interconnect import stream
|
||||||
|
|
||||||
class JTAGAtlantic(Module):
|
class JTAGAtlantic(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sink = sink = stream.Endpoint([("data", 8)])
|
self.sink = sink = stream.Endpoint([("data", 8)])
|
||||||
self.source = source = stream.Endpoint([("data", 8)])
|
self.source = source = stream.Endpoint([("data", 8)])
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
@ -32,3 +34,143 @@ class JTAGAtlantic(Module):
|
||||||
i_t_dav=source.ready,
|
i_t_dav=source.ready,
|
||||||
o_t_ena=source.valid,
|
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