whitespace cleanup, remove minerva DataSelector class
[soc.git] / src / soc / minerva / units / loadstore.py
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
4
5 from soc.minerva.cache import L1Cache
6 from soc.minerva.wishbone import wishbone_layout, WishboneArbiter, Cycle
7
8
9 __all__ = ["LoadStoreUnitInterface", "BareLoadStoreUnit",
10 "CachedLoadStoreUnit"]
11
12
13 class LoadStoreUnitInterface:
14 def __init__(self):
15 self.dbus = Record(wishbone_layout)
16
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()
26
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)
33
34
35 class BareLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
36 def elaborate(self, platform):
37 m = Module()
38
39 with m.If(self.dbus.cyc):
40 with m.If(self.dbus.ack | self.dbus.err | ~self.m_valid):
41 m.d.sync += [
42 self.dbus.cyc.eq(0),
43 self.dbus.stb.eq(0),
44 self.m_load_data.eq(self.dbus.dat_r)
45 ]
46 with m.Elif((self.x_load | self.x_store) &
47 self.x_valid & ~self.x_stall):
48 m.d.sync += [
49 self.dbus.cyc.eq(1),
50 self.dbus.stb.eq(1),
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)
55 ]
56
57 with m.If(self.dbus.cyc & self.dbus.err):
58 m.d.sync += [
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)
62 ]
63 with m.Elif(~self.m_stall):
64 m.d.sync += [
65 self.m_load_error.eq(0),
66 self.m_store_error.eq(0)
67 ]
68
69 m.d.comb += self.x_busy.eq(self.dbus.cyc)
70
71 with m.If(self.m_load_error | self.m_store_error):
72 m.d.comb += self.m_busy.eq(0)
73 with m.Else():
74 m.d.comb += self.m_busy.eq(self.dbus.cyc)
75
76 return m
77
78
79 class CachedLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
80 def __init__(self, *dcache_args):
81 super().__init__()
82
83 self.dcache_args = dcache_args
84
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()
90
91 def elaborate(self, platform):
92 m = Module()
93
94 dcache = m.submodules.dcache = L1Cache(*self.dcache_args)
95
96 x_dcache_select = Signal()
97 m_dcache_select = Signal()
98
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)
103
104 m.d.comb += [
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)
113 ]
114
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),
118 depth=dcache.nwords)
119 m.d.comb += [
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),
127 ]
128
129 dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
130 m.d.comb += dbus_arbiter.bus.connect(self.dbus)
131
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):
135 m.d.sync += [
136 wrbuf_port.cyc.eq(0),
137 wrbuf_port.stb.eq(0)
138 ]
139 m.d.comb += wrbuf.r_en.eq(1)
140 with m.Elif(wrbuf.r_rdy):
141 m.d.sync += [
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)
147 ]
148 m.d.comb += wrbuf_port.we.eq(Const(1))
149
150 dcache_port = dbus_arbiter.port(priority=1)
151 m.d.comb += [
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)
161 ]
162
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):
167 m.d.sync += [
168 bare_port.cyc.eq(0),
169 bare_port.stb.eq(0),
170 bare_rdata.eq(bare_port.dat_r)
171 ]
172 with m.Elif((self.x_load | self.x_store) &
173 ~x_dcache_select & self.x_valid & ~self.x_stall):
174 m.d.sync += [
175 bare_port.cyc.eq(1),
176 bare_port.stb.eq(1),
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)
181 ]
182
183 with m.If(self.dbus.cyc & self.dbus.err):
184 m.d.sync += [
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)
188 ]
189 with m.Elif(~self.m_stall):
190 m.d.sync += [
191 self.m_load_error.eq(0),
192 self.m_store_error.eq(0)
193 ]
194
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)
199 with m.Else():
200 m.d.comb += self.x_busy.eq(bare_port.cyc)
201
202 with m.If(self.m_load_error | self.m_store_error):
203 m.d.comb += [
204 self.m_busy.eq(0),
205 self.m_load_data.eq(0)
206 ]
207 with m.Elif(m_dcache_select):
208 m.d.comb += [
209 self.m_busy.eq(dcache.s2_re & dcache.s2_miss),
210 self.m_load_data.eq(dcache.s2_rdata)
211 ]
212 with m.Else():
213 m.d.comb += [
214 self.m_busy.eq(bare_port.cyc),
215 self.m_load_data.eq(bare_rdata)
216 ]
217
218 return m