clean up output from BareLoadStoreUnit
[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 make_wb_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 print ("loadstoreunit addr mask data", addr_wid, mask_wid, data_wid)
16 self.dbus = Record(make_wb_layout(addr_wid, mask_wid, data_wid))
17 print (self.dbus.sel.shape())
18 self.mask_wid = mask_wid
19 self.addr_wid = addr_wid
20 self.data_wid = data_wid
21 self.adr_lsbs = log2_int(mask_wid) # LSBs of addr covered by mask
22 badwid = addr_wid-self.adr_lsbs # TODO: is this correct?
23
24 # INPUTS
25 self.x_addr_i = Signal(addr_wid) # address used for loads/stores
26 self.x_mask_i = Signal(mask_wid) # Mask of which bytes to write
27 self.x_ld_i = Signal() # set to do a memory load
28 self.x_st_i = Signal() # set to do a memory store
29 self.x_st_data_i = Signal(data_wid) # The data to write when storing
30
31 self.x_stall_i = Signal() # do nothing until low
32 self.x_valid_i = Signal() # Whether x pipeline stage is
33 # currently enabled (I
34 # think?). Set to 1 for #now
35 self.m_stall_i = Signal() # do nothing until low
36 self.m_valid_i = Signal() # Whether m pipeline stage is
37 # currently enabled. Set
38 # to 1 for now
39
40 # OUTPUTS
41 self.x_busy_o = Signal() # set when the memory is busy
42 self.m_busy_o = Signal() # set when the memory is busy
43
44 self.m_ld_data_o = Signal(data_wid) # Data returned from memory read
45 # Data validity is NOT indicated by m_valid_i or x_valid_i as
46 # those are inputs. I believe it is valid on the next cycle
47 # after raising m_load where busy is low
48
49 self.m_load_err_o = Signal() # if there was an error when loading
50 self.m_store_err_o = Signal() # if there was an error when storing
51 self.m_badaddr_o = Signal(badwid) # The address of the load/store error
52
53
54 class BareLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
55 def elaborate(self, platform):
56 m = Module()
57
58 with m.If(self.dbus.cyc):
59 with m.If(self.dbus.ack | self.dbus.err | ~self.m_valid_i):
60 m.d.sync += [
61 self.dbus.cyc.eq(0),
62 self.dbus.stb.eq(0),
63 self.m_ld_data_o.eq(self.dbus.dat_r)
64 ]
65 with m.Elif((self.x_ld_i | self.x_st_i) &
66 self.x_valid_i & ~self.x_stall_i):
67 m.d.sync += [
68 self.dbus.cyc.eq(1),
69 self.dbus.stb.eq(1),
70 self.dbus.adr.eq(self.x_addr_i[self.adr_lsbs:]),
71 self.dbus.sel.eq(self.x_mask_i),
72 self.dbus.we.eq(self.x_st_i),
73 self.dbus.dat_w.eq(self.x_st_data_i)
74 ]
75 with m.Else():
76 m.d.sync += [
77 self.dbus.adr.eq(0),
78 self.dbus.sel.eq(0),
79 self.dbus.we.eq(0),
80 self.dbus.sel.eq(0),
81 self.dbus.dat_w.eq(0),
82 ]
83
84 with m.If(self.dbus.cyc & self.dbus.err):
85 m.d.sync += [
86 self.m_load_err_o.eq(~self.dbus.we),
87 self.m_store_err_o.eq(self.dbus.we),
88 self.m_badaddr_o.eq(self.dbus.adr)
89 ]
90 with m.Elif(~self.m_stall_i):
91 m.d.sync += [
92 self.m_load_err_o.eq(0),
93 self.m_store_err_o.eq(0)
94 ]
95
96 m.d.comb += self.x_busy_o.eq(self.dbus.cyc)
97
98 with m.If(self.m_load_err_o | self.m_store_err_o):
99 m.d.comb += self.m_busy_o.eq(0)
100 with m.Else():
101 m.d.comb += self.m_busy_o.eq(self.dbus.cyc)
102
103 return m
104
105
106 class CachedLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
107 def __init__(self, *dcache_args, addr_wid=32, mask_wid=4, data_wid=32):
108 super().__init__(addr_wid, mask_wid, data_wid)
109
110 self.dcache_args = dcache_args
111
112 self.x_fence_i = Signal()
113 self.x_flush = Signal()
114 self.m_addr = Signal(addr_wid)
115 self.m_load = Signal()
116 self.m_store = Signal()
117
118 def elaborate(self, platform):
119 m = Module()
120
121 dcache = m.submodules.dcache = L1Cache(*self.dcache_args)
122
123 x_dcache_select = Signal()
124 m_dcache_select = Signal()
125
126 m.d.comb += x_dcache_select.eq((self.x_addr_i >= dcache.base) &
127 (self.x_addr_i < dcache.limit))
128 with m.If(~self.x_stall_i):
129 m.d.sync += m_dcache_select.eq(x_dcache_select)
130
131 m.d.comb += [
132 dcache.s1_addr.eq(self.x_addr_i[self.adr_lsbs:]),
133 dcache.s1_flush.eq(self.x_flush),
134 dcache.s1_stall.eq(self.x_stall_i),
135 dcache.s1_valid.eq(self.x_valid_i & x_dcache_select),
136 dcache.s2_addr.eq(self.m_addr[self.adr_lsbs:]),
137 dcache.s2_re.eq(self.m_load),
138 dcache.s2_evict.eq(self.m_store),
139 dcache.s2_valid.eq(self.m_valid_i & m_dcache_select)
140 ]
141
142 wrbuf_w_data = Record([("addr", self.addr_wid-self.adr_lsbs),
143 ("mask", self.mask_wid),
144 ("data", self.data_wid)])
145 wrbuf_r_data = Record.like(wrbuf_w_data)
146 wrbuf = m.submodules.wrbuf = SyncFIFO(width=len(wrbuf_w_data),
147 depth=dcache.nwords)
148 m.d.comb += [
149 wrbuf.w_data.eq(wrbuf_w_data),
150 wrbuf_w_data.addr.eq(self.x_addr_i[self.adr_lsbs:]),
151 wrbuf_w_data.mask.eq(self.x_mask_i),
152 wrbuf_w_data.data.eq(self.x_st_data_i),
153 wrbuf.w_en.eq(self.x_st_i & self.x_valid_i &
154 x_dcache_select & ~self.x_stall_i),
155 wrbuf_r_data.eq(wrbuf.r_data),
156 ]
157
158 dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
159 m.d.comb += dbus_arbiter.bus.connect(self.dbus)
160
161 wrbuf_port = dbus_arbiter.port(priority=0)
162 with m.If(wrbuf_port.cyc):
163 with m.If(wrbuf_port.ack | wrbuf_port.err):
164 m.d.sync += [
165 wrbuf_port.cyc.eq(0),
166 wrbuf_port.stb.eq(0)
167 ]
168 m.d.comb += wrbuf.r_en.eq(1)
169 with m.Elif(wrbuf.r_rdy):
170 m.d.sync += [
171 wrbuf_port.cyc.eq(1),
172 wrbuf_port.stb.eq(1),
173 wrbuf_port.adr.eq(wrbuf_r_data.addr),
174 wrbuf_port.sel.eq(wrbuf_r_data.mask),
175 wrbuf_port.dat_w.eq(wrbuf_r_data.data)
176 ]
177 m.d.comb += wrbuf_port.we.eq(Const(1))
178
179 dcache_port = dbus_arbiter.port(priority=1)
180 cti = Mux(dcache.bus_last, Cycle.END, Cycle.INCREMENT)
181 m.d.comb += [
182 dcache_port.cyc.eq(dcache.bus_re),
183 dcache_port.stb.eq(dcache.bus_re),
184 dcache_port.adr.eq(dcache.bus_addr),
185 dcache_port.cti.eq(cti),
186 dcache_port.bte.eq(Const(log2_int(dcache.nwords) - 1)),
187 dcache.bus_valid.eq(dcache_port.ack),
188 dcache.bus_error.eq(dcache_port.err),
189 dcache.bus_rdata.eq(dcache_port.dat_r)
190 ]
191
192 bare_port = dbus_arbiter.port(priority=2)
193 bare_rdata = Signal.like(bare_port.dat_r)
194 with m.If(bare_port.cyc):
195 with m.If(bare_port.ack | bare_port.err | ~self.m_valid_i):
196 m.d.sync += [
197 bare_port.cyc.eq(0),
198 bare_port.stb.eq(0),
199 bare_rdata.eq(bare_port.dat_r)
200 ]
201 with m.Elif((self.x_ld_i | self.x_st_i) &
202 ~x_dcache_select & self.x_valid_i & ~self.x_stall_i):
203 m.d.sync += [
204 bare_port.cyc.eq(1),
205 bare_port.stb.eq(1),
206 bare_port.adr.eq(self.x_addr_i[self.adr_lsbs:]),
207 bare_port.sel.eq(self.x_mask_i),
208 bare_port.we.eq(self.x_st_i),
209 bare_port.dat_w.eq(self.x_st_data_i)
210 ]
211
212 with m.If(self.dbus.cyc & self.dbus.err):
213 m.d.sync += [
214 self.m_load_err_o.eq(~self.dbus.we),
215 self.m_store_err_o.eq(self.dbus.we),
216 self.m_badaddr_o.eq(self.dbus.adr)
217 ]
218 with m.Elif(~self.m_stall_i):
219 m.d.sync += [
220 self.m_load_err_o.eq(0),
221 self.m_store_err_o.eq(0)
222 ]
223
224 with m.If(self.x_fence_i):
225 m.d.comb += self.x_busy_o.eq(wrbuf.r_rdy)
226 with m.Elif(x_dcache_select):
227 m.d.comb += self.x_busy_o.eq(self.x_st_i & ~wrbuf.w_rdy)
228 with m.Else():
229 m.d.comb += self.x_busy_o.eq(bare_port.cyc)
230
231 with m.If(self.m_load_err_o | self.m_store_err_o):
232 m.d.comb += [
233 self.m_busy_o.eq(0),
234 self.m_ld_data_o.eq(0)
235 ]
236 with m.Elif(m_dcache_select):
237 m.d.comb += [
238 self.m_busy_o.eq(dcache.s2_re & dcache.s2_miss),
239 self.m_ld_data_o.eq(dcache.s2_rdata)
240 ]
241 with m.Else():
242 m.d.comb += [
243 self.m_busy_o.eq(bare_port.cyc),
244 self.m_ld_data_o.eq(bare_rdata)
245 ]
246
247 return m