From d0ebbda4b385c0a4d4b1f43ae9fcde2601639c5b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 6 Sep 2019 11:55:41 +0200 Subject: [PATCH] soc/cores/jtag: add Xilinx JTAG TAPs support and simple JTAG PHY (can be used for JTAG UART) --- litex/soc/cores/jtag.py | 146 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index 6140649b6..dfc1fd71e 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -1,8 +1,10 @@ -# This file is Copyright (c) 2019 Antti Lukats $ # This file is Copyright (c) 2019 Florent Kermarrec +# This file is Copyright (c) 2019 Antti Lukats +# This file is Copyright (c) 2017 Robert Jordens # License: BSD from migen import * +from migen.genlib.cdc import AsyncResetSynchronizer from litex.soc.interconnect import stream @@ -10,7 +12,7 @@ from litex.soc.interconnect import stream class JTAGAtlantic(Module): def __init__(self): - self.sink = sink = stream.Endpoint([("data", 8)]) + self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8)]) # # # @@ -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)