move comments to minerva LoadStoreInterface
[soc.git] / src / soc / minerva / units / loadstore.py
1 from nmigen import Elaboratable, Module, Signal, Record, Cat, Const, Mux
2 from nmigen.utils import log2_int
3 from nmigen.lib.fifo import SyncFIFO
4
5 from soc.minerva.cache import L1Cache
6 from soc.minerva.wishbone import wishbone_layout, WishboneArbiter, Cycle
7
8
9 __all__ = ["LoadStoreUnitInterface", "BareLoadStoreUnit",
10 "CachedLoadStoreUnit"]
11
12
13 class LoadStoreUnitInterface:
14 def __init__(self, addr_wid=32, mask_wid=4, data_wid=32):
15 self.dbus = Record(wishbone_layout)
16 badwid = addr_wid-log2_int(mask_wid) # TODO: is this correct?
17
18 self.x_addr = Signal(addr_wid) # The address used for loads/stores
19 self.x_mask = Signal(mask_wid) # Mask of which bytes to write
20 self.x_load = Signal() # set to do a memory load
21 self.x_store = Signal() # set to do a memory store
22 self.x_store_data = Signal(data_wid) # The data to write when storing
23 self.x_stall = Signal() # input - do nothing until low
24 self.x_valid = Signal()
25 self.m_stall = Signal() # input - do nothing until low
26 self.m_valid = Signal() # when this is high and m_busy is
27 # low, the data for the memory load
28 # can be read from m_load_data
29
30 self.x_busy = Signal() # set when the memory is busy
31 self.m_busy = Signal() # set when the memory is busy
32 self.m_load_data = Signal(data_wid) # Data returned from a memory read
33 self.m_load_error = Signal() # Whether there was an error when loading
34 self.m_store_error = Signal() # Whether there was an error when storing
35 self.m_badaddr = Signal(badwid) # The address of the load/store error
36
37
38 class BareLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
39 def elaborate(self, platform):
40 m = Module()
41
42 with m.If(self.dbus.cyc):
43 with m.If(self.dbus.ack | self.dbus.err | ~self.m_valid):
44 m.d.sync += [
45 self.dbus.cyc.eq(0),
46 self.dbus.stb.eq(0),
47 self.m_load_data.eq(self.dbus.dat_r)
48 ]
49 with m.Elif((self.x_load | self.x_store) &
50 self.x_valid & ~self.x_stall):
51 m.d.sync += [
52 self.dbus.cyc.eq(1),
53 self.dbus.stb.eq(1),
54 self.dbus.adr.eq(self.x_addr[2:]),
55 self.dbus.sel.eq(self.x_mask),
56 self.dbus.we.eq(self.x_store),
57 self.dbus.dat_w.eq(self.x_store_data)
58 ]
59
60 with m.If(self.dbus.cyc & self.dbus.err):
61 m.d.sync += [
62 self.m_load_error.eq(~self.dbus.we),
63 self.m_store_error.eq(self.dbus.we),
64 self.m_badaddr.eq(self.dbus.adr)
65 ]
66 with m.Elif(~self.m_stall):
67 m.d.sync += [
68 self.m_load_error.eq(0),
69 self.m_store_error.eq(0)
70 ]
71
72 m.d.comb += self.x_busy.eq(self.dbus.cyc)
73
74 with m.If(self.m_load_error | self.m_store_error):
75 m.d.comb += self.m_busy.eq(0)
76 with m.Else():
77 m.d.comb += self.m_busy.eq(self.dbus.cyc)
78
79 return m
80
81
82 class CachedLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
83 def __init__(self, *dcache_args):
84 super().__init__()
85
86 self.dcache_args = dcache_args
87
88 self.x_fence_i = Signal()
89 self.x_flush = Signal()
90 self.m_addr = Signal(32)
91 self.m_load = Signal()
92 self.m_store = Signal()
93
94 def elaborate(self, platform):
95 m = Module()
96
97 dcache = m.submodules.dcache = L1Cache(*self.dcache_args)
98
99 x_dcache_select = Signal()
100 m_dcache_select = Signal()
101
102 m.d.comb += x_dcache_select.eq((self.x_addr >= dcache.base) &
103 (self.x_addr < dcache.limit))
104 with m.If(~self.x_stall):
105 m.d.sync += m_dcache_select.eq(x_dcache_select)
106
107 m.d.comb += [
108 dcache.s1_addr.eq(self.x_addr[2:]),
109 dcache.s1_flush.eq(self.x_flush),
110 dcache.s1_stall.eq(self.x_stall),
111 dcache.s1_valid.eq(self.x_valid & x_dcache_select),
112 dcache.s2_addr.eq(self.m_addr[2:]),
113 dcache.s2_re.eq(self.m_load),
114 dcache.s2_evict.eq(self.m_store),
115 dcache.s2_valid.eq(self.m_valid & m_dcache_select)
116 ]
117
118 wrbuf_w_data = Record([("addr", 30), ("mask", 4), ("data", 32)])
119 wrbuf_r_data = Record.like(wrbuf_w_data)
120 wrbuf = m.submodules.wrbuf = SyncFIFO(width=len(wrbuf_w_data),
121 depth=dcache.nwords)
122 m.d.comb += [
123 wrbuf.w_data.eq(wrbuf_w_data),
124 wrbuf_w_data.addr.eq(self.x_addr[2:]),
125 wrbuf_w_data.mask.eq(self.x_mask),
126 wrbuf_w_data.data.eq(self.x_store_data),
127 wrbuf.w_en.eq(self.x_store & self.x_valid &
128 x_dcache_select & ~self.x_stall),
129 wrbuf_r_data.eq(wrbuf.r_data),
130 ]
131
132 dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
133 m.d.comb += dbus_arbiter.bus.connect(self.dbus)
134
135 wrbuf_port = dbus_arbiter.port(priority=0)
136 with m.If(wrbuf_port.cyc):
137 with m.If(wrbuf_port.ack | wrbuf_port.err):
138 m.d.sync += [
139 wrbuf_port.cyc.eq(0),
140 wrbuf_port.stb.eq(0)
141 ]
142 m.d.comb += wrbuf.r_en.eq(1)
143 with m.Elif(wrbuf.r_rdy):
144 m.d.sync += [
145 wrbuf_port.cyc.eq(1),
146 wrbuf_port.stb.eq(1),
147 wrbuf_port.adr.eq(wrbuf_r_data.addr),
148 wrbuf_port.sel.eq(wrbuf_r_data.mask),
149 wrbuf_port.dat_w.eq(wrbuf_r_data.data)
150 ]
151 m.d.comb += wrbuf_port.we.eq(Const(1))
152
153 dcache_port = dbus_arbiter.port(priority=1)
154 m.d.comb += [
155 cti = Mux(dcache.bus_last, Cycle.END, Cycle.INCREMENT)
156 dcache_port.cyc.eq(dcache.bus_re),
157 dcache_port.stb.eq(dcache.bus_re),
158 dcache_port.adr.eq(dcache.bus_addr),
159 dcache_port.cti.eq(cti),
160 dcache_port.bte.eq(Const(log2_int(dcache.nwords) - 1)),
161 dcache.bus_valid.eq(dcache_port.ack),
162 dcache.bus_error.eq(dcache_port.err),
163 dcache.bus_rdata.eq(dcache_port.dat_r)
164 ]
165
166 bare_port = dbus_arbiter.port(priority=2)
167 bare_rdata = Signal.like(bare_port.dat_r)
168 with m.If(bare_port.cyc):
169 with m.If(bare_port.ack | bare_port.err | ~self.m_valid):
170 m.d.sync += [
171 bare_port.cyc.eq(0),
172 bare_port.stb.eq(0),
173 bare_rdata.eq(bare_port.dat_r)
174 ]
175 with m.Elif((self.x_load | self.x_store) &
176 ~x_dcache_select & self.x_valid & ~self.x_stall):
177 m.d.sync += [
178 bare_port.cyc.eq(1),
179 bare_port.stb.eq(1),
180 bare_port.adr.eq(self.x_addr[2:]),
181 bare_port.sel.eq(self.x_mask),
182 bare_port.we.eq(self.x_store),
183 bare_port.dat_w.eq(self.x_store_data)
184 ]
185
186 with m.If(self.dbus.cyc & self.dbus.err):
187 m.d.sync += [
188 self.m_load_error.eq(~self.dbus.we),
189 self.m_store_error.eq(self.dbus.we),
190 self.m_badaddr.eq(self.dbus.adr)
191 ]
192 with m.Elif(~self.m_stall):
193 m.d.sync += [
194 self.m_load_error.eq(0),
195 self.m_store_error.eq(0)
196 ]
197
198 with m.If(self.x_fence_i):
199 m.d.comb += self.x_busy.eq(wrbuf.r_rdy)
200 with m.Elif(x_dcache_select):
201 m.d.comb += self.x_busy.eq(self.x_store & ~wrbuf.w_rdy)
202 with m.Else():
203 m.d.comb += self.x_busy.eq(bare_port.cyc)
204
205 with m.If(self.m_load_error | self.m_store_error):
206 m.d.comb += [
207 self.m_busy.eq(0),
208 self.m_load_data.eq(0)
209 ]
210 with m.Elif(m_dcache_select):
211 m.d.comb += [
212 self.m_busy.eq(dcache.s2_re & dcache.s2_miss),
213 self.m_load_data.eq(dcache.s2_rdata)
214 ]
215 with m.Else():
216 m.d.comb += [
217 self.m_busy.eq(bare_port.cyc),
218 self.m_load_data.eq(bare_rdata)
219 ]
220
221 return m