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
:
15 self
.dbus
= Record(wishbone_layout
)
17 self
.x_addr
= Signal(32)
18 self
.x_mask
= Signal(4)
19 self
.x_load
= Signal()
20 self
.x_store
= Signal()
21 self
.x_store_data
= Signal(32)
22 self
.x_stall
= Signal()
23 self
.x_valid
= Signal()
24 self
.m_stall
= Signal()
25 self
.m_valid
= Signal()
27 self
.x_busy
= Signal()
28 self
.m_busy
= Signal()
29 self
.m_load_data
= Signal(32)
30 self
.m_load_error
= Signal()
31 self
.m_store_error
= Signal()
32 self
.m_badaddr
= Signal(30)
35 class BareLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
36 def elaborate(self
, platform
):
39 with m
.If(self
.dbus
.cyc
):
40 with m
.If(self
.dbus
.ack | self
.dbus
.err | ~self
.m_valid
):
44 self
.m_load_data
.eq(self
.dbus
.dat_r
)
46 with m
.Elif((self
.x_load | self
.x_store
) &
47 self
.x_valid
& ~self
.x_stall
):
51 self
.dbus
.adr
.eq(self
.x_addr
[2:]),
52 self
.dbus
.sel
.eq(self
.x_mask
),
53 self
.dbus
.we
.eq(self
.x_store
),
54 self
.dbus
.dat_w
.eq(self
.x_store_data
)
57 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
59 self
.m_load_error
.eq(~self
.dbus
.we
),
60 self
.m_store_error
.eq(self
.dbus
.we
),
61 self
.m_badaddr
.eq(self
.dbus
.adr
)
63 with m
.Elif(~self
.m_stall
):
65 self
.m_load_error
.eq(0),
66 self
.m_store_error
.eq(0)
69 m
.d
.comb
+= self
.x_busy
.eq(self
.dbus
.cyc
)
71 with m
.If(self
.m_load_error | self
.m_store_error
):
72 m
.d
.comb
+= self
.m_busy
.eq(0)
74 m
.d
.comb
+= self
.m_busy
.eq(self
.dbus
.cyc
)
79 class CachedLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
80 def __init__(self
, *dcache_args
):
83 self
.dcache_args
= dcache_args
85 self
.x_fence_i
= Signal()
86 self
.x_flush
= Signal()
87 self
.m_addr
= Signal(32)
88 self
.m_load
= Signal()
89 self
.m_store
= Signal()
91 def elaborate(self
, platform
):
94 dcache
= m
.submodules
.dcache
= L1Cache(*self
.dcache_args
)
96 x_dcache_select
= Signal()
97 m_dcache_select
= Signal()
99 m
.d
.comb
+= x_dcache_select
.eq((self
.x_addr
>= dcache
.base
) &
100 (self
.x_addr
< dcache
.limit
))
101 with m
.If(~self
.x_stall
):
102 m
.d
.sync
+= m_dcache_select
.eq(x_dcache_select
)
105 dcache
.s1_addr
.eq(self
.x_addr
[2:]),
106 dcache
.s1_flush
.eq(self
.x_flush
),
107 dcache
.s1_stall
.eq(self
.x_stall
),
108 dcache
.s1_valid
.eq(self
.x_valid
& x_dcache_select
),
109 dcache
.s2_addr
.eq(self
.m_addr
[2:]),
110 dcache
.s2_re
.eq(self
.m_load
),
111 dcache
.s2_evict
.eq(self
.m_store
),
112 dcache
.s2_valid
.eq(self
.m_valid
& m_dcache_select
)
115 wrbuf_w_data
= Record([("addr", 30), ("mask", 4), ("data", 32)])
116 wrbuf_r_data
= Record
.like(wrbuf_w_data
)
117 wrbuf
= m
.submodules
.wrbuf
= SyncFIFO(width
=len(wrbuf_w_data
),
120 wrbuf
.w_data
.eq(wrbuf_w_data
),
121 wrbuf_w_data
.addr
.eq(self
.x_addr
[2:]),
122 wrbuf_w_data
.mask
.eq(self
.x_mask
),
123 wrbuf_w_data
.data
.eq(self
.x_store_data
),
124 wrbuf
.w_en
.eq(self
.x_store
& self
.x_valid
&
125 x_dcache_select
& ~self
.x_stall
),
126 wrbuf_r_data
.eq(wrbuf
.r_data
),
129 dbus_arbiter
= m
.submodules
.dbus_arbiter
= WishboneArbiter()
130 m
.d
.comb
+= dbus_arbiter
.bus
.connect(self
.dbus
)
132 wrbuf_port
= dbus_arbiter
.port(priority
=0)
133 with m
.If(wrbuf_port
.cyc
):
134 with m
.If(wrbuf_port
.ack | wrbuf_port
.err
):
136 wrbuf_port
.cyc
.eq(0),
139 m
.d
.comb
+= wrbuf
.r_en
.eq(1)
140 with m
.Elif(wrbuf
.r_rdy
):
142 wrbuf_port
.cyc
.eq(1),
143 wrbuf_port
.stb
.eq(1),
144 wrbuf_port
.adr
.eq(wrbuf_r_data
.addr
),
145 wrbuf_port
.sel
.eq(wrbuf_r_data
.mask
),
146 wrbuf_port
.dat_w
.eq(wrbuf_r_data
.data
)
148 m
.d
.comb
+= wrbuf_port
.we
.eq(Const(1))
150 dcache_port
= dbus_arbiter
.port(priority
=1)
152 cti
= Mux(dcache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)
153 dcache_port
.cyc
.eq(dcache
.bus_re
),
154 dcache_port
.stb
.eq(dcache
.bus_re
),
155 dcache_port
.adr
.eq(dcache
.bus_addr
),
156 dcache_port
.cti
.eq(cti
),
157 dcache_port
.bte
.eq(Const(log2_int(dcache
.nwords
) - 1)),
158 dcache
.bus_valid
.eq(dcache_port
.ack
),
159 dcache
.bus_error
.eq(dcache_port
.err
),
160 dcache
.bus_rdata
.eq(dcache_port
.dat_r
)
163 bare_port
= dbus_arbiter
.port(priority
=2)
164 bare_rdata
= Signal
.like(bare_port
.dat_r
)
165 with m
.If(bare_port
.cyc
):
166 with m
.If(bare_port
.ack | bare_port
.err | ~self
.m_valid
):
170 bare_rdata
.eq(bare_port
.dat_r
)
172 with m
.Elif((self
.x_load | self
.x_store
) &
173 ~x_dcache_select
& self
.x_valid
& ~self
.x_stall
):
177 bare_port
.adr
.eq(self
.x_addr
[2:]),
178 bare_port
.sel
.eq(self
.x_mask
),
179 bare_port
.we
.eq(self
.x_store
),
180 bare_port
.dat_w
.eq(self
.x_store_data
)
183 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
185 self
.m_load_error
.eq(~self
.dbus
.we
),
186 self
.m_store_error
.eq(self
.dbus
.we
),
187 self
.m_badaddr
.eq(self
.dbus
.adr
)
189 with m
.Elif(~self
.m_stall
):
191 self
.m_load_error
.eq(0),
192 self
.m_store_error
.eq(0)
195 with m
.If(self
.x_fence_i
):
196 m
.d
.comb
+= self
.x_busy
.eq(wrbuf
.r_rdy
)
197 with m
.Elif(x_dcache_select
):
198 m
.d
.comb
+= self
.x_busy
.eq(self
.x_store
& ~wrbuf
.w_rdy
)
200 m
.d
.comb
+= self
.x_busy
.eq(bare_port
.cyc
)
202 with m
.If(self
.m_load_error | self
.m_store_error
):
205 self
.m_load_data
.eq(0)
207 with m
.Elif(m_dcache_select
):
209 self
.m_busy
.eq(dcache
.s2_re
& dcache
.s2_miss
),
210 self
.m_load_data
.eq(dcache
.s2_rdata
)
214 self
.m_busy
.eq(bare_port
.cyc
),
215 self
.m_load_data
.eq(bare_rdata
)