Update comments on LoadStoreUnitInterface again
[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, 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?
17
18 # INPUTS
19 self.x_addr = Signal(addr_wid) # The address used for loads/stores
20 self.x_mask = Signal(mask_wid) # Mask of which bytes to write
21 self.x_load = Signal() # set to do a memory load
22 self.x_store = Signal() # set to do a memory store
23 self.x_store_data = Signal(data_wid) # The data to write when storing
24 self.x_stall = Signal() # do nothing until low
25 self.x_valid = Signal() # Not entirely sure yet
26 self.m_stall = Signal() # do nothing until low
27 self.m_valid = Signal() # Not entirely sure yet
28
29 # OUTPUTS
30 self.x_busy = Signal() # set when the memory is busy
31 self.m_busy = Signal() # set when the memory is busy
32 self.m_load_data = Signal(data_wid) # Data returned from a memory read
33 # Data validity is NOT indicated by m_valid or x_valid as
34 # those are inputs. I believe it is valid on the next cycle
35 # after raising m_load where busy is low
36
37 self.m_load_error = Signal() # Whether there was an error when loading
38 self.m_store_error = Signal() # Whether there was an error when storing
39 self.m_badaddr = Signal(badwid) # The address of the load/store error
40
41
42 class BareLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
43 def elaborate(self, platform):
44 m = Module()
45
46 with m.If(self.dbus.cyc):
47 with m.If(self.dbus.ack | self.dbus.err | ~self.m_valid):
48 m.d.sync += [
49 self.dbus.cyc.eq(0),
50 self.dbus.stb.eq(0),
51 self.m_load_data.eq(self.dbus.dat_r)
52 ]
53 with m.Elif((self.x_load | self.x_store) &
54 self.x_valid & ~self.x_stall):
55 m.d.sync += [
56 self.dbus.cyc.eq(1),
57 self.dbus.stb.eq(1),
58 self.dbus.adr.eq(self.x_addr[2:]),
59 self.dbus.sel.eq(self.x_mask),
60 self.dbus.we.eq(self.x_store),
61 self.dbus.dat_w.eq(self.x_store_data)
62 ]
63
64 with m.If(self.dbus.cyc & self.dbus.err):
65 m.d.sync += [
66 self.m_load_error.eq(~self.dbus.we),
67 self.m_store_error.eq(self.dbus.we),
68 self.m_badaddr.eq(self.dbus.adr)
69 ]
70 with m.Elif(~self.m_stall):
71 m.d.sync += [
72 self.m_load_error.eq(0),
73 self.m_store_error.eq(0)
74 ]
75
76 m.d.comb += self.x_busy.eq(self.dbus.cyc)
77
78 with m.If(self.m_load_error | self.m_store_error):
79 m.d.comb += self.m_busy.eq(0)
80 with m.Else():
81 m.d.comb += self.m_busy.eq(self.dbus.cyc)
82
83 return m
84
85
86 class CachedLoadStoreUnit(LoadStoreUnitInterface, Elaboratable):
87 def __init__(self, *dcache_args):
88 super().__init__()
89
90 self.dcache_args = dcache_args
91
92 self.x_fence_i = Signal()
93 self.x_flush = Signal()
94 self.m_addr = Signal(32)
95 self.m_load = Signal()
96 self.m_store = Signal()
97
98 def elaborate(self, platform):
99 m = Module()
100
101 dcache = m.submodules.dcache = L1Cache(*self.dcache_args)
102
103 x_dcache_select = Signal()
104 m_dcache_select = Signal()
105
106 m.d.comb += x_dcache_select.eq((self.x_addr >= dcache.base) &
107 (self.x_addr < dcache.limit))
108 with m.If(~self.x_stall):
109 m.d.sync += m_dcache_select.eq(x_dcache_select)
110
111 m.d.comb += [
112 dcache.s1_addr.eq(self.x_addr[2:]),
113 dcache.s1_flush.eq(self.x_flush),
114 dcache.s1_stall.eq(self.x_stall),
115 dcache.s1_valid.eq(self.x_valid & x_dcache_select),
116 dcache.s2_addr.eq(self.m_addr[2:]),
117 dcache.s2_re.eq(self.m_load),
118 dcache.s2_evict.eq(self.m_store),
119 dcache.s2_valid.eq(self.m_valid & m_dcache_select)
120 ]
121
122 wrbuf_w_data = Record([("addr", 30), ("mask", 4), ("data", 32)])
123 wrbuf_r_data = Record.like(wrbuf_w_data)
124 wrbuf = m.submodules.wrbuf = SyncFIFO(width=len(wrbuf_w_data),
125 depth=dcache.nwords)
126 m.d.comb += [
127 wrbuf.w_data.eq(wrbuf_w_data),
128 wrbuf_w_data.addr.eq(self.x_addr[2:]),
129 wrbuf_w_data.mask.eq(self.x_mask),
130 wrbuf_w_data.data.eq(self.x_store_data),
131 wrbuf.w_en.eq(self.x_store & self.x_valid &
132 x_dcache_select & ~self.x_stall),
133 wrbuf_r_data.eq(wrbuf.r_data),
134 ]
135
136 dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
137 m.d.comb += dbus_arbiter.bus.connect(self.dbus)
138
139 wrbuf_port = dbus_arbiter.port(priority=0)
140 with m.If(wrbuf_port.cyc):
141 with m.If(wrbuf_port.ack | wrbuf_port.err):
142 m.d.sync += [
143 wrbuf_port.cyc.eq(0),
144 wrbuf_port.stb.eq(0)
145 ]
146 m.d.comb += wrbuf.r_en.eq(1)
147 with m.Elif(wrbuf.r_rdy):
148 m.d.sync += [
149 wrbuf_port.cyc.eq(1),
150 wrbuf_port.stb.eq(1),
151 wrbuf_port.adr.eq(wrbuf_r_data.addr),
152 wrbuf_port.sel.eq(wrbuf_r_data.mask),
153 wrbuf_port.dat_w.eq(wrbuf_r_data.data)
154 ]
155 m.d.comb += wrbuf_port.we.eq(Const(1))
156
157 dcache_port = dbus_arbiter.port(priority=1)
158 cti = Mux(dcache.bus_last, Cycle.END, Cycle.INCREMENT)
159 m.d.comb += [
160 dcache_port.cyc.eq(dcache.bus_re),
161 dcache_port.stb.eq(dcache.bus_re),
162 dcache_port.adr.eq(dcache.bus_addr),
163 dcache_port.cti.eq(cti),
164 dcache_port.bte.eq(Const(log2_int(dcache.nwords) - 1)),
165 dcache.bus_valid.eq(dcache_port.ack),
166 dcache.bus_error.eq(dcache_port.err),
167 dcache.bus_rdata.eq(dcache_port.dat_r)
168 ]
169
170 bare_port = dbus_arbiter.port(priority=2)
171 bare_rdata = Signal.like(bare_port.dat_r)
172 with m.If(bare_port.cyc):
173 with m.If(bare_port.ack | bare_port.err | ~self.m_valid):
174 m.d.sync += [
175 bare_port.cyc.eq(0),
176 bare_port.stb.eq(0),
177 bare_rdata.eq(bare_port.dat_r)
178 ]
179 with m.Elif((self.x_load | self.x_store) &
180 ~x_dcache_select & self.x_valid & ~self.x_stall):
181 m.d.sync += [
182 bare_port.cyc.eq(1),
183 bare_port.stb.eq(1),
184 bare_port.adr.eq(self.x_addr[2:]),
185 bare_port.sel.eq(self.x_mask),
186 bare_port.we.eq(self.x_store),
187 bare_port.dat_w.eq(self.x_store_data)
188 ]
189
190 with m.If(self.dbus.cyc & self.dbus.err):
191 m.d.sync += [
192 self.m_load_error.eq(~self.dbus.we),
193 self.m_store_error.eq(self.dbus.we),
194 self.m_badaddr.eq(self.dbus.adr)
195 ]
196 with m.Elif(~self.m_stall):
197 m.d.sync += [
198 self.m_load_error.eq(0),
199 self.m_store_error.eq(0)
200 ]
201
202 with m.If(self.x_fence_i):
203 m.d.comb += self.x_busy.eq(wrbuf.r_rdy)
204 with m.Elif(x_dcache_select):
205 m.d.comb += self.x_busy.eq(self.x_store & ~wrbuf.w_rdy)
206 with m.Else():
207 m.d.comb += self.x_busy.eq(bare_port.cyc)
208
209 with m.If(self.m_load_error | self.m_store_error):
210 m.d.comb += [
211 self.m_busy.eq(0),
212 self.m_load_data.eq(0)
213 ]
214 with m.Elif(m_dcache_select):
215 m.d.comb += [
216 self.m_busy.eq(dcache.s2_re & dcache.s2_miss),
217 self.m_load_data.eq(dcache.s2_rdata)
218 ]
219 with m.Else():
220 m.d.comb += [
221 self.m_busy.eq(bare_port.cyc),
222 self.m_load_data.eq(bare_rdata)
223 ]
224
225 return m