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
5 from soc
.minerva
.cache
import L1Cache
6 from soc
.minerva
.wishbone
import make_wb_layout
, WishboneArbiter
, Cycle
9 __all__
= ["LoadStoreUnitInterface", "BareLoadStoreUnit",
10 "CachedLoadStoreUnit"]
13 class LoadStoreUnitInterface
:
14 def __init__(self
, pspec
):
16 self
.dbus
= Record(make_wb_layout(pspec
))
17 print (self
.dbus
.sel
.shape())
18 self
.mask_wid
= mask_wid
= pspec
.mask_wid
19 self
.addr_wid
= addr_wid
= pspec
.addr_wid
20 self
.data_wid
= data_wid
= pspec
.reg_wid
21 print ("loadstoreunit addr mask data", addr_wid
, mask_wid
, data_wid
)
22 self
.adr_lsbs
= log2_int(mask_wid
) # LSBs of addr covered by mask
23 badwid
= addr_wid
-self
.adr_lsbs
# TODO: is this correct?
26 self
.x_addr_i
= Signal(addr_wid
) # address used for loads/stores
27 self
.x_mask_i
= Signal(mask_wid
) # Mask of which bytes to write
28 self
.x_ld_i
= Signal() # set to do a memory load
29 self
.x_st_i
= Signal() # set to do a memory store
30 self
.x_st_data_i
= Signal(data_wid
) # The data to write when storing
32 self
.x_stall_i
= Signal() # do nothing until low
33 self
.x_valid_i
= Signal() # Whether x pipeline stage is
34 # currently enabled (I
35 # think?). Set to 1 for #now
36 self
.m_stall_i
= Signal() # do nothing until low
37 self
.m_valid_i
= Signal() # Whether m pipeline stage is
38 # currently enabled. Set
42 self
.x_busy_o
= Signal() # set when the memory is busy
43 self
.m_busy_o
= Signal() # set when the memory is busy
45 self
.m_ld_data_o
= Signal(data_wid
) # Data returned from memory read
46 # Data validity is NOT indicated by m_valid_i or x_valid_i as
47 # those are inputs. I believe it is valid on the next cycle
48 # after raising m_load where busy is low
50 self
.m_load_err_o
= Signal() # if there was an error when loading
51 self
.m_store_err_o
= Signal() # if there was an error when storing
52 self
.m_badaddr_o
= Signal(badwid
) # The address of the load/store error
59 yield self
.x_st_data_i
67 yield self
.m_ld_data_o
68 yield self
.m_load_err_o
69 yield self
.m_store_err_o
70 yield self
.m_badaddr_o
71 for sig
in self
.dbus
.fields
.values():
78 class BareLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
79 def elaborate(self
, platform
):
82 with m
.If(self
.dbus
.cyc
):
83 with m
.If(self
.dbus
.ack | self
.dbus
.err | ~self
.m_valid_i
):
87 self
.m_ld_data_o
.eq(self
.dbus
.dat_r
)
89 with m
.Elif((self
.x_ld_i | self
.x_st_i
) &
90 self
.x_valid_i
& ~self
.x_stall_i
):
94 self
.dbus
.adr
.eq(self
.x_addr_i
[self
.adr_lsbs
:]),
95 self
.dbus
.sel
.eq(self
.x_mask_i
),
96 self
.dbus
.we
.eq(self
.x_st_i
),
97 self
.dbus
.dat_w
.eq(self
.x_st_data_i
)
105 self
.dbus
.dat_w
.eq(0),
108 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
110 self
.m_load_err_o
.eq(~self
.dbus
.we
),
111 self
.m_store_err_o
.eq(self
.dbus
.we
),
112 self
.m_badaddr_o
.eq(self
.dbus
.adr
)
114 with m
.Elif(~self
.m_stall_i
):
116 self
.m_load_err_o
.eq(0),
117 self
.m_store_err_o
.eq(0)
120 m
.d
.comb
+= self
.x_busy_o
.eq(self
.dbus
.cyc
)
122 with m
.If(self
.m_load_err_o | self
.m_store_err_o
):
123 m
.d
.comb
+= self
.m_busy_o
.eq(0)
125 m
.d
.comb
+= self
.m_busy_o
.eq(self
.dbus
.cyc
)
130 class CachedLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
131 def __init__(self
, pspec
):
132 super().__init
__(pspec
)
134 self
.dcache_args
= psiec
.dcache_args
136 self
.x_fence_i
= Signal()
137 self
.x_flush
= Signal()
138 self
.m_addr
= Signal(addr_wid
)
139 self
.m_load
= Signal()
140 self
.m_store
= Signal()
142 def elaborate(self
, platform
):
145 dcache
= m
.submodules
.dcache
= L1Cache(*self
.dcache_args
)
147 x_dcache_select
= Signal()
148 m_dcache_select
= Signal()
150 m
.d
.comb
+= x_dcache_select
.eq((self
.x_addr_i
>= dcache
.base
) &
151 (self
.x_addr_i
< dcache
.limit
))
152 with m
.If(~self
.x_stall_i
):
153 m
.d
.sync
+= m_dcache_select
.eq(x_dcache_select
)
156 dcache
.s1_addr
.eq(self
.x_addr_i
[self
.adr_lsbs
:]),
157 dcache
.s1_flush
.eq(self
.x_flush
),
158 dcache
.s1_stall
.eq(self
.x_stall_i
),
159 dcache
.s1_valid
.eq(self
.x_valid_i
& x_dcache_select
),
160 dcache
.s2_addr
.eq(self
.m_addr
[self
.adr_lsbs
:]),
161 dcache
.s2_re
.eq(self
.m_load
),
162 dcache
.s2_evict
.eq(self
.m_store
),
163 dcache
.s2_valid
.eq(self
.m_valid_i
& m_dcache_select
)
166 wrbuf_w_data
= Record([("addr", self
.addr_wid
-self
.adr_lsbs
),
167 ("mask", self
.mask_wid
),
168 ("data", self
.data_wid
)])
169 wrbuf_r_data
= Record
.like(wrbuf_w_data
)
170 wrbuf
= m
.submodules
.wrbuf
= SyncFIFO(width
=len(wrbuf_w_data
),
173 wrbuf
.w_data
.eq(wrbuf_w_data
),
174 wrbuf_w_data
.addr
.eq(self
.x_addr_i
[self
.adr_lsbs
:]),
175 wrbuf_w_data
.mask
.eq(self
.x_mask_i
),
176 wrbuf_w_data
.data
.eq(self
.x_st_data_i
),
177 wrbuf
.w_en
.eq(self
.x_st_i
& self
.x_valid_i
&
178 x_dcache_select
& ~self
.x_stall_i
),
179 wrbuf_r_data
.eq(wrbuf
.r_data
),
182 dba
= WishboneArbiter(self
.pspec
)
183 m
.submodules
.dbus_arbiter
= dba
184 m
.d
.comb
+= dba
.bus
.connect(self
.dbus
)
186 wrbuf_port
= dbus_arbiter
.port(priority
=0)
187 with m
.If(wrbuf_port
.cyc
):
188 with m
.If(wrbuf_port
.ack | wrbuf_port
.err
):
190 wrbuf_port
.cyc
.eq(0),
193 m
.d
.comb
+= wrbuf
.r_en
.eq(1)
194 with m
.Elif(wrbuf
.r_rdy
):
196 wrbuf_port
.cyc
.eq(1),
197 wrbuf_port
.stb
.eq(1),
198 wrbuf_port
.adr
.eq(wrbuf_r_data
.addr
),
199 wrbuf_port
.sel
.eq(wrbuf_r_data
.mask
),
200 wrbuf_port
.dat_w
.eq(wrbuf_r_data
.data
)
202 m
.d
.comb
+= wrbuf_port
.we
.eq(Const(1))
204 dcache_port
= dba
.port(priority
=1)
205 cti
= Mux(dcache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)
207 dcache_port
.cyc
.eq(dcache
.bus_re
),
208 dcache_port
.stb
.eq(dcache
.bus_re
),
209 dcache_port
.adr
.eq(dcache
.bus_addr
),
210 dcache_port
.cti
.eq(cti
),
211 dcache_port
.bte
.eq(Const(log2_int(dcache
.nwords
) - 1)),
212 dcache
.bus_valid
.eq(dcache_port
.ack
),
213 dcache
.bus_error
.eq(dcache_port
.err
),
214 dcache
.bus_rdata
.eq(dcache_port
.dat_r
)
217 bare_port
= dba
.port(priority
=2)
218 bare_rdata
= Signal
.like(bare_port
.dat_r
)
219 with m
.If(bare_port
.cyc
):
220 with m
.If(bare_port
.ack | bare_port
.err | ~self
.m_valid_i
):
224 bare_rdata
.eq(bare_port
.dat_r
)
226 with m
.Elif((self
.x_ld_i | self
.x_st_i
) &
227 ~x_dcache_select
& self
.x_valid_i
& ~self
.x_stall_i
):
231 bare_port
.adr
.eq(self
.x_addr_i
[self
.adr_lsbs
:]),
232 bare_port
.sel
.eq(self
.x_mask_i
),
233 bare_port
.we
.eq(self
.x_st_i
),
234 bare_port
.dat_w
.eq(self
.x_st_data_i
)
237 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
239 self
.m_load_err_o
.eq(~self
.dbus
.we
),
240 self
.m_store_err_o
.eq(self
.dbus
.we
),
241 self
.m_badaddr_o
.eq(self
.dbus
.adr
)
243 with m
.Elif(~self
.m_stall_i
):
245 self
.m_load_err_o
.eq(0),
246 self
.m_store_err_o
.eq(0)
249 with m
.If(self
.x_fence_i
):
250 m
.d
.comb
+= self
.x_busy_o
.eq(wrbuf
.r_rdy
)
251 with m
.Elif(x_dcache_select
):
252 m
.d
.comb
+= self
.x_busy_o
.eq(self
.x_st_i
& ~wrbuf
.w_rdy
)
254 m
.d
.comb
+= self
.x_busy_o
.eq(bare_port
.cyc
)
256 with m
.If(self
.m_load_err_o | self
.m_store_err_o
):
259 self
.m_ld_data_o
.eq(0)
261 with m
.Elif(m_dcache_select
):
263 self
.m_busy_o
.eq(dcache
.s2_re
& dcache
.s2_miss
),
264 self
.m_ld_data_o
.eq(dcache
.s2_rdata
)
268 self
.m_busy_o
.eq(bare_port
.cyc
),
269 self
.m_ld_data_o
.eq(bare_rdata
)