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