a1f14b3d5dfbeafcee830b86a0fc4192920b0b41
1 from nmigen
import Elaboratable
, Module
, Signal
, Record
, Const
, Mux
2 from nmigen
.utils
import log2_int
4 from soc
.minerva
.cache
import L1Cache
5 from soc
.minerva
.wishbone
import make_wb_layout
, WishboneArbiter
, Cycle
8 __all__
= ["FetchUnitInterface", "BareFetchUnit", "CachedFetchUnit"]
11 class FetchUnitInterface
:
12 def __init__(self
, pspec
):
14 self
.addr_wid
= pspec
.addr_wid
15 if isinstance(pspec
.imem_reg_wid
, int):
16 self
.data_wid
= pspec
.imem_reg_wid
18 self
.data_wid
= pspec
.reg_wid
19 self
.adr_lsbs
= log2_int(self
.data_wid
//8)
20 self
.ibus
= Record(make_wb_layout(pspec
))
21 bad_wid
= pspec
.addr_wid
- self
.adr_lsbs
# TODO: is this correct?
23 # inputs: address to fetch PC, and valid/stall signalling
24 self
.a_pc_i
= Signal(self
.addr_wid
)
25 self
.a_stall_i
= Signal()
26 self
.a_valid_i
= Signal()
27 self
.f_stall_i
= Signal()
28 self
.f_valid_i
= Signal()
30 # outputs: instruction (or error), and busy indicators
31 self
.a_busy_o
= Signal()
32 self
.f_busy_o
= Signal()
33 self
.f_instr_o
= Signal(self
.data_wid
)
34 self
.f_fetch_err_o
= Signal()
35 self
.f_badaddr_o
= Signal(bad_wid
)
37 # detect whether the wishbone bus is enabled / disabled
38 if (hasattr(pspec
, "wb_icache_en") and
39 isinstance(pspec
.wb_icache_en
, Signal
)):
40 self
.jtag_en
= pspec
.wb_icache_en
42 self
.jtag_en
= Const(1, 1) # permanently on
54 yield self
.f_fetch_err_o
55 yield self
.f_badaddr_o
56 for sig
in self
.ibus
.fields
.values():
63 class BareFetchUnit(FetchUnitInterface
, Elaboratable
):
64 def elaborate(self
, platform
):
67 with m
.If(self
.jtag_en
): # for safety, JTAG can completely disable WB
69 ibus_rdata
= Signal
.like(self
.ibus
.dat_r
)
70 with m
.If(self
.ibus
.cyc
):
71 with m
.If(self
.ibus
.ack | self
.ibus
.err | ~self
.f_valid_i
):
76 ibus_rdata
.eq(self
.ibus
.dat_r
)
78 with m
.Elif(self
.a_valid_i
& ~self
.a_stall_i
):
80 self
.ibus
.adr
.eq(self
.a_pc_i
[self
.adr_lsbs
:]),
83 self
.ibus
.sel
.eq((1<<(1<<self
.adr_lsbs
))-1),
86 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
88 self
.f_fetch_err_o
.eq(1),
89 self
.f_badaddr_o
.eq(self
.ibus
.adr
)
91 with m
.Elif(~self
.f_stall_i
):
92 m
.d
.sync
+= self
.f_fetch_err_o
.eq(0)
94 m
.d
.comb
+= self
.a_busy_o
.eq(self
.ibus
.cyc
)
96 with m
.If(self
.f_fetch_err_o
):
97 m
.d
.comb
+= self
.f_busy_o
.eq(0)
100 self
.f_busy_o
.eq(self
.ibus
.cyc
),
101 self
.f_instr_o
.eq(ibus_rdata
)
107 class CachedFetchUnit(FetchUnitInterface
, Elaboratable
):
108 def __init__(self
, pspec
):
109 super().__init
__(pspec
)
111 self
.icache_args
= pspec
.icache_args
113 self
.a_flush
= Signal()
114 self
.f_pc
= Signal(addr_wid
)
116 def elaborate(self
, platform
):
119 icache
= m
.submodules
.icache
= L1Cache(*self
.icache_args
)
121 a_icache_select
= Signal()
123 # Test whether the target address is inside the L1 cache region.
124 # We use bit masks in order to avoid carry chains from arithmetic
125 # comparisons. This restricts the region boundaries to powers of 2.
127 # TODO: minerva defaults adr_lsbs to 2. check this code
128 with m
.Switch(self
.a_pc_i
[self
.adr_lsbs
:]):
129 def addr_below(limit
):
130 assert limit
in range(1, 2**30 + 1)
131 range_bits
= log2_int(limit
)
132 const_bits
= 30 - range_bits
133 return "{}{}".format("0" * const_bits
, "-" * range_bits
)
135 if icache
.base
>= 4: # XX (1<<self.adr_lsbs?)
136 with m
.Case(addr_below(icache
.base
>> self
.adr_lsbs
)):
137 m
.d
.comb
+= a_icache_select
.eq(0)
138 with m
.Case(addr_below(icache
.limit
>> self
.adr_lsbs
)):
139 m
.d
.comb
+= a_icache_select
.eq(1)
141 m
.d
.comb
+= a_icache_select
.eq(0)
143 f_icache_select
= Signal()
146 with m
.If(~self
.a_stall_i
):
148 f_icache_select
.eq(a_icache_select
),
149 f_flush
.eq(self
.a_flush
),
153 icache
.s1_addr
.eq(self
.a_pc_i
[self
.adr_lsbs
:]),
154 icache
.s1_flush
.eq(self
.a_flush
),
155 icache
.s1_stall
.eq(self
.a_stall_i
),
156 icache
.s1_valid
.eq(self
.a_valid_i
& a_icache_select
),
157 icache
.s2_addr
.eq(self
.f_pc
[self
.adr_lsbs
:]),
158 icache
.s2_re
.eq(Const(1)),
159 icache
.s2_evict
.eq(Const(0)),
160 icache
.s2_valid
.eq(self
.f_valid_i
& f_icache_select
)
163 iba
= WishboneArbiter(self
.pspec
)
164 m
.submodules
.ibus_arbiter
= iba
165 m
.d
.comb
+= iba
.bus
.connect(self
.ibus
)
167 icache_port
= iba
.port(priority
=0)
168 cti
= Mux(icache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)
170 icache_port
.cyc
.eq(icache
.bus_re
),
171 icache_port
.stb
.eq(icache
.bus_re
),
172 icache_port
.adr
.eq(icache
.bus_addr
),
173 icache_port
.cti
.eq(cti
),
174 icache_port
.bte
.eq(Const(log2_int(icache
.nwords
) - 1)),
175 icache
.bus_valid
.eq(icache_port
.ack
),
176 icache
.bus_error
.eq(icache_port
.err
),
177 icache
.bus_rdata
.eq(icache_port
.dat_r
)
180 bare_port
= iba
.port(priority
=1)
181 bare_rdata
= Signal
.like(bare_port
.dat_r
)
182 with m
.If(bare_port
.cyc
):
183 with m
.If(bare_port
.ack | bare_port
.err | ~self
.f_valid_i
):
188 bare_rdata
.eq(bare_port
.dat_r
)
190 with m
.Elif(~a_icache_select
& self
.a_valid_i
& ~self
.a_stall_i
):
194 bare_port
.sel
.eq((1<<(1<<self
.adr_lsbs
))-1),
195 bare_port
.adr
.eq(self
.a_pc_i
[self
.adr_lsbs
:])
198 m
.d
.comb
+= self
.a_busy_o
.eq(bare_port
.cyc
)
200 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
202 self
.f_fetch_err_o
.eq(1),
203 self
.f_badaddr_o
.eq(self
.ibus
.adr
)
205 with m
.Elif(~self
.f_stall_i
):
206 m
.d
.sync
+= self
.f_fetch_err_o
.eq(0)
209 m
.d
.comb
+= self
.f_busy_o
.eq(~icache
.s2_flush_ack
)
210 with m
.Elif(self
.f_fetch_err_o
):
211 m
.d
.comb
+= self
.f_busy_o
.eq(0)
212 with m
.Elif(f_icache_select
):
214 self
.f_busy_o
.eq(icache
.s2_miss
),
215 self
.f_instr_o
.eq(icache
.s2_rdata
)
219 self
.f_busy_o
.eq(bare_port
.cyc
),
220 self
.f_instr_o
.eq(bare_rdata
)