ffb8f63da0c3a84cad1391deba5eeb363fdad8ef
[nmigen-soc.git] / nmigen_soc / wishbone / sram.py
1 from nmigen import Elaboratable, Memory, Module
2 from nmigen.utils import log2_int
3
4 from nmigen.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 sepcified, this is the granularity
34 of the Wishbone bus. Optional. See :class:`Interface`.
35 features : iter(str)
36 If the Wishbone bus is not sepcified, 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=frozenset()):
50 if not isinstance(memory, Memory):
51 raise TypeError("Memory {!r} is not a Memory"
52 .format(memory))
53 self.memory = memory
54 self.read_only = read_only
55 if bus is None:
56 bus = Interface(addr_width=log2_int(self.memory.depth,
57 need_pow2=False),
58 data_width=self.memory.width,
59 granularity=granularity,
60 features=features,
61 alignment=0,
62 name=None)
63 self.bus = bus
64 self.granularity = bus.granularity
65
66 def elaborate(self, platform):
67 m = Module()
68
69 if self.memory.width > len(self.bus.dat_r):
70 raise NotImplementedError
71
72 # read
73 m.submodules.rdport = rdport = self.memory.read_port()
74 m.d.comb += [
75 rdport.addr.eq(self.bus.adr[:len(rdport.addr)]),
76 self.bus.dat_r.eq(rdport.data)
77 ]
78
79 # write
80 if not self.read_only:
81 m.submodules.wrport = wrport = self.memory.write_port(
82 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