1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
6 from functools
import reduce
7 from operator
import or_
10 from migen
.genlib
import roundrobin
11 from migen
.genlib
.record
import *
12 from migen
.genlib
.misc
import split
, displacer
, chooser
, WaitTimer
13 from migen
.genlib
.fsm
import FSM
, NextState
15 from litex
.soc
.interconnect
import csr
16 from litex
.build
.generic_platform
import *
18 # TODO: rewrite without FlipFlop
22 ("adr", "adr_width", DIR_M_TO_S
),
23 ("dat_w", "data_width", DIR_M_TO_S
),
24 ("dat_r", "data_width", DIR_S_TO_M
),
25 ("sel", "sel_width", DIR_M_TO_S
),
26 ("cyc", 1, DIR_M_TO_S
),
27 ("stb", 1, DIR_M_TO_S
),
28 ("ack", 1, DIR_S_TO_M
),
29 ("we", 1, DIR_M_TO_S
),
30 ("cti", 3, DIR_M_TO_S
),
31 ("bte", 2, DIR_M_TO_S
),
32 ("err", 1, DIR_S_TO_M
)
36 class Interface(Record
):
37 def __init__(self
, data_width
=32, adr_width
=30):
38 self
.data_width
= data_width
39 self
.adr_width
= adr_width
40 Record
.__init
__(self
, set_layout_parameters(_layout
,
41 adr_width
= adr_width
,
42 data_width
= data_width
,
43 sel_width
= data_width
//8))
44 self
.adr
.reset_less
= True
45 self
.dat_w
.reset_less
= True
46 self
.dat_r
.reset_less
= True
47 self
.sel
.reset_less
= True
51 return Interface(len(other
.dat_w
))
53 def _do_transaction(self
):
57 while not (yield self
.ack
):
62 def write(self
, adr
, dat
, sel
=None):
64 sel
= 2**len(self
.sel
) - 1
65 yield self
.adr
.eq(adr
)
66 yield self
.dat_w
.eq(dat
)
67 yield self
.sel
.eq(sel
)
69 yield from self
._do
_transaction
()
72 yield self
.adr
.eq(adr
)
74 yield from self
._do
_transaction
()
75 return (yield self
.dat_r
)
77 def get_ios(self
, bus_name
="wb"):
79 for name
, width
, direction
in self
.layout
:
80 subsignals
.append(Subsignal(name
, Pins(width
)))
81 ios
= [(bus_name
, 0) + tuple(subsignals
)]
84 def connect_to_pads(self
, pads
, mode
="master"):
85 assert mode
in ["slave", "master"]
87 for name
, width
, direction
in self
.layout
:
88 sig
= getattr(self
, name
)
89 pad
= getattr(pads
, name
)
91 if direction
== DIR_M_TO_S
:
96 if direction
== DIR_S_TO_M
:
103 class InterconnectPointToPoint(Module
):
104 def __init__(self
, master
, slave
):
105 self
.comb
+= master
.connect(slave
)
108 class Arbiter(Module
):
109 def __init__(self
, masters
, target
):
110 self
.submodules
.rr
= roundrobin
.RoundRobin(len(masters
))
112 # mux master->slave signals
113 for name
, size
, direction
in _layout
:
114 if direction
== DIR_M_TO_S
:
115 choices
= Array(getattr(m
, name
) for m
in masters
)
116 self
.comb
+= getattr(target
, name
).eq(choices
[self
.rr
.grant
])
118 # connect slave->master signals
119 for name
, size
, direction
in _layout
:
120 if direction
== DIR_S_TO_M
:
121 source
= getattr(target
, name
)
122 for i
, m
in enumerate(masters
):
123 dest
= getattr(m
, name
)
124 if name
== "ack" or name
== "err":
125 self
.comb
+= dest
.eq(source
& (self
.rr
.grant
== i
))
127 self
.comb
+= dest
.eq(source
)
129 # connect bus requests to round-robin selector
130 reqs
= [m
.cyc
for m
in masters
]
131 self
.comb
+= self
.rr
.request
.eq(Cat(*reqs
))
134 class Decoder(Module
):
135 # slaves is a list of pairs:
136 # 0) function that takes the address signal and returns a FHDL expression
137 # that evaluates to 1 when the slave is selected and 0 otherwise.
138 # 1) wishbone.Slave reference.
139 # register adds flip-flops after the address comparators. Improves timing,
140 # but breaks Wishbone combinatorial feedback.
141 def __init__(self
, master
, slaves
, register
=False):
143 slave_sel
= Signal(ns
)
144 slave_sel_r
= Signal(ns
)
146 # decode slave addresses
147 self
.comb
+= [slave_sel
[i
].eq(fun(master
.adr
))
148 for i
, (fun
, bus
) in enumerate(slaves
)]
150 self
.sync
+= slave_sel_r
.eq(slave_sel
)
152 self
.comb
+= slave_sel_r
.eq(slave_sel
)
154 # connect master->slaves signals except cyc
156 for name
, size
, direction
in _layout
:
157 if direction
== DIR_M_TO_S
and name
!= "cyc":
158 self
.comb
+= getattr(slave
[1], name
).eq(getattr(master
, name
))
160 # combine cyc with slave selection signals
161 self
.comb
+= [slave
[1].cyc
.eq(master
.cyc
& slave_sel
[i
])
162 for i
, slave
in enumerate(slaves
)]
164 # generate master ack (resp. err) by ORing all slave acks (resp. errs)
166 master
.ack
.eq(reduce(or_
, [slave
[1].ack
for slave
in slaves
])),
167 master
.err
.eq(reduce(or_
, [slave
[1].err
for slave
in slaves
]))
170 # mux (1-hot) slave data return
171 masked
= [Replicate(slave_sel_r
[i
], len(master
.dat_r
)) & slaves
[i
][1].dat_r
for i
in range(ns
)]
172 self
.comb
+= master
.dat_r
.eq(reduce(or_
, masked
))
175 class Timeout(Module
):
176 def __init__(self
, master
, cycles
):
177 self
.error
= Signal()
181 timer
= WaitTimer(int(cycles
))
182 self
.submodules
+= timer
184 timer
.wait
.eq(master
.stb
& master
.cyc
& ~master
.ack
),
186 master
.dat_r
.eq((2**len(master
.dat_w
))-1),
193 class InterconnectShared(Module
):
194 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
196 self
.submodules
.arbiter
= Arbiter(masters
, shared
)
197 self
.submodules
.decoder
= Decoder(shared
, slaves
, register
)
198 if timeout_cycles
is not None:
199 self
.submodules
.timeout
= Timeout(shared
, timeout_cycles
)
202 class Crossbar(Module
):
203 def __init__(self
, masters
, slaves
, register
=False):
204 matches
, busses
= zip(*slaves
)
205 access
= [[Interface() for j
in slaves
] for i
in masters
]
206 # decode each master into its access row
207 for row
, master
in zip(access
, masters
):
208 row
= list(zip(matches
, row
))
209 self
.submodules
+= Decoder(master
, row
, register
)
210 # arbitrate each access column onto its slave
211 for column
, bus
in zip(zip(*access
), busses
):
212 self
.submodules
+= Arbiter(column
, bus
)
215 class DownConverter(Module
):
218 This module splits Wishbone accesses from a master interface to a smaller
222 Writes from master are splitted N writes to the slave. Access is acked when the last
223 access is acked by the slave.
226 Read from master are splitted in N reads to the the slave. Read datas from
227 the slave are cached before being presented concatenated on the last access.
230 def __init__(self
, master
, slave
):
231 dw_from
= len(master
.dat_r
)
232 dw_to
= len(slave
.dat_w
)
233 ratio
= dw_from
//dw_to
240 counter
= Signal(max=ratio
)
241 counter_reset
= Signal()
242 counter_ce
= Signal()
247 counter
.eq(counter
+ 1)
249 counter_done
= Signal()
250 self
.comb
+= counter_done
.eq(counter
== ratio
-1)
253 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
256 If(master
.stb
& master
.cyc
,
268 If(master
.stb
& master
.cyc
,
284 If(master
.stb
& master
.cyc
,
301 slave
.cti
.eq(7) # indicate end of burst
305 slave
.adr
.eq(Cat(counter
, master
.adr
))
310 for i
in range(ratio
):
312 slave
.sel
.eq(master
.sel
[i
*dw_to
//8:(i
+1)*dw_to
]),
313 slave
.dat_w
.eq(master
.dat_w
[i
*dw_to
:(i
+1)*dw_to
])
315 self
.comb
+= Case(counter
, cases
)
318 cached_data
= Signal(dw_from
, reset_less
=True)
319 self
.comb
+= master
.dat_r
.eq(Cat(cached_data
[dw_to
:], slave
.dat_r
))
321 If(read
& counter_ce
,
322 cached_data
.eq(master
.dat_r
)
328 class FlipFlop(Module
):
329 def __init__(self
, *args
, **kwargs
):
330 self
.d
= Signal(*args
, **kwargs
)
331 self
.q
= Signal(*args
, **kwargs
)
332 self
.sync
+= self
.q
.eq(self
.d
)
335 class UpConverter(Module
):
338 This module up-converts wishbone accesses and bursts from a master interface
339 to a wider slave interface. This allows efficient use wishbone bursts.
342 Wishbone writes are cached before being written to the slave. Access to
343 the slave is done at the end of a burst or when address reach end of burst
347 Cache is refilled only at the beginning of each burst, the subsequent
348 reads of a burst use the cached data.
351 def __init__(self
, master
, slave
):
352 dw_from
= len(master
.dat_r
)
353 dw_to
= len(slave
.dat_w
)
354 ratio
= dw_to
//dw_from
355 ratiobits
= log2_int(ratio
)
364 address
= FlipFlop(30)
365 self
.submodules
+= address
366 self
.comb
+= address
.d
.eq(master
.adr
)
368 counter
= Signal(max=ratio
)
369 counter_ce
= Signal()
370 counter_reset
= Signal()
375 counter
.eq(counter
+ 1)
377 counter_offset
= Signal(max=ratio
)
378 counter_done
= Signal()
380 counter_offset
.eq(address
.q
),
381 counter_done
.eq((counter
+ counter_offset
) == ratio
-1)
384 cached_data
= Signal(dw_to
)
385 cached_sel
= Signal(dw_to
//8)
387 end_of_burst
= Signal()
388 self
.comb
+= end_of_burst
.eq(~master
.cyc |
389 (master
.stb
& master
.cyc
& master
.ack
& ((master
.cti
== 7) | counter_done
)))
392 need_refill
= FlipFlop(reset
=1)
393 self
.submodules
+= need_refill
395 need_refill
.reset
.eq(end_of_burst
),
400 self
.submodules
.fsm
= fsm
= FSM()
403 If(master
.stb
& master
.cyc
,
417 If(master
.stb
& master
.cyc
,
433 slave
.dat_w
.eq(cached_data
),
434 slave
.sel
.eq(cached_sel
),
444 need_refill
.ce
.eq(1),
450 If(master
.stb
& master
.cyc
,
458 slave
.cti
.eq(7), # we are not able to generate bursts since up-converting
459 slave
.adr
.eq(address
.q
[ratiobits
:])
463 cached_datas
= [FlipFlop(dw_from
) for i
in range(ratio
)]
464 cached_sels
= [FlipFlop(dw_from
//8) for i
in range(ratio
)]
465 self
.submodules
+= cached_datas
, cached_sels
468 for i
in range(ratio
):
470 cases
[i
] = write_sel
.eq(1)
472 cached_sels
[i
].reset
.eq(counter_reset
),
474 cached_datas
[i
].d
.eq(master
.dat_w
),
476 cached_datas
[i
].d
.eq(slave
.dat_r
[dw_from
*i
:dw_from
*(i
+1)])
478 cached_sels
[i
].d
.eq(master
.sel
),
479 If((write
& write_sel
) | refill
,
480 cached_datas
[i
].ce
.eq(1),
481 cached_sels
[i
].ce
.eq(1)
484 self
.comb
+= Case(counter
+ counter_offset
, cases
)
487 for i
in range(ratio
):
488 cases
[i
] = master
.dat_r
.eq(cached_datas
[i
].q
)
489 self
.comb
+= Case(address
.q
[:ratiobits
], cases
)
492 cached_data
.eq(Cat([cached_data
.q
for cached_data
in cached_datas
])),
493 cached_sel
.eq(Cat([cached_sel
.q
for cached_sel
in cached_sels
]))
497 class Converter(Module
):
500 This module is a wrapper for DownConverter and UpConverter.
501 It should preferably be used rather than direct instantiations
502 of specific converters.
504 def __init__(self
, master
, slave
):
510 dw_from
= len(master
.dat_r
)
511 dw_to
= len(slave
.dat_r
)
513 downconverter
= DownConverter(master
, slave
)
514 self
.submodules
+= downconverter
515 elif dw_from
< dw_to
:
516 upconverter
= UpConverter(master
, slave
)
517 self
.submodules
+= upconverter
519 self
.comb
+= master
.connect(slave
)
525 This module is a write-back wishbone cache that can be used as a L2 cache.
526 Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
528 def __init__(self
, cachesize
, master
, slave
, reverse
=True):
534 dw_from
= len(master
.dat_r
)
535 dw_to
= len(slave
.dat_r
)
536 if dw_to
> dw_from
and (dw_to
% dw_from
) != 0:
537 raise ValueError("Slave data width must be a multiple of {dw}".format(dw
=dw_from
))
538 if dw_to
< dw_from
and (dw_from
% dw_to
) != 0:
539 raise ValueError("Master data width must be a multiple of {dw}".format(dw
=dw_to
))
542 # TAG | LINE NUMBER | LINE OFFSET
543 offsetbits
= log2_int(max(dw_to
//dw_from
, 1))
544 addressbits
= len(slave
.adr
) + offsetbits
545 linebits
= log2_int(cachesize
) - offsetbits
546 tagbits
= addressbits
- linebits
547 wordbits
= log2_int(max(dw_from
//dw_to
, 1))
548 adr_offset
, adr_line
, adr_tag
= split(master
.adr
, offsetbits
, linebits
, tagbits
)
549 word
= Signal(wordbits
) if wordbits
else None
552 data_mem
= Memory(dw_to
*2**wordbits
, 2**linebits
)
553 data_port
= data_mem
.get_port(write_capable
=True, we_granularity
=8)
554 self
.specials
+= data_mem
, data_port
556 write_from_slave
= Signal()
557 if adr_offset
is None:
560 adr_offset_r
= Signal(offsetbits
, reset_less
=True)
561 self
.sync
+= adr_offset_r
.eq(adr_offset
)
564 data_port
.adr
.eq(adr_line
),
566 displacer(slave
.dat_r
, word
, data_port
.dat_w
),
567 displacer(Replicate(1, dw_to
//8), word
, data_port
.we
)
569 data_port
.dat_w
.eq(Replicate(master
.dat_w
, max(dw_to
//dw_from
, 1))),
570 If(master
.cyc
& master
.stb
& master
.we
& master
.ack
,
571 displacer(master
.sel
, adr_offset
, data_port
.we
, 2**offsetbits
, reverse
=reverse
)
574 chooser(data_port
.dat_r
, word
, slave
.dat_w
),
575 slave
.sel
.eq(2**(dw_to
//8)-1),
576 chooser(data_port
.dat_r
, adr_offset_r
, master
.dat_r
, reverse
=reverse
)
581 tag_layout
= [("tag", tagbits
), ("dirty", 1)]
582 tag_mem
= Memory(layout_len(tag_layout
), 2**linebits
)
583 tag_port
= tag_mem
.get_port(write_capable
=True)
584 self
.specials
+= tag_mem
, tag_port
585 tag_do
= Record(tag_layout
)
586 tag_di
= Record(tag_layout
)
588 tag_do
.raw_bits().eq(tag_port
.dat_r
),
589 tag_port
.dat_w
.eq(tag_di
.raw_bits())
593 tag_port
.adr
.eq(adr_line
),
594 tag_di
.tag
.eq(adr_tag
)
597 self
.comb
+= slave
.adr
.eq(Cat(word
, adr_line
, tag_do
.tag
))
599 self
.comb
+= slave
.adr
.eq(Cat(adr_line
, tag_do
.tag
))
601 # slave word computation, word_clr and word_inc will be simplified
602 # at synthesis when wordbits=0
613 def word_is_last(word
):
615 return word
== 2**wordbits
-1
620 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
622 If(master
.cyc
& master
.stb
,
623 NextState("TEST_HIT")
628 If(tag_do
.tag
== adr_tag
,
639 # Write the tag first to set the slave address
653 If(word_is_last(word
),
654 # Write the tag first to set the slave address
666 write_from_slave
.eq(1),
668 If(word_is_last(word
),
669 NextState("TEST_HIT"),
678 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
682 bus_data_width
= len(self
.bus
.dat_r
)
683 if isinstance(mem_or_size
, Memory
):
684 assert(mem_or_size
.width
<= bus_data_width
)
685 self
.mem
= mem_or_size
687 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
688 if read_only
is None:
689 if hasattr(self
.mem
, "bus_read_only"):
690 read_only
= self
.mem
.bus_read_only
697 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8,
698 mode
=READ_FIRST
if read_only
else WRITE_FIRST
)
699 self
.specials
+= self
.mem
, port
700 # generate write enable signal
702 self
.comb
+= [port
.we
[i
].eq(self
.bus
.cyc
& self
.bus
.stb
& self
.bus
.we
& self
.bus
.sel
[i
])
703 for i
in range(bus_data_width
//8)]
706 port
.adr
.eq(self
.bus
.adr
[:len(port
.adr
)]),
707 self
.bus
.dat_r
.eq(port
.dat_r
)
710 self
.comb
+= port
.dat_w
.eq(self
.bus
.dat_w
),
714 If(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
, self
.bus
.ack
.eq(1))
718 class CSRBank(csr
.GenericBank
):
719 def __init__(self
, description
, bus
=None):
726 csr
.GenericBank
.__init
__(self
, description
, len(self
.bus
.dat_w
))
728 for i
, c
in enumerate(self
.simple_csrs
):
730 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
731 c
.re
.eq(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
& self
.bus
.we
& \
732 (self
.bus
.adr
[:self
.decode_bits
] == i
))
735 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
737 Case(self
.bus
.adr
[:self
.decode_bits
], brcases
),
738 If(bus
.ack
, bus
.ack
.eq(0)).Elif(bus
.cyc
& bus
.stb
, bus
.ack
.eq(1))