whitespace
[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 ..cache import L1Cache
5 from ..wishbone import wishbone_layout, WishboneArbiter, Cycle
6
7
8 __all__ = ["PCSelector", "FetchUnitInterface", "BareFetchUnit",
9 "CachedFetchUnit"]
10
11
12 class PCSelector(Elaboratable):
13 def __init__(self):
14 self.f_pc = Signal(32)
15 self.d_pc = Signal(32)
16 self.d_branch_predict_taken = Signal()
17 self.d_branch_target = Signal(32)
18 self.d_valid = Signal()
19 self.x_pc = Signal(32)
20 self.x_fence_i = Signal()
21 self.x_valid = Signal()
22 self.m_branch_predict_taken = Signal()
23 self.m_branch_taken = Signal()
24 self.m_branch_target = Signal(32)
25 self.m_exception = Signal()
26 self.m_mret = Signal()
27 self.m_valid = Signal()
28 self.mtvec_r_base = Signal(30)
29 self.mepc_r_base = Signal(30)
30
31 self.a_pc = Signal(32)
32
33 def elaborate(self, platform):
34 m = Module()
35
36 with m.If(self.m_exception & self.m_valid):
37 m.d.comb += self.a_pc.eq(self.mtvec_r_base << 2)
38 with m.Elif(self.m_mret & self.m_valid):
39 m.d.comb += self.a_pc.eq(self.mepc_r_base << 2)
40 with m.Elif(self.m_branch_predict_taken & ~self.m_branch_taken &
41 self.m_valid):
42 m.d.comb += self.a_pc.eq(self.x_pc)
43 with m.Elif(~self.m_branch_predict_taken & self.m_branch_taken &
44 self.m_valid):
45 m.d.comb += self.a_pc.eq(self.m_branch_target),
46 with m.Elif(self.x_fence_i & self.x_valid):
47 m.d.comb += self.a_pc.eq(self.d_pc)
48 with m.Elif(self.d_branch_predict_taken & self.d_valid):
49 m.d.comb += self.a_pc.eq(self.d_branch_target),
50 with m.Else():
51 m.d.comb += self.a_pc.eq(self.f_pc + 4)
52
53 return m
54
55
56 class FetchUnitInterface:
57 def __init__(self):
58 self.ibus = Record(wishbone_layout)
59
60 self.a_pc = Signal(32)
61 self.a_stall = Signal()
62 self.a_valid = Signal()
63 self.f_stall = Signal()
64 self.f_valid = Signal()
65
66 self.a_busy = Signal()
67 self.f_busy = Signal()
68 self.f_instruction = Signal(32)
69 self.f_fetch_error = Signal()
70 self.f_badaddr = Signal(30)
71
72
73 class BareFetchUnit(FetchUnitInterface, Elaboratable):
74 def elaborate(self, platform):
75 m = Module()
76
77 ibus_rdata = Signal.like(self.ibus.dat_r)
78 with m.If(self.ibus.cyc):
79 with m.If(self.ibus.ack | self.ibus.err | ~self.f_valid):
80 m.d.sync += [
81 self.ibus.cyc.eq(0),
82 self.ibus.stb.eq(0),
83 ibus_rdata.eq(self.ibus.dat_r)
84 ]
85 with m.Elif(self.a_valid & ~self.a_stall):
86 m.d.sync += [
87 self.ibus.adr.eq(self.a_pc[2:]),
88 self.ibus.cyc.eq(1),
89 self.ibus.stb.eq(1)
90 ]
91
92 with m.If(self.ibus.cyc & self.ibus.err):
93 m.d.sync += [
94 self.f_fetch_error.eq(1),
95 self.f_badaddr.eq(self.ibus.adr)
96 ]
97 with m.Elif(~self.f_stall):
98 m.d.sync += self.f_fetch_error.eq(0)
99
100 m.d.comb += self.a_busy.eq(self.ibus.cyc)
101
102 with m.If(self.f_fetch_error):
103 m.d.comb += [
104 self.f_busy.eq(0),
105 self.f_instruction.eq(0x00000013) # nop (addi x0, x0, 0)
106 ]
107 with m.Else():
108 m.d.comb += [
109 self.f_busy.eq(self.ibus.cyc),
110 self.f_instruction.eq(ibus_rdata)
111 ]
112
113 return m
114
115
116 class CachedFetchUnit(FetchUnitInterface, Elaboratable):
117 def __init__(self, *icache_args):
118 super().__init__()
119
120 self.icache_args = icache_args
121
122 self.a_flush = Signal()
123 self.f_pc = Signal(32)
124
125 def elaborate(self, platform):
126 m = Module()
127
128 icache = m.submodules.icache = L1Cache(*self.icache_args)
129
130 a_icache_select = Signal()
131 f_icache_select = Signal()
132
133 m.d.comb += a_icache_select.eq((self.a_pc >= icache.base) & (self.a_pc < icache.limit))
134 with m.If(~self.a_stall):
135 m.d.sync += f_icache_select.eq(a_icache_select)
136
137 m.d.comb += [
138 icache.s1_addr.eq(self.a_pc[2:]),
139 icache.s1_flush.eq(self.a_flush),
140 icache.s1_stall.eq(self.a_stall),
141 icache.s1_valid.eq(self.a_valid & a_icache_select),
142 icache.s2_addr.eq(self.f_pc[2:]),
143 icache.s2_re.eq(Const(1)),
144 icache.s2_evict.eq(Const(0)),
145 icache.s2_valid.eq(self.f_valid & f_icache_select)
146 ]
147
148 ibus_arbiter = m.submodules.ibus_arbiter = WishboneArbiter()
149 m.d.comb += ibus_arbiter.bus.connect(self.ibus)
150
151 icache_pt = ibus_arbiter.port(priority=0)
152 m.d.comb += [
153 icache_pt.cyc.eq(icache.bus_re),
154 icache_pt.stb.eq(icache.bus_re),
155 icache_pt.adr.eq(icache.bus_addr),
156 icache_pt.cti.eq(Mux(icache.bus_last, Cycle.END, Cycle.INCREMENT)),
157 icache_pt.bte.eq(Const(log2_int(icache.nwords) - 1)),
158 icache.bus_valid.eq(icache_pt.ack),
159 icache.bus_error.eq(icache_pt.err),
160 icache.bus_rdata.eq(icache_pt.dat_r)
161 ]
162
163 bare_port = ibus_arbiter.port(priority=1)
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.f_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(~a_icache_select & self.a_valid & ~self.a_stall):
173 m.d.sync += [
174 bare_port.cyc.eq(1),
175 bare_port.stb.eq(1),
176 bare_port.adr.eq(self.a_pc[2:])
177 ]
178
179 with m.If(self.ibus.cyc & self.ibus.err):
180 m.d.sync += [
181 self.f_fetch_error.eq(1),
182 self.f_badaddr.eq(self.ibus.adr)
183 ]
184 with m.Elif(~self.f_stall):
185 m.d.sync += self.f_fetch_error.eq(0)
186
187 with m.If(a_icache_select):
188 m.d.comb += self.a_busy.eq(0)
189 with m.Else():
190 m.d.comb += self.a_busy.eq(bare_port.cyc)
191
192 with m.If(self.f_fetch_error):
193 m.d.comb += [
194 self.f_busy.eq(0),
195 self.f_instruction.eq(0x00000013) # nop (addi x0, x0, 0)
196 ]
197 with m.Elif(f_icache_select):
198 m.d.comb += [
199 self.f_busy.eq(icache.s2_re & icache.s2_miss),
200 self.f_instruction.eq(icache.s2_rdata)
201 ]
202 with m.Else():
203 m.d.comb += [
204 self.f_busy.eq(bare_port.cyc),
205 self.f_instruction.eq(bare_rdata)
206 ]
207
208 return m