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