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