235e14a3ce84ca343e4383fdbafccee0fff088f0
1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
8 from functools
import reduce
9 from operator
import or_
12 from migen
.genlib
import roundrobin
13 from migen
.genlib
.record
import *
14 from migen
.genlib
.misc
import split
, displacer
, chooser
, WaitTimer
16 from litex
.build
.generic_platform
import *
18 from litex
.soc
.interconnect
import csr
, csr_bus
20 # Wishbone Definition ------------------------------------------------------------------------------
23 ("adr", "adr_width", DIR_M_TO_S
),
24 ("dat_w", "data_width", DIR_M_TO_S
),
25 ("dat_r", "data_width", DIR_S_TO_M
),
26 ("sel", "sel_width", DIR_M_TO_S
),
27 ("cyc", 1, DIR_M_TO_S
),
28 ("stb", 1, DIR_M_TO_S
),
29 ("ack", 1, DIR_S_TO_M
),
30 ("we", 1, DIR_M_TO_S
),
31 ("cti", 3, DIR_M_TO_S
),
32 ("bte", 2, DIR_M_TO_S
),
33 ("err", 1, DIR_S_TO_M
)
37 class Interface(Record
):
38 def __init__(self
, data_width
=32, adr_width
=31):
39 self
.data_width
= data_width
40 self
.adr_width
= adr_width
41 Record
.__init
__(self
, set_layout_parameters(_layout
,
42 adr_width
= adr_width
,
43 data_width
= data_width
,
44 sel_width
= data_width
//8))
45 self
.adr
.reset_less
= True
46 self
.dat_w
.reset_less
= True
47 self
.dat_r
.reset_less
= True
48 self
.sel
.reset_less
= True
52 return Interface(len(other
.dat_w
))
54 def _do_transaction(self
):
58 while not (yield self
.ack
):
63 def write(self
, adr
, dat
, sel
=None):
65 sel
= 2**len(self
.sel
) - 1
66 yield self
.adr
.eq(adr
)
67 yield self
.dat_w
.eq(dat
)
68 yield self
.sel
.eq(sel
)
70 yield from self
._do
_transaction
()
73 yield self
.adr
.eq(adr
)
75 yield from self
._do
_transaction
()
76 return (yield self
.dat_r
)
78 def get_ios(self
, bus_name
="wb"):
80 for name
, width
, direction
in self
.layout
:
81 subsignals
.append(Subsignal(name
, Pins(width
)))
82 ios
= [(bus_name
, 0) + tuple(subsignals
)]
85 def connect_to_pads(self
, pads
, mode
="master"):
86 assert mode
in ["slave", "master"]
88 for name
, width
, direction
in self
.layout
:
89 sig
= getattr(self
, name
)
90 pad
= getattr(pads
, name
)
92 if direction
== DIR_M_TO_S
:
97 if direction
== DIR_S_TO_M
:
100 r
.append(sig
.eq(pad
))
103 # Wishbone Timeout ---------------------------------------------------------------------------------
105 class Timeout(Module
):
106 def __init__(self
, master
, cycles
):
107 self
.error
= Signal()
111 timer
= WaitTimer(int(cycles
))
112 self
.submodules
+= timer
114 timer
.wait
.eq(master
.stb
& master
.cyc
& ~master
.ack
),
116 master
.dat_r
.eq((2**len(master
.dat_w
))-1),
122 # Wishbone Interconnect ----------------------------------------------------------------------------
124 class InterconnectPointToPoint(Module
):
125 def __init__(self
, master
, slave
):
126 self
.comb
+= master
.connect(slave
)
129 class Arbiter(Module
):
130 def __init__(self
, masters
, target
):
131 self
.submodules
.rr
= roundrobin
.RoundRobin(len(masters
))
133 # mux master->slave signals
134 for name
, size
, direction
in _layout
:
135 if direction
== DIR_M_TO_S
:
136 choices
= Array(getattr(m
, name
) for m
in masters
)
137 self
.comb
+= getattr(target
, name
).eq(choices
[self
.rr
.grant
])
139 # connect slave->master signals
140 for name
, size
, direction
in _layout
:
141 if direction
== DIR_S_TO_M
:
142 source
= getattr(target
, name
)
143 for i
, m
in enumerate(masters
):
144 dest
= getattr(m
, name
)
145 if name
== "ack" or name
== "err":
146 self
.comb
+= dest
.eq(source
& (self
.rr
.grant
== i
))
148 self
.comb
+= dest
.eq(source
)
150 # connect bus requests to round-robin selector
151 reqs
= [m
.cyc
for m
in masters
]
152 self
.comb
+= self
.rr
.request
.eq(Cat(*reqs
))
155 class Decoder(Module
):
156 # slaves is a list of pairs:
157 # 0) function that takes the address signal and returns a FHDL expression
158 # that evaluates to 1 when the slave is selected and 0 otherwise.
159 # 1) wishbone.Slave reference.
160 # register adds flip-flops after the address comparators. Improves timing,
161 # but breaks Wishbone combinatorial feedback.
162 def __init__(self
, master
, slaves
, register
=False):
164 slave_sel
= Signal(ns
)
165 slave_sel_r
= Signal(ns
)
167 # decode slave addresses
168 self
.comb
+= [slave_sel
[i
].eq(fun(master
.adr
))
169 for i
, (fun
, bus
) in enumerate(slaves
)]
171 self
.sync
+= slave_sel_r
.eq(slave_sel
)
173 self
.comb
+= slave_sel_r
.eq(slave_sel
)
175 # connect master->slaves signals except cyc
177 for name
, size
, direction
in _layout
:
178 if direction
== DIR_M_TO_S
and name
!= "cyc":
179 self
.comb
+= getattr(slave
[1], name
).eq(getattr(master
, name
))
181 # combine cyc with slave selection signals
182 self
.comb
+= [slave
[1].cyc
.eq(master
.cyc
& slave_sel
[i
])
183 for i
, slave
in enumerate(slaves
)]
185 # generate master ack (resp. err) by ORing all slave acks (resp. errs)
187 master
.ack
.eq(reduce(or_
, [slave
[1].ack
for slave
in slaves
])),
188 master
.err
.eq(reduce(or_
, [slave
[1].err
for slave
in slaves
]))
191 # mux (1-hot) slave data return
192 masked
= [Replicate(slave_sel_r
[i
], len(master
.dat_r
)) & slaves
[i
][1].dat_r
for i
in range(ns
)]
193 self
.comb
+= master
.dat_r
.eq(reduce(or_
, masked
))
196 class InterconnectShared(Module
):
197 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
199 self
.submodules
.arbiter
= Arbiter(masters
, shared
)
200 self
.submodules
.decoder
= Decoder(shared
, slaves
, register
)
201 if timeout_cycles
is not None:
202 self
.submodules
.timeout
= Timeout(shared
, timeout_cycles
)
205 class Crossbar(Module
):
206 def __init__(self
, masters
, slaves
, register
=False):
207 matches
, busses
= zip(*slaves
)
208 access
= [[Interface() for j
in slaves
] for i
in masters
]
209 # decode each master into its access row
210 for row
, master
in zip(access
, masters
):
211 row
= list(zip(matches
, row
))
212 self
.submodules
+= Decoder(master
, row
, register
)
213 # arbitrate each access column onto its slave
214 for column
, bus
in zip(zip(*access
), busses
):
215 self
.submodules
+= Arbiter(column
, bus
)
217 # Wishbone Data Width Converter --------------------------------------------------------------------
219 class DownConverter(Module
):
222 This module splits Wishbone accesses from a master interface to a smaller slave interface.
225 Writes from master are splitted N writes to the slave. Access is acked when the last
226 access is acked by the slave.
229 Read from master are splitted in N reads to the the slave. Read datas from
230 the slave are cached before being presented concatenated on the last access.
233 def __init__(self
, master
, slave
):
234 dw_from
= len(master
.dat_w
)
235 dw_to
= len(slave
.dat_w
)
236 ratio
= dw_from
//dw_to
241 counter
= Signal(max=ratio
)
244 fsm
= FSM(reset_state
="IDLE")
245 fsm
= ResetInserter()(fsm
)
246 self
.submodules
.fsm
= fsm
247 self
.comb
+= fsm
.reset
.eq(~master
.cyc
)
249 NextValue(counter
, 0),
250 If(master
.stb
& master
.cyc
,
251 NextState("CONVERT"),
255 slave
.adr
.eq(Cat(counter
, master
.adr
)),
256 Case(counter
, {i
: slave
.sel
.eq(master
.sel
[i
*dw_to
//8:]) for i
in range(ratio
)}),
257 If(master
.stb
& master
.cyc
,
258 skip
.eq(slave
.sel
== 0),
259 slave
.we
.eq(master
.we
),
263 NextValue(counter
, counter
+ 1),
264 If(counter
== (ratio
- 1),
273 self
.comb
+= Case(counter
, {i
: slave
.dat_w
.eq(master
.dat_w
[i
*dw_to
:]) for i
in range(ratio
)})
276 dat_r
= Signal(dw_from
, reset_less
=True)
277 self
.comb
+= master
.dat_r
.eq(Cat(dat_r
[dw_to
:], slave
.dat_r
))
278 self
.sync
+= If(slave
.ack | skip
, dat_r
.eq(master
.dat_r
))
280 class UpConverter(Module
):
282 def __init__(self
, master
, slave
):
283 dw_from
= len(master
.dat_w
)
284 dw_to
= len(slave
.dat_w
)
285 ratio
= dw_to
//dw_from
289 self
.comb
+= master
.connect(slave
, omit
={"adr", "sel", "dat_w", "dat_r"})
291 for i
in range(ratio
):
293 slave
.adr
.eq(master
.adr
[int(log2(ratio
)):]),
294 slave
.sel
[i
*dw_from
//8:(i
+1)*dw_from
//8].eq(2**(dw_from
//8) - 1),
295 slave
.dat_w
[i
*dw_from
:(i
+1)*dw_from
].eq(master
.dat_w
),
296 master
.dat_r
.eq(slave
.dat_r
[i
*dw_from
:(i
+1)*dw_from
]),
298 self
.comb
+= Case(master
.adr
[:int(log2(ratio
))], cases
)
300 class Converter(Module
):
303 This module is a wrapper for DownConverter and UpConverter.
304 It should preferably be used rather than direct instantiations
305 of specific converters.
307 def __init__(self
, master
, slave
):
313 dw_from
= len(master
.dat_r
)
314 dw_to
= len(slave
.dat_r
)
316 downconverter
= DownConverter(master
, slave
)
317 self
.submodules
+= downconverter
318 elif dw_from
< dw_to
:
319 upconverter
= UpConverter(master
, slave
)
320 self
.submodules
+= upconverter
322 self
.comb
+= master
.connect(slave
)
324 # Wishbone SRAM ------------------------------------------------------------------------------------
327 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
331 bus_data_width
= len(self
.bus
.dat_r
)
332 if isinstance(mem_or_size
, Memory
):
333 assert(mem_or_size
.width
<= bus_data_width
)
334 self
.mem
= mem_or_size
336 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
337 if read_only
is None:
338 if hasattr(self
.mem
, "bus_read_only"):
339 read_only
= self
.mem
.bus_read_only
346 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8,
347 mode
=READ_FIRST
if read_only
else WRITE_FIRST
)
348 self
.specials
+= self
.mem
, port
349 # generate write enable signal
351 self
.comb
+= [port
.we
[i
].eq(self
.bus
.cyc
& self
.bus
.stb
& self
.bus
.we
& self
.bus
.sel
[i
])
352 for i
in range(bus_data_width
//8)]
355 port
.adr
.eq(self
.bus
.adr
[:len(port
.adr
)]),
356 self
.bus
.dat_r
.eq(port
.dat_r
)
359 self
.comb
+= port
.dat_w
.eq(self
.bus
.dat_w
),
363 If(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
, self
.bus
.ack
.eq(1))
366 # Wishbone To CSR ----------------------------------------------------------------------------------
368 class Wishbone2CSR(Module
):
369 def __init__(self
, bus_wishbone
=None, bus_csr
=None):
372 # If no CSR bus provided, create it with default parameters.
373 self
.csr
= csr_bus
.Interface()
374 self
.wishbone
= bus_wishbone
375 if self
.wishbone
is None:
376 # If no Wishbone bus provided, create it with default parameters.
377 self
.wishbone
= Interface()
382 self
.csr
.dat_w
.eq(self
.wishbone
.dat_w
),
383 self
.wishbone
.dat_r
.eq(self
.csr
.dat_r
)
386 fsm
= FSM(reset_state
="WRITE-READ")
387 self
.submodules
+= fsm
388 fsm
.act("WRITE-READ",
389 If(self
.wishbone
.cyc
& self
.wishbone
.stb
,
390 self
.csr
.adr
.eq(self
.wishbone
.adr
),
391 self
.csr
.we
.eq(self
.wishbone
.we
& (self
.wishbone
.sel
!= 0)),
396 self
.wishbone
.ack
.eq(1),
397 NextState("WRITE-READ")
400 # Wishbone Cache -----------------------------------------------------------------------------------
405 This module is a write-back wishbone cache that can be used as a L2 cache.
406 Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
408 def __init__(self
, cachesize
, master
, slave
, reverse
=True):
414 dw_from
= len(master
.dat_r
)
415 dw_to
= len(slave
.dat_r
)
416 if dw_to
> dw_from
and (dw_to
% dw_from
) != 0:
417 raise ValueError("Slave data width must be a multiple of {dw}".format(dw
=dw_from
))
418 if dw_to
< dw_from
and (dw_from
% dw_to
) != 0:
419 raise ValueError("Master data width must be a multiple of {dw}".format(dw
=dw_to
))
422 # TAG | LINE NUMBER | LINE OFFSET
423 offsetbits
= log2_int(max(dw_to
//dw_from
, 1))
424 addressbits
= len(slave
.adr
) + offsetbits
425 linebits
= log2_int(cachesize
) - offsetbits
426 tagbits
= addressbits
- linebits
427 wordbits
= log2_int(max(dw_from
//dw_to
, 1))
428 adr_offset
, adr_line
, adr_tag
= split(master
.adr
, offsetbits
, linebits
, tagbits
)
429 word
= Signal(wordbits
) if wordbits
else None
432 data_mem
= Memory(dw_to
*2**wordbits
, 2**linebits
)
433 data_port
= data_mem
.get_port(write_capable
=True, we_granularity
=8)
434 self
.specials
+= data_mem
, data_port
436 write_from_slave
= Signal()
437 if adr_offset
is None:
440 adr_offset_r
= Signal(offsetbits
, reset_less
=True)
441 self
.sync
+= adr_offset_r
.eq(adr_offset
)
444 data_port
.adr
.eq(adr_line
),
446 displacer(slave
.dat_r
, word
, data_port
.dat_w
),
447 displacer(Replicate(1, dw_to
//8), word
, data_port
.we
)
449 data_port
.dat_w
.eq(Replicate(master
.dat_w
, max(dw_to
//dw_from
, 1))),
450 If(master
.cyc
& master
.stb
& master
.we
& master
.ack
,
451 displacer(master
.sel
, adr_offset
, data_port
.we
, 2**offsetbits
, reverse
=reverse
)
454 chooser(data_port
.dat_r
, word
, slave
.dat_w
),
455 slave
.sel
.eq(2**(dw_to
//8)-1),
456 chooser(data_port
.dat_r
, adr_offset_r
, master
.dat_r
, reverse
=reverse
)
461 tag_layout
= [("tag", tagbits
), ("dirty", 1)]
462 tag_mem
= Memory(layout_len(tag_layout
), 2**linebits
)
463 tag_port
= tag_mem
.get_port(write_capable
=True)
464 self
.specials
+= tag_mem
, tag_port
465 tag_do
= Record(tag_layout
)
466 tag_di
= Record(tag_layout
)
468 tag_do
.raw_bits().eq(tag_port
.dat_r
),
469 tag_port
.dat_w
.eq(tag_di
.raw_bits())
473 tag_port
.adr
.eq(adr_line
),
474 tag_di
.tag
.eq(adr_tag
)
477 self
.comb
+= slave
.adr
.eq(Cat(word
, adr_line
, tag_do
.tag
))
479 self
.comb
+= slave
.adr
.eq(Cat(adr_line
, tag_do
.tag
))
481 # slave word computation, word_clr and word_inc will be simplified
482 # at synthesis when wordbits=0
493 def word_is_last(word
):
495 return word
== 2**wordbits
-1
500 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
502 If(master
.cyc
& master
.stb
,
503 NextState("TEST_HIT")
508 If(tag_do
.tag
== adr_tag
,
519 # Write the tag first to set the slave address
533 If(word_is_last(word
),
534 # Write the tag first to set the slave address
546 write_from_slave
.eq(1),
548 If(word_is_last(word
),
549 NextState("TEST_HIT"),