periph: conform with nmigen-soc breaking changes.
[lambdasoc.git] / lambdasoc / periph / sram.py
1 from nmigen import *
2 from nmigen.utils import log2_int
3
4 from nmigen_soc import wishbone
5 from nmigen_soc.memory import MemoryMap
6 from nmigen_soc.periph import ConstantMap
7
8 from . import Peripheral
9
10
11 __all__ = ["SRAMPeripheral"]
12
13
14 class SRAMPeripheral(Peripheral, Elaboratable):
15 """SRAM storage peripheral.
16
17 Parameters
18 ----------
19 size : int
20 Memory size in bytes.
21 data_width : int
22 Bus data width.
23 granularity : int
24 Bus granularity.
25 writable : bool
26 Memory is writable.
27
28 Attributes
29 ----------
30 bus : :class:`nmigen_soc.wishbone.Interface`
31 Wishbone bus interface.
32 """
33 # TODO raise bus.err if read-only and a bus write is attempted.
34 def __init__(self, *, size, data_width=32, granularity=8, writable=True):
35 super().__init__()
36
37 if not isinstance(size, int) or size <= 0 or size & size-1:
38 raise ValueError("Size must be an integer power of two, not {!r}"
39 .format(size))
40 if size < data_width // granularity:
41 raise ValueError("Size {} cannot be lesser than the data width/granularity ratio "
42 "of {} ({} / {})"
43 .format(size, data_width // granularity, data_width, granularity))
44
45 self._mem = Memory(depth=(size * granularity) // data_width, width=data_width)
46
47 self.bus = wishbone.Interface(addr_width=log2_int(self._mem.depth),
48 data_width=self._mem.width, granularity=granularity,
49 features={"cti", "bte"})
50
51 map = MemoryMap(addr_width=log2_int(size), data_width=granularity, name=self.name)
52 map.add_resource(self._mem, name="mem", size=size)
53 self.bus.memory_map = map
54
55 self.size = size
56 self.granularity = granularity
57 self.writable = writable
58
59 @property
60 def init(self):
61 return self._mem.init
62
63 @init.setter
64 def init(self, init):
65 self._mem.init = init
66
67 @property
68 def constant_map(self):
69 return ConstantMap(
70 SIZE = self.size,
71 )
72
73 def elaborate(self, platform):
74 m = Module()
75
76 incr = Signal.like(self.bus.adr)
77
78 with m.Switch(self.bus.bte):
79 with m.Case(wishbone.BurstTypeExt.LINEAR):
80 m.d.comb += incr.eq(self.bus.adr + 1)
81 with m.Case(wishbone.BurstTypeExt.WRAP_4):
82 m.d.comb += incr[:2].eq(self.bus.adr[:2] + 1)
83 m.d.comb += incr[2:].eq(self.bus.adr[2:])
84 with m.Case(wishbone.BurstTypeExt.WRAP_8):
85 m.d.comb += incr[:3].eq(self.bus.adr[:3] + 1)
86 m.d.comb += incr[3:].eq(self.bus.adr[3:])
87 with m.Case(wishbone.BurstTypeExt.WRAP_16):
88 m.d.comb += incr[:4].eq(self.bus.adr[:4] + 1)
89 m.d.comb += incr[4:].eq(self.bus.adr[4:])
90
91 m.submodules.mem_rp = mem_rp = self._mem.read_port()
92 m.d.comb += self.bus.dat_r.eq(mem_rp.data)
93
94 with m.If(self.bus.ack):
95 m.d.sync += self.bus.ack.eq(0)
96
97 with m.If(self.bus.cyc & self.bus.stb):
98 m.d.sync += self.bus.ack.eq(1)
99 with m.If((self.bus.cti == wishbone.CycleType.INCR_BURST) & self.bus.ack):
100 m.d.comb += mem_rp.addr.eq(incr)
101 with m.Else():
102 m.d.comb += mem_rp.addr.eq(self.bus.adr)
103
104 if self.writable:
105 m.submodules.mem_wp = mem_wp = self._mem.write_port(granularity=self.granularity)
106 m.d.comb += mem_wp.addr.eq(mem_rp.addr)
107 m.d.comb += mem_wp.data.eq(self.bus.dat_w)
108 with m.If(self.bus.cyc & self.bus.stb & self.bus.we):
109 m.d.comb += mem_wp.en.eq(self.bus.sel)
110
111 return m