Added JTAG bus interface.
[c4m-jtag.git] / c4m / nmigen / jtag / bus.py
1 from nmigen import *
2 from nmigen.hdl.rec import Direction
3
4 class Interface(Record):
5 """JTAG Interface.
6
7 Parameters
8 ----------
9 with_reset : bool, default=False
10 wether to include trst field; if this field is not present a JTAG master
11 should not rely on this pin for resetting a TAP.
12 """
13 def __init__(self, *, with_reset=False, name=None, src_loc_at=0):
14 layout = [
15 ("tck", 1, Direction.NONE),
16 ("tms", 1, Direction.NONE),
17 ("tdo", 1, Direction.FANOUT),
18 ("tdi", 1, Direction.FANIN),
19 ]
20 if with_reset:
21 layout.append(
22 ("trst", 1, Direction.FANOUT)
23 )
24 super().__init__(layout, name=name, src_loc_at=src_loc_at+1)
25
26
27 class Chain(Elaboratable):
28 """A chain of JTAG interfaces.
29
30 Parameters
31 ----------
32 buses : iterable of :class:`Interface`, default=[]
33 Initial value of the buses in the chain.
34 with_reset : bool, default=False
35 Wether the generated bus has a reset pin. If value is True all buses in
36 the chain also have to have a reset signal
37
38 Attributes
39 ----------
40 bus : :class:`Interface`
41 """
42 def __init__(self, *, with_reset=False, buses=[], name=None, src_loc_at=0):
43 for bus in buses:
44 if not isinstance(bus, Interface):
45 raise ValueError("Object in buses that is not a JTAG Interface")
46 if with_reset and not hasattr(bus, "trst"):
47 raise ValueError("JTAG bus in buses without a reset signal")
48
49 kwargs = {
50 "with_reset": with_reset,
51 "src_loc_at": src_loc_at + 1,
52 }
53 if name is not None:
54 kwargs["name"] = name + "_bus"
55 self.bus = Interface(**kwargs)
56
57 self._buses = buses
58
59 def add(bus):
60 """Add a bus to the chain"""
61
62 if not isinstance(bus, Interface):
63 raise ValueError("bus in not a JTAG Interface")
64 if hasattr(self.bus, "trst") and not hasattr(bus, "trst"):
65 raise ValueError("bus needs to have a reset signal")
66 self._buses.append(bus)
67
68 def elaborate(self, platform):
69 with_reset = hasattr(self.bus, "trst")
70
71 m = Module()
72
73 # Connect first and last
74 m.d.comb += [
75 self._buses[0].tdi.eq(self.bus.tdo),
76 self.bus.tdi.eq(self._buses[-1].tdo),
77 ]
78 for i in range(len(self._buses)):
79 if i < len(self._buses) - 1:
80 m.d.comb += self._buses[i+1].tdi.eq(self._buses[i].tdo)
81 if with_reset:
82 m.d.comb += self._buses[i].trst.eq(self.bus.trst)
83
84 return m