add minerva source from https://github.com/lambdaconcept/minerva
[soc.git] / src / soc / minerva / units / loadstore.py
1 from nmigen import *
2 from nmigen.utils import log2_int
3 from nmigen.lib.fifo import SyncFIFO
4
5 from ..cache import *
6 from ..isa import Funct3
7 from ..wishbone import *
8
9
10 __all__ = ["DataSelector", "LoadStoreUnitInterface", "BareLoadStoreUnit", "CachedLoadStoreUnit"]
11
12
13 class DataSelector(Elaboratable):
14 def __init__(self):
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)
21
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))
26
27 def elaborate(self, platform):
28 m = Module()
29
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())
35
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)
43
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)
51
52 w_byte = Signal((8, True))
53 w_half = Signal((16, True))
54
55 m.d.comb += [
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))
58 ]
59
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)
71
72 return m
73
74
75 class LoadStoreUnitInterface:
76 def __init__(self):
77 self.dbus = Record(wishbone_layout)
78
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()
88
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)
95
96
97 class BareLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
98 def elaborate(self, platform):
99 m = Module()
100
101 with m.If(self.dbus.cyc):
102 with m.If(self.dbus.ack | self.dbus.err | ~self.m_valid):
103 m.d.sync += [
104 self.dbus.cyc.eq(0),
105 self.dbus.stb.eq(0),
106 self.m_load_data.eq(self.dbus.dat_r)
107 ]
108 with m.Elif((self.x_load | self.x_store) & self.x_valid & ~self.x_stall):
109 m.d.sync += [
110 self.dbus.cyc.eq(1),
111 self.dbus.stb.eq(1),
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)
116 ]
117
118 with m.If(self.dbus.cyc & self.dbus.err):
119 m.d.sync += [
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)
123 ]
124 with m.Elif(~self.m_stall):
125 m.d.sync += [
126 self.m_load_error.eq(0),
127 self.m_store_error.eq(0)
128 ]
129
130 m.d.comb += self.x_busy.eq(self.dbus.cyc)
131
132 with m.If(self.m_load_error | self.m_store_error):
133 m.d.comb += self.m_busy.eq(0)
134 with m.Else():
135 m.d.comb += self.m_busy.eq(self.dbus.cyc)
136
137 return m
138
139
140 class CachedLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
141 def __init__(self, *dcache_args):
142 super().__init__()
143
144 self.dcache_args = dcache_args
145
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()
151
152 def elaborate(self, platform):
153 m = Module()
154
155 dcache = m.submodules.dcache = L1Cache(*self.dcache_args)
156
157 x_dcache_select = Signal()
158 m_dcache_select = Signal()
159
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)
163
164 m.d.comb += [
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)
173 ]
174
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)
178 m.d.comb += [
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),
185 ]
186
187 dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
188 m.d.comb += dbus_arbiter.bus.connect(self.dbus)
189
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):
193 m.d.sync += [
194 wrbuf_port.cyc.eq(0),
195 wrbuf_port.stb.eq(0)
196 ]
197 m.d.comb += wrbuf.r_en.eq(1)
198 with m.Elif(wrbuf.r_rdy):
199 m.d.sync += [
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)
205 ]
206 m.d.comb += wrbuf_port.we.eq(Const(1))
207
208 dcache_port = dbus_arbiter.port(priority=1)
209 m.d.comb += [
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)
218 ]
219
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):
224 m.d.sync += [
225 bare_port.cyc.eq(0),
226 bare_port.stb.eq(0),
227 bare_rdata.eq(bare_port.dat_r)
228 ]
229 with m.Elif((self.x_load | self.x_store) & ~x_dcache_select & self.x_valid & ~self.x_stall):
230 m.d.sync += [
231 bare_port.cyc.eq(1),
232 bare_port.stb.eq(1),
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)
237 ]
238
239 with m.If(self.dbus.cyc & self.dbus.err):
240 m.d.sync += [
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)
244 ]
245 with m.Elif(~self.m_stall):
246 m.d.sync += [
247 self.m_load_error.eq(0),
248 self.m_store_error.eq(0)
249 ]
250
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)
255 with m.Else():
256 m.d.comb += self.x_busy.eq(bare_port.cyc)
257
258 with m.If(self.m_load_error | self.m_store_error):
259 m.d.comb += [
260 self.m_busy.eq(0),
261 self.m_load_data.eq(0)
262 ]
263 with m.Elif(m_dcache_select):
264 m.d.comb += [
265 self.m_busy.eq(dcache.s2_re & dcache.s2_miss),
266 self.m_load_data.eq(dcache.s2_rdata)
267 ]
268 with m.Else():
269 m.d.comb += [
270 self.m_busy.eq(bare_port.cyc),
271 self.m_load_data.eq(bare_rdata)
272 ]
273
274 return m