wishbone: fix docstring & unneeded parameter for InterconnectShared
[nmigen-soc.git] / nmigen_soc / wishbone / sram.py
1 from nmigen import *
2 from nmigen.utils import *
3
4 from .bus import Interface
5
6
7 __all__ = ["SRAM"]
8
9
10 class SRAM(Elaboratable):
11 """SRAM module carrying a volatile memory block (implemented with :class:`Memory`)
12 that can be read and write (or only read if the SRAM is read-only) through a Wishbone bus.
13
14 If no Wishbone bus is specified during initialisation, this creates one whose address width
15 is just enough to fit the whole memory (i.e. equals to the log2(memory depth) rounded up), and
16 whose data width is equal to the memory width.
17
18 Parameters
19 ----------
20 memory : :class:`Memory`
21 The memory to be accessed via the Wishbone bus.
22 read_only : bool
23 Whether or not the memory is read-only. Defaults to False.
24 bus : :class:`Interface` or None
25 The Wishbone bus interface providing access to the read/write ports of the memory.
26 Optional and defaults to None, which lets this module to instantiate one as described
27 above, having the granularity, features and alignment as specified by their
28 corresponding parameters.
29 granularity : int or None
30 If the Wishbone bus is not sepcified, this is the granularity of the Wishbone bus.
31 Optional. See :class:`Interface`.
32 features : iter(str)
33 If the Wishbone bus is not sepcified, this is the optional signal set for the Wishbone bus.
34 See :class:`Interface`.
35
36 Attributes
37 ----------
38 memory : :class:`Memory`
39 The memory to be accessed via the Wishbone bus.
40 bus : :class:`Interface`
41 The Wishbone bus interface providing access to the read/write ports of the memory.
42 """
43 def __init__(self, memory, read_only=False, bus=None,
44 granularity=None, features=frozenset()):
45 if not isinstance(memory, Memory):
46 raise TypeError("Memory {!r} is not a Memory"
47 .format(memory))
48 self.memory = memory
49 self.read_only = read_only
50 # Define total address space:
51 # - Base: equals memory.depth
52 # - Has an additional ReadPort: add rdport.depth
53 # - Has an additional WirtePort: add wrport.depth
54 self._memdepth = self.memory.depth * 2
55 if not read_only:
56 self._memdepth += self.memory.depth
57 if bus is None:
58 bus = Interface(addr_width=max(0, log2_int(self._memdepth, need_pow2=False)),
59 data_width=self.memory.width,
60 granularity=granularity,
61 features=features,
62 alignment=0,
63 name=None)
64 self.bus = bus
65 self.granularity = bus.granularity
66
67 def elaborate(self, platform):
68 m = Module()
69
70 if self.memory.width > len(self.bus.dat_r):
71 raise NotImplementedError
72
73 # read
74 m.submodules.rdport = rdport = self.memory.read_port()
75 m.d.comb += [
76 rdport.addr.eq(self.bus.adr[:len(rdport.addr)]),
77 self.bus.dat_r.eq(rdport.data)
78 ]
79
80 # write
81 if not self.read_only:
82 m.submodules.wrport = wrport = self.memory.write_port(granularity=self.granularity)
83 m.d.comb += [
84 wrport.addr.eq(self.bus.adr[:len(rdport.addr)]),
85 wrport.data.eq(self.bus.dat_w)
86 ]
87 for i in range(4):
88 m.d.comb += wrport.en[i].eq(self.bus.cyc & self.bus.stb &
89 self.bus.we & self.bus.sel[i])
90
91 # generate ack
92 m.d.sync += self.bus.ack.eq(0)
93 with m.If(self.bus.cyc & self.bus.stb & ~self.bus.ack):
94 m.d.sync += self.bus.ack.eq(1)
95
96 return m