wishbone: fix SRAM; improve tests for Decoder & Arbiter
[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 if bus is None:
51 bus = Interface(addr_width=log2_int(self.memory.depth, need_pow2=False),
52 data_width=self.memory.width,
53 granularity=granularity,
54 features=features,
55 alignment=0,
56 name=None)
57 self.bus = bus
58 self.granularity = bus.granularity
59
60 def elaborate(self, platform):
61 m = Module()
62
63 if self.memory.width > len(self.bus.dat_r):
64 raise NotImplementedError
65
66 # read
67 m.submodules.rdport = rdport = self.memory.read_port()
68 m.d.comb += [
69 rdport.addr.eq(self.bus.adr[:len(rdport.addr)]),
70 self.bus.dat_r.eq(rdport.data)
71 ]
72
73 # write
74 if not self.read_only:
75 m.submodules.wrport = wrport = self.memory.write_port(granularity=self.granularity)
76 m.d.comb += [
77 wrport.addr.eq(self.bus.adr[:len(rdport.addr)]),
78 wrport.data.eq(self.bus.dat_w)
79 ]
80 for i in range(4):
81 m.d.comb += wrport.en[i].eq(self.bus.cyc & self.bus.stb &
82 self.bus.we & self.bus.sel[i])
83
84 # generate ack
85 m.d.sync += self.bus.ack.eq(0)
86 with m.If(self.bus.cyc & self.bus.stb & ~self.bus.ack):
87 m.d.sync += self.bus.ack.eq(1)
88
89 return m