wishbone.bus.Interface: add support for LOCK_IO signal.
[nmigen-soc.git] / nmigen_soc / wishbone / bus.py
1 from enum import Enum
2 from nmigen import *
3 from nmigen.hdl.rec import Direction
4 from nmigen.utils import log2_int
5
6 from ..memory import MemoryMap
7
8
9 __all__ = ["CycleType", "BurstTypeExt", "Interface"]
10
11
12 class CycleType(Enum):
13 """Wishbone Registered Feedback cycle type."""
14 CLASSIC = 0b000
15 CONST_BURST = 0b001
16 INCR_BURST = 0b010
17 END_OF_BURST = 0b111
18
19
20 class BurstTypeExt(Enum):
21 """Wishbone Registered Feedback burst type extension."""
22 LINEAR = 0b00
23 WRAP_4 = 0b01
24 WRAP_8 = 0b10
25 WRAP_16 = 0b11
26
27
28 class Interface(Record):
29 """Wishbone interface.
30
31 See the `Wishbone specification <https://opencores.org/howto/wishbone>`_ for description
32 of the Wishbone signals. The ``RST_I`` and ``CLK_I`` signals are provided as a part of
33 the clock domain that drives the interface.
34
35 Note that the data width of the underlying memory map of the interface is equal to port
36 granularity, not port size. If port granularity is less than port size, then the address width
37 of the underlying memory map is extended to reflect that.
38
39 Parameters
40 ----------
41 addr_width : int
42 Width of the address signal.
43 data_width : int
44 Width of the data signals ("port size" in Wishbone terminology).
45 One of 8, 16, 32, 64.
46 granularity : int
47 Granularity of select signals ("port granularity" in Wishbone terminology).
48 One of 8, 16, 32, 64.
49 optional : iter(str)
50 Selects the optional signals that will be a part of this interface.
51 alignment : int
52 Resource and window alignment. See :class:`MemoryMap`.
53 name : str
54 Name of the underlying record.
55
56 Attributes
57 ----------
58 The correspondence between the nMigen-SoC signals and the Wishbone signals changes depending
59 on whether the interface acts as an initiator or a target.
60
61 adr : Signal(addr_width)
62 Corresponds to Wishbone signal ``ADR_O`` (initiator) or ``ADR_I`` (target).
63 dat_w : Signal(data_width)
64 Corresponds to Wishbone signal ``DAT_O`` (initiator) or ``DAT_I`` (target).
65 dat_r : Signal(data_width)
66 Corresponds to Wishbone signal ``DAT_I`` (initiator) or ``DAT_O`` (target).
67 sel : Signal(data_width // granularity)
68 Corresponds to Wishbone signal ``SEL_O`` (initiator) or ``SEL_I`` (target).
69 cyc : Signal()
70 Corresponds to Wishbone signal ``CYC_O`` (initiator) or ``CYC_I`` (target).
71 stb : Signal()
72 Corresponds to Wishbone signal ``STB_O`` (initiator) or ``STB_I`` (target).
73 we : Signal()
74 Corresponds to Wishbone signal ``WE_O`` (initiator) or ``WE_I`` (target).
75 ack : Signal()
76 Corresponds to Wishbone signal ``ACK_I`` (initiator) or ``ACK_O`` (target).
77 err : Signal()
78 Optional. Corresponds to Wishbone signal ``ERR_I`` (initiator) or ``ERR_O`` (target).
79 rty : Signal()
80 Optional. Corresponds to Wishbone signal ``RTY_I`` (initiator) or ``RTY_O`` (target).
81 stall : Signal()
82 Optional. Corresponds to Wishbone signal ``STALL_I`` (initiator) or ``STALL_O`` (target).
83 lock : Signal()
84 Optional. Corresponds to Wishbone signal ``LOCK_O`` (initiator) or ``LOCK_I`` (target).
85 cti : Signal()
86 Optional. Corresponds to Wishbone signal ``CTI_O`` (initiator) or ``CTI_I`` (target).
87 bte : Signal()
88 Optional. Corresponds to Wishbone signal ``BTE_O`` (initiator) or ``BTE_I`` (target).
89 """
90 def __init__(self, *, addr_width, data_width, granularity=None, optional=frozenset(),
91 alignment=0, name=None):
92 if not isinstance(addr_width, int) or addr_width < 0:
93 raise ValueError("Address width must be a non-negative integer, not {!r}"
94 .format(addr_width))
95 if data_width not in (8, 16, 32, 64):
96 raise ValueError("Data width must be one of 8, 16, 32, 64, not {!r}"
97 .format(data_width))
98 if granularity is None:
99 granularity = data_width
100 elif granularity not in (8, 16, 32, 64):
101 raise ValueError("Granularity must be one of 8, 16, 32, 64, not {!r}"
102 .format(granularity))
103 if granularity > data_width:
104 raise ValueError("Granularity {} may not be greater than data width {}"
105 .format(granularity, data_width))
106 self.addr_width = addr_width
107 self.data_width = data_width
108 self.granularity = granularity
109 granularity_bits = log2_int(data_width // granularity)
110 self.memory_map = MemoryMap(addr_width=max(1, addr_width + granularity_bits),
111 data_width=data_width >> granularity_bits,
112 alignment=alignment)
113
114 optional = set(optional)
115 unknown = optional - {"rty", "err", "stall", "lock", "cti", "bte"}
116 if unknown:
117 raise ValueError("Optional signal(s) {} are not supported"
118 .format(", ".join(map(repr, unknown))))
119 layout = [
120 ("adr", addr_width, Direction.FANOUT),
121 ("dat_w", data_width, Direction.FANOUT),
122 ("dat_r", data_width, Direction.FANIN),
123 ("sel", data_width // granularity, Direction.FANOUT),
124 ("cyc", 1, Direction.FANOUT),
125 ("stb", 1, Direction.FANOUT),
126 ("we", 1, Direction.FANOUT),
127 ("ack", 1, Direction.FANIN),
128 ]
129 if "err" in optional:
130 layout += [("err", 1, Direction.FANIN)]
131 if "rty" in optional:
132 layout += [("rty", 1, Direction.FANIN)]
133 if "stall" in optional:
134 layout += [("stall", 1, Direction.FANIN)]
135 if "lock" in optional:
136 layout += [("lock", 1, Direction.FANOUT)]
137 if "cti" in optional:
138 layout += [("cti", CycleType, Direction.FANOUT)]
139 if "bte" in optional:
140 layout += [("bte", BurstTypeExt, Direction.FANOUT)]
141 super().__init__(layout, name=name, src_loc_at=1)