1 from nmigen
import Elaboratable
, Module
, Signal
, Record
, Const
, Mux
2 from nmigen
.utils
import log2_int
4 from ..cache
import L1Cache
5 from ..wishbone
import wishbone_layout
, WishboneArbiter
, Cycle
8 __all__
= ["PCSelector", "FetchUnitInterface", "BareFetchUnit", "CachedFetchUnit"]
11 class PCSelector(Elaboratable
):
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)
30 self
.a_pc
= Signal(32)
32 def elaborate(self
, platform
):
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
),
48 m
.d
.comb
+= self
.a_pc
.eq(self
.f_pc
+ 4)
53 class FetchUnitInterface
:
55 self
.ibus
= Record(wishbone_layout
)
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()
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)
70 class BareFetchUnit(FetchUnitInterface
, Elaboratable
):
71 def elaborate(self
, platform
):
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
):
80 ibus_rdata
.eq(self
.ibus
.dat_r
)
82 with m
.Elif(self
.a_valid
& ~self
.a_stall
):
84 self
.ibus
.adr
.eq(self
.a_pc
[2:]),
89 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
91 self
.f_fetch_error
.eq(1),
92 self
.f_badaddr
.eq(self
.ibus
.adr
)
94 with m
.Elif(~self
.f_stall
):
95 m
.d
.sync
+= self
.f_fetch_error
.eq(0)
97 m
.d
.comb
+= self
.a_busy
.eq(self
.ibus
.cyc
)
99 with m
.If(self
.f_fetch_error
):
102 self
.f_instruction
.eq(0x00000013) # nop (addi x0, x0, 0)
106 self
.f_busy
.eq(self
.ibus
.cyc
),
107 self
.f_instruction
.eq(ibus_rdata
)
113 class CachedFetchUnit(FetchUnitInterface
, Elaboratable
):
114 def __init__(self
, *icache_args
):
117 self
.icache_args
= icache_args
119 self
.a_flush
= Signal()
120 self
.f_pc
= Signal(32)
122 def elaborate(self
, platform
):
125 icache
= m
.submodules
.icache
= L1Cache(*self
.icache_args
)
127 a_icache_select
= Signal()
128 f_icache_select
= Signal()
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
)
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
)
145 ibus_arbiter
= m
.submodules
.ibus_arbiter
= WishboneArbiter()
146 m
.d
.comb
+= ibus_arbiter
.bus
.connect(self
.ibus
)
148 icache_port
= ibus_arbiter
.port(priority
=0)
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
)
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
):
167 bare_rdata
.eq(bare_port
.dat_r
)
169 with m
.Elif(~a_icache_select
& self
.a_valid
& ~self
.a_stall
):
173 bare_port
.adr
.eq(self
.a_pc
[2:])
176 with m
.If(self
.ibus
.cyc
& self
.ibus
.err
):
178 self
.f_fetch_error
.eq(1),
179 self
.f_badaddr
.eq(self
.ibus
.adr
)
181 with m
.Elif(~self
.f_stall
):
182 m
.d
.sync
+= self
.f_fetch_error
.eq(0)
184 with m
.If(a_icache_select
):
185 m
.d
.comb
+= self
.a_busy
.eq(0)
187 m
.d
.comb
+= self
.a_busy
.eq(bare_port
.cyc
)
189 with m
.If(self
.f_fetch_error
):
192 self
.f_instruction
.eq(0x00000013) # nop (addi x0, x0, 0)
194 with m
.Elif(f_icache_select
):
196 self
.f_busy
.eq(icache
.s2_re
& icache
.s2_miss
),
197 self
.f_instruction
.eq(icache
.s2_rdata
)
201 self
.f_busy
.eq(bare_port
.cyc
),
202 self
.f_instruction
.eq(bare_rdata
)