a21ab913e79dc7a9b4c59c877ae1439c04df915f
[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 name=self.name)
47
48 self.bus = wishbone.Interface(addr_width=log2_int(self._mem.depth),
49 data_width=self._mem.width, granularity=granularity,
50 features={"cti", "bte"})
51
52 map = MemoryMap(addr_width=log2_int(size), data_width=granularity)
53 map.add_resource(self._mem, size=size)
54 self.bus.memory_map = map
55
56 self.size = size
57 self.granularity = granularity
58 self.writable = writable
59
60 @property
61 def init(self):
62 return self._mem.init
63
64 @init.setter
65 def init(self, init):
66 self._mem.init = init
67
68 @property
69 def constant_map(self):
70 return ConstantMap(
71 SIZE = self.size,
72 )
73
74 def elaborate(self, platform):
75 m = Module()
76
77 incr = Signal.like(self.bus.adr)
78
79 with m.Switch(self.bus.bte):
80 with m.Case(wishbone.BurstTypeExt.LINEAR):
81 m.d.comb += incr.eq(self.bus.adr + 1)
82 with m.Case(wishbone.BurstTypeExt.WRAP_4):
83 m.d.comb += incr[:2].eq(self.bus.adr[:2] + 1)
84 m.d.comb += incr[2:].eq(self.bus.adr[2:])
85 with m.Case(wishbone.BurstTypeExt.WRAP_8):
86 m.d.comb += incr[:3].eq(self.bus.adr[:3] + 1)
87 m.d.comb += incr[3:].eq(self.bus.adr[3:])
88 with m.Case(wishbone.BurstTypeExt.WRAP_16):
89 m.d.comb += incr[:4].eq(self.bus.adr[:4] + 1)
90 m.d.comb += incr[4:].eq(self.bus.adr[4:])
91
92 m.submodules.mem_rp = mem_rp = self._mem.read_port()
93 m.d.comb += self.bus.dat_r.eq(mem_rp.data)
94
95 with m.If(self.bus.ack):
96 m.d.sync += self.bus.ack.eq(0)
97
98 with m.If(self.bus.cyc & self.bus.stb):
99 m.d.sync += self.bus.ack.eq(1)
100 with m.If((self.bus.cti == wishbone.CycleType.INCR_BURST) & self.bus.ack):
101 m.d.comb += mem_rp.addr.eq(incr)
102 with m.Else():
103 m.d.comb += mem_rp.addr.eq(self.bus.adr)
104
105 if self.writable:
106 m.submodules.mem_wp = mem_wp = self._mem.write_port(granularity=self.granularity)
107 m.d.comb += mem_wp.addr.eq(mem_rp.addr)
108 m.d.comb += mem_wp.data.eq(self.bus.dat_w)
109 with m.If(self.bus.cyc & self.bus.stb & self.bus.we):
110 m.d.comb += mem_wp.en.eq(self.bus.sel)
111
112 return m