port minerva cache fixes
[soc.git] / src / soc / minerva / units / fetch.py
1 from nmigen import Elaboratable, Module, Signal, Record, Const, Mux
2 from nmigen.utils import log2_int
3
4 from soc.minerva.cache import L1Cache
5 from soc.minerva.wishbone import make_wb_layout, WishboneArbiter, Cycle
6
7
8 __all__ = ["FetchUnitInterface", "BareFetchUnit", "CachedFetchUnit"]
9
10
11 class FetchUnitInterface:
12 def __init__(self, pspec):
13 self.pspec = pspec
14 self.addr_wid = pspec.addr_wid
15 self.data_wid = pspec.reg_wid
16 self.adr_lsbs = log2_int(pspec.reg_wid//8)
17 self.ibus = Record(make_wb_layout(pspec))
18 bad_wid = pspec.addr_wid - self.adr_lsbs # TODO: is this correct?
19
20 # inputs: address to fetch PC, and valid/stall signalling
21 self.a_pc_i = Signal(self.addr_wid)
22 self.a_stall_i = Signal()
23 self.a_valid_i = Signal()
24 self.f_stall_i = Signal()
25 self.f_valid_i = Signal()
26
27 # outputs: instruction (or error), and busy indicators
28 self.a_busy_o = Signal()
29 self.f_busy_o = Signal()
30 self.f_instr_o = Signal(self.data_wid)
31 self.f_fetch_err_o = Signal()
32 self.f_badaddr_o = Signal(bad_wid)
33
34 def __iter__(self):
35 yield self.a_pc_i
36 yield self.a_stall_i
37 yield self.a_valid_i
38 yield self.f_stall_i
39 yield self.f_valid_i
40 yield self.a_busy_o
41 yield self.f_busy_o
42 yield self.f_instr_o
43 yield self.f_fetch_err_o
44 yield self.f_badaddr_o
45 for sig in self.ibus.fields.values():
46 yield sig
47
48 def ports(self):
49 return list(self)
50
51
52 class BareFetchUnit(FetchUnitInterface, Elaboratable):
53 def elaborate(self, platform):
54 m = Module()
55
56 ibus_rdata = Signal.like(self.ibus.dat_r)
57 with m.If(self.ibus.cyc):
58 with m.If(self.ibus.ack | self.ibus.err | ~self.f_valid_i):
59 m.d.sync += [
60 self.ibus.cyc.eq(0),
61 self.ibus.stb.eq(0),
62 ibus_rdata.eq(self.ibus.dat_r)
63 ]
64 with m.Elif(self.a_valid_i & ~self.a_stall_i):
65 m.d.sync += [
66 self.ibus.adr.eq(self.a_pc_i[self.adr_lsbs:]),
67 self.ibus.cyc.eq(1),
68 self.ibus.stb.eq(1)
69 ]
70
71 with m.If(self.ibus.cyc & self.ibus.err):
72 m.d.sync += [
73 self.f_fetch_err_o.eq(1),
74 self.f_badaddr_o.eq(self.ibus.adr)
75 ]
76 with m.Elif(~self.f_stall_i):
77 m.d.sync += self.f_fetch_err_o.eq(0)
78
79 m.d.comb += self.a_busy_o.eq(self.ibus.cyc)
80
81 with m.If(self.f_fetch_err_o):
82 m.d.comb += [
83 self.f_busy_o.eq(0),
84 self.f_instr_o.eq(0x0)
85 ]
86 with m.Else():
87 m.d.comb += [
88 self.f_busy_o.eq(self.ibus.cyc),
89 self.f_instr_o.eq(ibus_rdata)
90 ]
91
92 return m
93
94
95 class CachedFetchUnit(FetchUnitInterface, Elaboratable):
96 def __init__(self, pspec):
97 super().__init__(pspec)
98
99 self.icache_args = pspec.icache_args
100
101 self.a_flush = Signal()
102 self.f_pc = Signal(addr_wid)
103
104 def elaborate(self, platform):
105 m = Module()
106
107 icache = m.submodules.icache = L1Cache(*self.icache_args)
108
109 a_icache_select = Signal()
110 f_icache_select = Signal()
111
112 m.d.comb += a_icache_select.eq((self.a_pc_i >= icache.base) &
113 (self.a_pc_i < icache.limit))
114 with m.If(~self.a_stall_i):
115 m.d.sync += f_icache_select.eq(a_icache_select)
116
117 m.d.comb += [
118 icache.s1_addr.eq(self.a_pc_i[self.adr_lsbs:]),
119 icache.s1_flush.eq(self.a_flush),
120 icache.s1_stall.eq(self.a_stall_i),
121 icache.s1_valid.eq(self.a_valid_i & a_icache_select),
122 icache.s2_addr.eq(self.f_pc[self.adr_lsbs:]),
123 icache.s2_re.eq(Const(1)),
124 icache.s2_evict.eq(Const(0)),
125 icache.s2_valid.eq(self.f_valid_i & f_icache_select)
126 ]
127
128 iba = WishboneArbiter(self.pspec)
129 m.submodules.ibus_arbiter = iba
130 m.d.comb += iba.bus.connect(self.ibus)
131
132 icache_port = iba.port(priority=0)
133 cti = Mux(icache.bus_last, Cycle.END, Cycle.INCREMENT)
134 m.d.comb += [
135 icache_port.cyc.eq(icache.bus_re),
136 icache_port.stb.eq(icache.bus_re),
137 icache_port.adr.eq(icache.bus_addr),
138 icache_port.cti.eq(cti),
139 icache_port.bte.eq(Const(log2_int(icache.nwords) - 1)),
140 icache.bus_valid.eq(icache_port.ack),
141 icache.bus_error.eq(icache_port.err),
142 icache.bus_rdata.eq(icache_port.dat_r)
143 ]
144
145 bare_port = iba.port(priority=1)
146 bare_rdata = Signal.like(bare_port.dat_r)
147 with m.If(bare_port.cyc):
148 with m.If(bare_port.ack | bare_port.err | ~self.f_valid_i):
149 m.d.sync += [
150 bare_port.cyc.eq(0),
151 bare_port.stb.eq(0),
152 bare_rdata.eq(bare_port.dat_r)
153 ]
154 with m.Elif(~a_icache_select & self.a_valid_i & ~self.a_stall_i):
155 m.d.sync += [
156 bare_port.cyc.eq(1),
157 bare_port.stb.eq(1),
158 bare_port.adr.eq(self.a_pc_i[self.adr_lsbs:])
159 ]
160
161 with m.If(self.ibus.cyc & self.ibus.err):
162 m.d.sync += [
163 self.f_fetch_err_o.eq(1),
164 self.f_badaddr_o.eq(self.ibus.adr)
165 ]
166 with m.Elif(~self.f_stall_i):
167 m.d.sync += self.f_fetch_err_o.eq(0)
168
169 with m.If(a_icache_select):
170 m.d.comb += self.a_busy_o.eq(0)
171 with m.Else():
172 m.d.comb += self.a_busy_o.eq(bare_port.cyc)
173
174 with m.If(self.f_fetch_err_o):
175 m.d.comb += [
176 self.f_busy_o.eq(0),
177 self.f_instr_o.eq(0x0)
178 ]
179 with m.Elif(f_icache_select):
180 m.d.comb += [
181 self.f_busy_o.eq(icache.s2_miss),
182 self.f_instr_o.eq(icache.s2_rdata)
183 ]
184 with m.Else():
185 m.d.comb += [
186 self.f_busy_o.eq(bare_port.cyc),
187 self.f_instr_o.eq(bare_rdata)
188 ]
189
190 return m