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