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