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
, 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
, data_wid
//8, data_wid
))
17 bad_wid
= addr_wid
- self
.adr_lsbs
# TODO: is this correct?
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()
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
)
34 class BareFetchUnit(FetchUnitInterface
, Elaboratable
):
35 def elaborate(self
, platform
):
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
):
44 ibus_rdata
.eq(self
.ibus
.dat_r
)
46 with m
.Elif(self
.a_valid_i
& ~self
.a_stall_i
):
48 self
.ibus
.adr
.eq(self
.a_pc_i
[self
.adr_lsbs
:]),
53 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
55 self
.f_fetch_err_o
.eq(1),
56 self
.f_badaddr_o
.eq(self
.ibus
.adr
)
58 with m
.Elif(~self
.f_stall_i
):
59 m
.d
.sync
+= self
.f_fetch_err_o
.eq(0)
61 m
.d
.comb
+= self
.a_busy_o
.eq(self
.ibus
.cyc
)
63 with m
.If(self
.f_fetch_err_o
):
66 self
.f_instr_o
.eq(0x0)
70 self
.f_busy_o
.eq(self
.ibus
.cyc
),
71 self
.f_instr_o
.eq(ibus_rdata
)
77 class CachedFetchUnit(FetchUnitInterface
, Elaboratable
):
78 def __init__(self
, *icache_args
, addr_wid
=32, data_wid
=32):
79 super().__init
__(addr_wid
=addr_wid
, data_wid
=data_wid
)
81 self
.icache_args
= icache_args
83 self
.a_flush
= Signal()
84 self
.f_pc
= Signal(addr_wid
)
86 def elaborate(self
, platform
):
89 icache
= m
.submodules
.icache
= L1Cache(*self
.icache_args
)
91 a_icache_select
= Signal()
92 f_icache_select
= Signal()
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
)
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
)
110 iba
= WishboneArbiter(self
.addr_wid
, self
.adr_lsbs
, self
.data_wid
)
111 m
.submodules
.ibus_arbiter
= iba
112 m
.d
.comb
+= iba
.bus
.connect(self
.ibus
)
114 icache_port
= iba
.port(priority
=0)
115 cti
= Mux(icache
.bus_last
, Cycle
.END
, Cycle
.INCREMENT
)
117 icache_port
.cyc
.eq(icache
.bus_re
),
118 icache_port
.stb
.eq(icache
.bus_re
),
119 icache_port
.adr
.eq(icache
.bus_addr
),
120 icache_port
.cti
.eq(cti
),
121 icache_port
.bte
.eq(Const(log2_int(icache
.nwords
) - 1)),
122 icache
.bus_valid
.eq(icache_port
.ack
),
123 icache
.bus_error
.eq(icache_port
.err
),
124 icache
.bus_rdata
.eq(icache_port
.dat_r
)
127 bare_port
= iba
.port(priority
=1)
128 bare_rdata
= Signal
.like(bare_port
.dat_r
)
129 with m
.If(bare_port
.cyc
):
130 with m
.If(bare_port
.ack | bare_port
.err | ~self
.f_valid_i
):
134 bare_rdata
.eq(bare_port
.dat_r
)
136 with m
.Elif(~a_icache_select
& self
.a_valid_i
& ~self
.a_stall_i
):
140 bare_port
.adr
.eq(self
.a_pc_i
[self
.adr_lsbs
:])
143 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
145 self
.f_fetch_err_o
.eq(1),
146 self
.f_badaddr_o
.eq(self
.ibus
.adr
)
148 with m
.Elif(~self
.f_stall_i
):
149 m
.d
.sync
+= self
.f_fetch_err_o
.eq(0)
151 with m
.If(a_icache_select
):
152 m
.d
.comb
+= self
.a_busy_o
.eq(0)
154 m
.d
.comb
+= self
.a_busy_o
.eq(bare_port
.cyc
)
156 with m
.If(self
.f_fetch_err_o
):
159 self
.f_instr_o
.eq(0x0)
161 with m
.Elif(f_icache_select
):
163 self
.f_busy_o
.eq(icache
.s2_re
& icache
.s2_miss
),
164 self
.f_instr_o
.eq(icache
.s2_rdata
)
168 self
.f_busy_o
.eq(bare_port
.cyc
),
169 self
.f_instr_o
.eq(bare_rdata
)