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