2 from nmigen
.utils
import log2_int
3 from nmigen
.lib
.fifo
import SyncFIFO
6 from ..isa
import Funct3
7 from ..wishbone
import *
10 __all__
= ["DataSelector", "LoadStoreUnitInterface", "BareLoadStoreUnit", "CachedLoadStoreUnit"]
13 class DataSelector(Elaboratable
):
15 self
.x_offset
= Signal(2)
16 self
.x_funct3
= Signal(3)
17 self
.x_store_operand
= Signal(32)
18 self
.w_offset
= Signal(2)
19 self
.w_funct3
= Signal(3)
20 self
.w_load_data
= Signal(32)
22 self
.x_misaligned
= Signal()
23 self
.x_mask
= Signal(4)
24 self
.x_store_data
= Signal(32)
25 self
.w_load_result
= Signal((32, True))
27 def elaborate(self
, platform
):
30 with m
.Switch(self
.x_funct3
):
31 with m
.Case(Funct3
.H
, Funct3
.HU
):
32 m
.d
.comb
+= self
.x_misaligned
.eq(self
.x_offset
[0])
33 with m
.Case(Funct3
.W
):
34 m
.d
.comb
+= self
.x_misaligned
.eq(self
.x_offset
.bool())
36 with m
.Switch(self
.x_funct3
):
37 with m
.Case(Funct3
.B
, Funct3
.BU
):
38 m
.d
.comb
+= self
.x_mask
.eq(0b1 << self
.x_offset
)
39 with m
.Case(Funct3
.H
, Funct3
.HU
):
40 m
.d
.comb
+= self
.x_mask
.eq(0b11 << self
.x_offset
)
41 with m
.Case(Funct3
.W
):
42 m
.d
.comb
+= self
.x_mask
.eq(0b1111)
44 with m
.Switch(self
.x_funct3
):
45 with m
.Case(Funct3
.B
):
46 m
.d
.comb
+= self
.x_store_data
.eq(self
.x_store_operand
[:8] << self
.x_offset
*8)
47 with m
.Case(Funct3
.H
):
48 m
.d
.comb
+= self
.x_store_data
.eq(self
.x_store_operand
[:16] << self
.x_offset
[1]*16)
49 with m
.Case(Funct3
.W
):
50 m
.d
.comb
+= self
.x_store_data
.eq(self
.x_store_operand
)
52 w_byte
= Signal((8, True))
53 w_half
= Signal((16, True))
56 w_byte
.eq(self
.w_load_data
.word_select(self
.w_offset
, 8)),
57 w_half
.eq(self
.w_load_data
.word_select(self
.w_offset
[1], 16))
60 with m
.Switch(self
.w_funct3
):
61 with m
.Case(Funct3
.B
):
62 m
.d
.comb
+= self
.w_load_result
.eq(w_byte
)
63 with m
.Case(Funct3
.BU
):
64 m
.d
.comb
+= self
.w_load_result
.eq(Cat(w_byte
, 0))
65 with m
.Case(Funct3
.H
):
66 m
.d
.comb
+= self
.w_load_result
.eq(w_half
)
67 with m
.Case(Funct3
.HU
):
68 m
.d
.comb
+= self
.w_load_result
.eq(Cat(w_half
, 0))
69 with m
.Case(Funct3
.W
):
70 m
.d
.comb
+= self
.w_load_result
.eq(self
.w_load_data
)
75 class LoadStoreUnitInterface
:
77 self
.dbus
= Record(wishbone_layout
)
79 self
.x_addr
= Signal(32)
80 self
.x_mask
= Signal(4)
81 self
.x_load
= Signal()
82 self
.x_store
= Signal()
83 self
.x_store_data
= Signal(32)
84 self
.x_stall
= Signal()
85 self
.x_valid
= Signal()
86 self
.m_stall
= Signal()
87 self
.m_valid
= Signal()
89 self
.x_busy
= Signal()
90 self
.m_busy
= Signal()
91 self
.m_load_data
= Signal(32)
92 self
.m_load_error
= Signal()
93 self
.m_store_error
= Signal()
94 self
.m_badaddr
= Signal(30)
97 class BareLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
98 def elaborate(self
, platform
):
101 with m
.If(self
.dbus
.cyc
):
102 with m
.If(self
.dbus
.ack | self
.dbus
.err | ~self
.m_valid
):
106 self
.m_load_data
.eq(self
.dbus
.dat_r
)
108 with m
.Elif((self
.x_load | self
.x_store
) & self
.x_valid
& ~self
.x_stall
):
112 self
.dbus
.adr
.eq(self
.x_addr
[2:]),
113 self
.dbus
.sel
.eq(self
.x_mask
),
114 self
.dbus
.we
.eq(self
.x_store
),
115 self
.dbus
.dat_w
.eq(self
.x_store_data
)
118 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
120 self
.m_load_error
.eq(~self
.dbus
.we
),
121 self
.m_store_error
.eq(self
.dbus
.we
),
122 self
.m_badaddr
.eq(self
.dbus
.adr
)
124 with m
.Elif(~self
.m_stall
):
126 self
.m_load_error
.eq(0),
127 self
.m_store_error
.eq(0)
130 m
.d
.comb
+= self
.x_busy
.eq(self
.dbus
.cyc
)
132 with m
.If(self
.m_load_error | self
.m_store_error
):
133 m
.d
.comb
+= self
.m_busy
.eq(0)
135 m
.d
.comb
+= self
.m_busy
.eq(self
.dbus
.cyc
)
140 class CachedLoadStoreUnit(LoadStoreUnitInterface
, Elaboratable
):
141 def __init__(self
, *dcache_args
):
144 self
.dcache_args
= dcache_args
146 self
.x_fence_i
= Signal()
147 self
.x_flush
= Signal()
148 self
.m_addr
= Signal(32)
149 self
.m_load
= Signal()
150 self
.m_store
= Signal()
152 def elaborate(self
, platform
):
155 dcache
= m
.submodules
.dcache
= L1Cache(*self
.dcache_args
)
157 x_dcache_select
= Signal()
158 m_dcache_select
= Signal()
160 m
.d
.comb
+= x_dcache_select
.eq((self
.x_addr
>= dcache
.base
) & (self
.x_addr
< dcache
.limit
))
161 with m
.If(~self
.x_stall
):
162 m
.d
.sync
+= m_dcache_select
.eq(x_dcache_select
)
165 dcache
.s1_addr
.eq(self
.x_addr
[2:]),
166 dcache
.s1_flush
.eq(self
.x_flush
),
167 dcache
.s1_stall
.eq(self
.x_stall
),
168 dcache
.s1_valid
.eq(self
.x_valid
& x_dcache_select
),
169 dcache
.s2_addr
.eq(self
.m_addr
[2:]),
170 dcache
.s2_re
.eq(self
.m_load
),
171 dcache
.s2_evict
.eq(self
.m_store
),
172 dcache
.s2_valid
.eq(self
.m_valid
& m_dcache_select
)
175 wrbuf_w_data
= Record([("addr", 30), ("mask", 4), ("data", 32)])
176 wrbuf_r_data
= Record
.like(wrbuf_w_data
)
177 wrbuf
= m
.submodules
.wrbuf
= SyncFIFO(width
=len(wrbuf_w_data
), depth
=dcache
.nwords
)
179 wrbuf
.w_data
.eq(wrbuf_w_data
),
180 wrbuf_w_data
.addr
.eq(self
.x_addr
[2:]),
181 wrbuf_w_data
.mask
.eq(self
.x_mask
),
182 wrbuf_w_data
.data
.eq(self
.x_store_data
),
183 wrbuf
.w_en
.eq(self
.x_store
& self
.x_valid
& x_dcache_select
& ~self
.x_stall
),
184 wrbuf_r_data
.eq(wrbuf
.r_data
),
187 dbus_arbiter
= m
.submodules
.dbus_arbiter
= WishboneArbiter()
188 m
.d
.comb
+= dbus_arbiter
.bus
.connect(self
.dbus
)
190 wrbuf_port
= dbus_arbiter
.port(priority
=0)
191 with m
.If(wrbuf_port
.cyc
):
192 with m
.If(wrbuf_port
.ack | wrbuf_port
.err
):
194 wrbuf_port
.cyc
.eq(0),
197 m
.d
.comb
+= wrbuf
.r_en
.eq(1)
198 with m
.Elif(wrbuf
.r_rdy
):
200 wrbuf_port
.cyc
.eq(1),
201 wrbuf_port
.stb
.eq(1),
202 wrbuf_port
.adr
.eq(wrbuf_r_data
.addr
),
203 wrbuf_port
.sel
.eq(wrbuf_r_data
.mask
),
204 wrbuf_port
.dat_w
.eq(wrbuf_r_data
.data
)
206 m
.d
.comb
+= wrbuf_port
.we
.eq(Const(1))
208 dcache_port
= dbus_arbiter
.port(priority
=1)
210 dcache_port
.cyc
.eq(dcache
.bus_re
),
211 dcache_port
.stb
.eq(dcache
.bus_re
),
212 dcache_port
.adr
.eq(dcache
.bus_addr
),
213 dcache_port
.cti
.eq(Mux(dcache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)),
214 dcache_port
.bte
.eq(Const(log2_int(dcache
.nwords
) - 1)),
215 dcache
.bus_valid
.eq(dcache_port
.ack
),
216 dcache
.bus_error
.eq(dcache_port
.err
),
217 dcache
.bus_rdata
.eq(dcache_port
.dat_r
)
220 bare_port
= dbus_arbiter
.port(priority
=2)
221 bare_rdata
= Signal
.like(bare_port
.dat_r
)
222 with m
.If(bare_port
.cyc
):
223 with m
.If(bare_port
.ack | bare_port
.err | ~self
.m_valid
):
227 bare_rdata
.eq(bare_port
.dat_r
)
229 with m
.Elif((self
.x_load | self
.x_store
) & ~x_dcache_select
& self
.x_valid
& ~self
.x_stall
):
233 bare_port
.adr
.eq(self
.x_addr
[2:]),
234 bare_port
.sel
.eq(self
.x_mask
),
235 bare_port
.we
.eq(self
.x_store
),
236 bare_port
.dat_w
.eq(self
.x_store_data
)
239 with m
.If(self
.dbus
.cyc
& self
.dbus
.err
):
241 self
.m_load_error
.eq(~self
.dbus
.we
),
242 self
.m_store_error
.eq(self
.dbus
.we
),
243 self
.m_badaddr
.eq(self
.dbus
.adr
)
245 with m
.Elif(~self
.m_stall
):
247 self
.m_load_error
.eq(0),
248 self
.m_store_error
.eq(0)
251 with m
.If(self
.x_fence_i
):
252 m
.d
.comb
+= self
.x_busy
.eq(wrbuf
.r_rdy
)
253 with m
.Elif(x_dcache_select
):
254 m
.d
.comb
+= self
.x_busy
.eq(self
.x_store
& ~wrbuf
.w_rdy
)
256 m
.d
.comb
+= self
.x_busy
.eq(bare_port
.cyc
)
258 with m
.If(self
.m_load_error | self
.m_store_error
):
261 self
.m_load_data
.eq(0)
263 with m
.Elif(m_dcache_select
):
265 self
.m_busy
.eq(dcache
.s2_re
& dcache
.s2_miss
),
266 self
.m_load_data
.eq(dcache
.s2_rdata
)
270 self
.m_busy
.eq(bare_port
.cyc
),
271 self
.m_load_data
.eq(bare_rdata
)