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 wishbone_layout
, WishboneArbiter
, Cycle
9 __all__
= ["LoadStoreUnitInterface", "BareLoadStoreUnit",
10 "CachedLoadStoreUnit"]
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?
19 self
.x_addr_i
= Signal(addr_wid
) # address used for loads/stores
20 self
.x_mask_i
= Signal(mask_wid
) # Mask of which bytes to write
21 self
.x_ld_i
= Signal() # set to do a memory load
22 self
.x_st_i
= Signal() # set to do a memory store
23 self
.x_st_data_i
= Signal(data_wid
) # The data to write when storing
25 self
.x_stall_i
= Signal() # do nothing until low
26 self
.x_valid_i
= Signal() # Whether x pipeline stage is
27 # currently enabled (I
28 # think?). Set to 1 for #now
29 self
.m_stall_i
= Signal() # do nothing until low
30 self
.m_valid_i
= Signal() # Whether m pipeline stage is
31 # currently enabled. Set
35 self
.x_busy_o
= Signal() # set when the memory is busy
36 self
.m_busy_o
= Signal() # set when the memory is busy
38 self
.m_ld_data_o
= Signal(data_wid
) # Data returned from memory read
39 # Data validity is NOT indicated by m_valid_i or x_valid_i as
40 # those are inputs. I believe it is valid on the next cycle
41 # after raising m_load where busy is low
43 self
.m_load_err_o
= Signal() # if there was an error when loading
44 self
.m_store_err_o
= Signal() # if there was an error when storing
45 self
.m_badaddr_o
= Signal(badwid
) # The address of the load/store error
48 class BareLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
49 def elaborate(self
, platform
):
52 with m
.If(self
.dbus
.cyc
):
53 with m
.If(self
.dbus
.ack | self
.dbus
.err | ~self
.m_valid_i
):
57 self
.m_ld_data_o
.eq(self
.dbus
.dat_r
)
59 with m
.Elif((self
.x_ld_i | self
.x_st_i
) &
60 self
.x_valid_i
& ~self
.x_stall_i
):
64 self
.dbus
.adr
.eq(self
.x_addr_i
[2:]),
65 self
.dbus
.sel
.eq(self
.x_mask_i
),
66 self
.dbus
.we
.eq(self
.x_st_i
),
67 self
.dbus
.dat_w
.eq(self
.x_st_data_i
)
70 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
72 self
.m_load_err_o
.eq(~self
.dbus
.we
),
73 self
.m_store_err_o
.eq(self
.dbus
.we
),
74 self
.m_badaddr_o
.eq(self
.dbus
.adr
)
76 with m
.Elif(~self
.m_stall_i
):
78 self
.m_load_err_o
.eq(0),
79 self
.m_store_err_o
.eq(0)
82 m
.d
.comb
+= self
.x_busy_o
.eq(self
.dbus
.cyc
)
84 with m
.If(self
.m_load_err_o | self
.m_store_err_o
):
85 m
.d
.comb
+= self
.m_busy_o
.eq(0)
87 m
.d
.comb
+= self
.m_busy_o
.eq(self
.dbus
.cyc
)
92 class CachedLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
93 def __init__(self
, *dcache_args
):
96 self
.dcache_args
= dcache_args
98 self
.x_fence_i
= Signal()
99 self
.x_flush
= Signal()
100 self
.m_addr
= Signal(32)
101 self
.m_load
= Signal()
102 self
.m_store
= Signal()
104 def elaborate(self
, platform
):
107 dcache
= m
.submodules
.dcache
= L1Cache(*self
.dcache_args
)
109 x_dcache_select
= Signal()
110 m_dcache_select
= Signal()
112 m
.d
.comb
+= x_dcache_select
.eq((self
.x_addr_i
>= dcache
.base
) &
113 (self
.x_addr_i
< dcache
.limit
))
114 with m
.If(~self
.x_stall_i
):
115 m
.d
.sync
+= m_dcache_select
.eq(x_dcache_select
)
118 dcache
.s1_addr
.eq(self
.x_addr_i
[2:]),
119 dcache
.s1_flush
.eq(self
.x_flush
),
120 dcache
.s1_stall
.eq(self
.x_stall_i
),
121 dcache
.s1_valid
.eq(self
.x_valid_i
& x_dcache_select
),
122 dcache
.s2_addr
.eq(self
.m_addr
[2:]),
123 dcache
.s2_re
.eq(self
.m_load
),
124 dcache
.s2_evict
.eq(self
.m_store
),
125 dcache
.s2_valid
.eq(self
.m_valid_i
& m_dcache_select
)
128 wrbuf_w_data
= Record([("addr", 30), ("mask", 4), ("data", 32)])
129 wrbuf_r_data
= Record
.like(wrbuf_w_data
)
130 wrbuf
= m
.submodules
.wrbuf
= SyncFIFO(width
=len(wrbuf_w_data
),
133 wrbuf
.w_data
.eq(wrbuf_w_data
),
134 wrbuf_w_data
.addr
.eq(self
.x_addr_i
[2:]),
135 wrbuf_w_data
.mask
.eq(self
.x_mask_i
),
136 wrbuf_w_data
.data
.eq(self
.x_st_data_i
),
137 wrbuf
.w_en
.eq(self
.x_st_i
& self
.x_valid_i
&
138 x_dcache_select
& ~self
.x_stall_i
),
139 wrbuf_r_data
.eq(wrbuf
.r_data
),
142 dbus_arbiter
= m
.submodules
.dbus_arbiter
= WishboneArbiter()
143 m
.d
.comb
+= dbus_arbiter
.bus
.connect(self
.dbus
)
145 wrbuf_port
= dbus_arbiter
.port(priority
=0)
146 with m
.If(wrbuf_port
.cyc
):
147 with m
.If(wrbuf_port
.ack | wrbuf_port
.err
):
149 wrbuf_port
.cyc
.eq(0),
152 m
.d
.comb
+= wrbuf
.r_en
.eq(1)
153 with m
.Elif(wrbuf
.r_rdy
):
155 wrbuf_port
.cyc
.eq(1),
156 wrbuf_port
.stb
.eq(1),
157 wrbuf_port
.adr
.eq(wrbuf_r_data
.addr
),
158 wrbuf_port
.sel
.eq(wrbuf_r_data
.mask
),
159 wrbuf_port
.dat_w
.eq(wrbuf_r_data
.data
)
161 m
.d
.comb
+= wrbuf_port
.we
.eq(Const(1))
163 dcache_port
= dbus_arbiter
.port(priority
=1)
164 cti
= Mux(dcache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)
166 dcache_port
.cyc
.eq(dcache
.bus_re
),
167 dcache_port
.stb
.eq(dcache
.bus_re
),
168 dcache_port
.adr
.eq(dcache
.bus_addr
),
169 dcache_port
.cti
.eq(cti
),
170 dcache_port
.bte
.eq(Const(log2_int(dcache
.nwords
) - 1)),
171 dcache
.bus_valid
.eq(dcache_port
.ack
),
172 dcache
.bus_error
.eq(dcache_port
.err
),
173 dcache
.bus_rdata
.eq(dcache_port
.dat_r
)
176 bare_port
= dbus_arbiter
.port(priority
=2)
177 bare_rdata
= Signal
.like(bare_port
.dat_r
)
178 with m
.If(bare_port
.cyc
):
179 with m
.If(bare_port
.ack | bare_port
.err | ~self
.m_valid_i
):
183 bare_rdata
.eq(bare_port
.dat_r
)
185 with m
.Elif((self
.x_ld_i | self
.x_st_i
) &
186 ~x_dcache_select
& self
.x_valid_i
& ~self
.x_stall_i
):
190 bare_port
.adr
.eq(self
.x_addr_i
[2:]),
191 bare_port
.sel
.eq(self
.x_mask_i
),
192 bare_port
.we
.eq(self
.x_st_i
),
193 bare_port
.dat_w
.eq(self
.x_st_data_i
)
196 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
198 self
.m_load_err_o
.eq(~self
.dbus
.we
),
199 self
.m_store_err_o
.eq(self
.dbus
.we
),
200 self
.m_badaddr_o
.eq(self
.dbus
.adr
)
202 with m
.Elif(~self
.m_stall_i
):
204 self
.m_load_err_o
.eq(0),
205 self
.m_store_err_o
.eq(0)
208 with m
.If(self
.x_fence_i
):
209 m
.d
.comb
+= self
.x_busy_o
.eq(wrbuf
.r_rdy
)
210 with m
.Elif(x_dcache_select
):
211 m
.d
.comb
+= self
.x_busy_o
.eq(self
.x_st_i
& ~wrbuf
.w_rdy
)
213 m
.d
.comb
+= self
.x_busy_o
.eq(bare_port
.cyc
)
215 with m
.If(self
.m_load_err_o | self
.m_store_err_o
):
218 self
.m_ld_data_o
.eq(0)
220 with m
.Elif(m_dcache_select
):
222 self
.m_busy_o
.eq(dcache
.s2_re
& dcache
.s2_miss
),
223 self
.m_ld_data_o
.eq(dcache
.s2_rdata
)
227 self
.m_busy_o
.eq(bare_port
.cyc
),
228 self
.m_ld_data_o
.eq(bare_rdata
)