|
| 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 | + cti : Signal() |
| 84 | + Optional. Corresponds to Wishbone signal ``CTI_O`` (initiator) or ``CTI_I`` (target). |
| 85 | + bte : Signal() |
| 86 | + Optional. Corresponds to Wishbone signal ``BTE_O`` (initiator) or ``BTE_I`` (target). |
| 87 | + """ |
| 88 | + def __init__(self, *, addr_width, data_width, granularity=None, optional=frozenset(), |
| 89 | + alignment=0, name=None): |
| 90 | + if not isinstance(addr_width, int) or addr_width < 0: |
| 91 | + raise ValueError("Address width must be a non-negative integer, not {!r}" |
| 92 | + .format(addr_width)) |
| 93 | + if data_width not in (8, 16, 32, 64): |
| 94 | + raise ValueError("Data width must be one of 8, 16, 32, 64, not {!r}" |
| 95 | + .format(data_width)) |
| 96 | + if granularity is None: |
| 97 | + granularity = data_width |
| 98 | + elif granularity not in (8, 16, 32, 64): |
| 99 | + raise ValueError("Granularity must be one of 8, 16, 32, 64, not {!r}" |
| 100 | + .format(granularity)) |
| 101 | + if granularity > data_width: |
| 102 | + raise ValueError("Granularity {} may not be greater than data width {}" |
| 103 | + .format(granularity, data_width)) |
| 104 | + self.addr_width = addr_width |
| 105 | + self.data_width = data_width |
| 106 | + self.granularity = granularity |
| 107 | + granularity_bits = log2_int(data_width // granularity) |
| 108 | + self.memory_map = MemoryMap(addr_width=max(1, addr_width + granularity_bits), |
| 109 | + data_width=data_width >> granularity_bits, |
| 110 | + alignment=alignment) |
| 111 | + |
| 112 | + optional = set(optional) |
| 113 | + unknown = optional - {"rty", "err", "stall", "cti", "bte"} |
| 114 | + if unknown: |
| 115 | + raise ValueError("Optional signal(s) {} are not supported" |
| 116 | + .format(", ".join(map(repr, unknown)))) |
| 117 | + layout = [ |
| 118 | + ("adr", addr_width, Direction.FANOUT), |
| 119 | + ("dat_w", data_width, Direction.FANOUT), |
| 120 | + ("dat_r", data_width, Direction.FANIN), |
| 121 | + ("sel", data_width // granularity, Direction.FANOUT), |
| 122 | + ("cyc", 1, Direction.FANOUT), |
| 123 | + ("stb", 1, Direction.FANOUT), |
| 124 | + ("we", 1, Direction.FANOUT), |
| 125 | + ("ack", 1, Direction.FANIN), |
| 126 | + ] |
| 127 | + if "err" in optional: |
| 128 | + layout += [("err", 1, Direction.FANIN)] |
| 129 | + if "rty" in optional: |
| 130 | + layout += [("rty", 1, Direction.FANIN)] |
| 131 | + if "stall" in optional: |
| 132 | + layout += [("stall", 1, Direction.FANIN)] |
| 133 | + if "cti" in optional: |
| 134 | + layout += [("cti", CycleType, Direction.FANOUT)] |
| 135 | + if "bte" in optional: |
| 136 | + layout += [("bte", BurstTypeExt, Direction.FANOUT)] |
| 137 | + super().__init__(layout, name=name, src_loc_at=1) |
0 commit comments