1 from functools
import reduce
2 from operator
import or_
4 from litex
.gen
import *
5 from litex
.gen
.genlib
import roundrobin
6 from litex
.gen
.genlib
.record
import *
7 from litex
.gen
.genlib
.misc
import split
, displacer
, chooser
8 from litex
.gen
.genlib
.fsm
import FSM
, NextState
10 from litex
.soc
.interconnect
import csr
12 # TODO: rewrite without FlipFlop and Counter
16 ("adr", 30, DIR_M_TO_S
),
17 ("dat_w", "data_width", DIR_M_TO_S
),
18 ("dat_r", "data_width", DIR_S_TO_M
),
19 ("sel", "sel_width", DIR_M_TO_S
),
20 ("cyc", 1, DIR_M_TO_S
),
21 ("stb", 1, DIR_M_TO_S
),
22 ("ack", 1, DIR_S_TO_M
),
23 ("we", 1, DIR_M_TO_S
),
24 ("cti", 3, DIR_M_TO_S
),
25 ("bte", 2, DIR_M_TO_S
),
26 ("err", 1, DIR_S_TO_M
)
30 class Interface(Record
):
31 def __init__(self
, data_width
=32):
32 Record
.__init
__(self
, set_layout_parameters(_layout
,
33 data_width
=data_width
,
34 sel_width
=data_width
//8))
36 def _do_transaction(self
):
40 while not (yield self
.ack
):
45 def write(self
, adr
, dat
, sel
=None):
47 sel
= 2**len(self
.sel
) - 1
48 yield self
.adr
.eq(adr
)
49 yield self
.dat_w
.eq(dat
)
50 yield self
.sel
.eq(sel
)
52 yield from self
._do
_transaction
()
55 yield self
.adr
.eq(adr
)
57 yield from self
._do
_transaction
()
58 return (yield self
.dat_r
)
61 class InterconnectPointToPoint(Module
):
62 def __init__(self
, master
, slave
):
63 self
.comb
+= master
.connect(slave
)
66 class Arbiter(Module
):
67 def __init__(self
, masters
, target
):
68 self
.submodules
.rr
= roundrobin
.RoundRobin(len(masters
))
70 # mux master->slave signals
71 for name
, size
, direction
in _layout
:
72 if direction
== DIR_M_TO_S
:
73 choices
= Array(getattr(m
, name
) for m
in masters
)
74 self
.comb
+= getattr(target
, name
).eq(choices
[self
.rr
.grant
])
76 # connect slave->master signals
77 for name
, size
, direction
in _layout
:
78 if direction
== DIR_S_TO_M
:
79 source
= getattr(target
, name
)
80 for i
, m
in enumerate(masters
):
81 dest
= getattr(m
, name
)
82 if name
== "ack" or name
== "err":
83 self
.comb
+= dest
.eq(source
& (self
.rr
.grant
== i
))
85 self
.comb
+= dest
.eq(source
)
87 # connect bus requests to round-robin selector
88 reqs
= [m
.cyc
for m
in masters
]
89 self
.comb
+= self
.rr
.request
.eq(Cat(*reqs
))
92 class Decoder(Module
):
93 # slaves is a list of pairs:
94 # 0) function that takes the address signal and returns a FHDL expression
95 # that evaluates to 1 when the slave is selected and 0 otherwise.
96 # 1) wishbone.Slave reference.
97 # register adds flip-flops after the address comparators. Improves timing,
98 # but breaks Wishbone combinatorial feedback.
99 def __init__(self
, master
, slaves
, register
=False):
101 slave_sel
= Signal(ns
)
102 slave_sel_r
= Signal(ns
)
104 # decode slave addresses
105 self
.comb
+= [slave_sel
[i
].eq(fun(master
.adr
))
106 for i
, (fun
, bus
) in enumerate(slaves
)]
108 self
.sync
+= slave_sel_r
.eq(slave_sel
)
110 self
.comb
+= slave_sel_r
.eq(slave_sel
)
112 # connect master->slaves signals except cyc
114 for name
, size
, direction
in _layout
:
115 if direction
== DIR_M_TO_S
and name
!= "cyc":
116 self
.comb
+= getattr(slave
[1], name
).eq(getattr(master
, name
))
118 # combine cyc with slave selection signals
119 self
.comb
+= [slave
[1].cyc
.eq(master
.cyc
& slave_sel
[i
])
120 for i
, slave
in enumerate(slaves
)]
122 # generate master ack (resp. err) by ORing all slave acks (resp. errs)
124 master
.ack
.eq(reduce(or_
, [slave
[1].ack
for slave
in slaves
])),
125 master
.err
.eq(reduce(or_
, [slave
[1].err
for slave
in slaves
]))
128 # mux (1-hot) slave data return
129 masked
= [Replicate(slave_sel_r
[i
], len(master
.dat_r
)) & slaves
[i
][1].dat_r
for i
in range(ns
)]
130 self
.comb
+= master
.dat_r
.eq(reduce(or_
, masked
))
133 class InterconnectShared(Module
):
134 def __init__(self
, masters
, slaves
, register
=False):
136 self
.submodules
+= Arbiter(masters
, shared
)
137 self
.submodules
+= Decoder(shared
, slaves
, register
)
140 class Crossbar(Module
):
141 def __init__(self
, masters
, slaves
, register
=False):
142 matches
, busses
= zip(*slaves
)
143 access
= [[Interface() for j
in slaves
] for i
in masters
]
144 # decode each master into its access row
145 for row
, master
in zip(access
, masters
):
146 row
= list(zip(matches
, row
))
147 self
.submodules
+= Decoder(master
, row
, register
)
148 # arbitrate each access column onto its slave
149 for column
, bus
in zip(zip(*access
), busses
):
150 self
.submodules
+= Arbiter(column
, bus
)
153 class DownConverter(Module
):
156 This module splits Wishbone accesses from a master interface to a smaller
160 Writes from master are splitted N writes to the slave. Access is acked when the last
161 access is acked by the slave.
164 Read from master are splitted in N reads to the the slave. Read datas from
165 the slave are cached before being presented concatenated on the last access.
168 def __init__(self
, master
, slave
):
169 dw_from
= len(master
.dat_r
)
170 dw_to
= len(slave
.dat_w
)
171 ratio
= dw_from
//dw_to
178 counter
= Signal(max=ratio
)
179 counter_reset
= Signal()
180 counter_ce
= Signal()
185 counter
.eq(counter
+ 1)
187 counter_done
= Signal()
188 self
.comb
+= counter_done
.eq(counter
== ratio
-1)
191 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
194 If(master
.stb
& master
.cyc
,
206 If(master
.stb
& master
.cyc
,
222 If(master
.stb
& master
.cyc
,
239 slave
.cti
.eq(7) # indicate end of burst
243 slave
.adr
.eq(Cat(counter
, master
.adr
))
248 for i
in range(ratio
):
250 slave
.sel
.eq(master
.sel
[i
*dw_to
//8:(i
+1)*dw_to
]),
251 slave
.dat_w
.eq(master
.dat_w
[i
*dw_to
:(i
+1)*dw_to
])
253 self
.comb
+= Case(counter
, cases
)
256 cached_data
= Signal(dw_from
)
257 self
.comb
+= master
.dat_r
.eq(Cat(cached_data
[dw_to
:], slave
.dat_r
))
259 If(read
& counter_ce
,
260 cached_data
.eq(master
.dat_r
)
264 class UpConverter(Module
):
267 This module up-converts wishbone accesses and bursts from a master interface
268 to a wider slave interface. This allows efficient use wishbone bursts.
271 Wishbone writes are cached before being written to the slave. Access to
272 the slave is done at the end of a burst or when address reach end of burst
276 Cache is refilled only at the beginning of each burst, the subsequent
277 reads of a burst use the cached data.
280 def __init__(self
, master
, slave
):
281 dw_from
= len(master
.dat_r
)
282 dw_to
= len(slave
.dat_w
)
283 ratio
= dw_to
//dw_from
284 ratiobits
= log2_int(ratio
)
293 address
= FlipFlop(30)
294 self
.submodules
+= address
295 self
.comb
+= address
.d
.eq(master
.adr
)
297 counter
= Signal(max=ratio
)
298 counter_ce
= Signal()
299 counter_reset
= Signal()
304 counter
.eq(counter
+ 1)
306 counter_offset
= Signal(max=ratio
)
307 counter_done
= Signal()
309 counter_offset
.eq(address
.q
),
310 counter_done
.eq((counter
+ counter_offset
) == ratio
-1)
313 cached_data
= Signal(dw_to
)
314 cached_sel
= Signal(dw_to
//8)
316 end_of_burst
= Signal()
317 self
.comb
+= end_of_burst
.eq(~master
.cyc |
318 (master
.stb
& master
.cyc
& master
.ack
& ((master
.cti
== 7) | counter_done
)))
321 need_refill
= FlipFlop(reset
=1)
322 self
.submodules
+= need_refill
324 need_refill
.reset
.eq(end_of_burst
),
329 self
.submodules
.fsm
= fsm
= FSM()
332 If(master
.stb
& master
.cyc
,
346 If(master
.stb
& master
.cyc
,
362 slave
.dat_w
.eq(cached_data
),
363 slave
.sel
.eq(cached_sel
),
373 need_refill
.ce
.eq(1),
379 If(master
.stb
& master
.cyc
,
387 slave
.cti
.eq(7), # we are not able to generate bursts since up-converting
388 slave
.adr
.eq(address
.q
[ratiobits
:])
392 cached_datas
= [FlipFlop(dw_from
) for i
in range(ratio
)]
393 cached_sels
= [FlipFlop(dw_from
//8) for i
in range(ratio
)]
394 self
.submodules
+= cached_datas
, cached_sels
397 for i
in range(ratio
):
399 cases
[i
] = write_sel
.eq(1)
401 cached_sels
[i
].reset
.eq(counter_reset
),
403 cached_datas
[i
].d
.eq(master
.dat_w
),
405 cached_datas
[i
].d
.eq(slave
.dat_r
[dw_from
*i
:dw_from
*(i
+1)])
407 cached_sels
[i
].d
.eq(master
.sel
),
408 If((write
& write_sel
) | refill
,
409 cached_datas
[i
].ce
.eq(1),
410 cached_sels
[i
].ce
.eq(1)
413 self
.comb
+= Case(counter
+ counter_offset
, cases
)
416 for i
in range(ratio
):
417 cases
[i
] = master
.dat_r
.eq(cached_datas
[i
].q
)
418 self
.comb
+= Case(address
.q
[:ratiobits
], cases
)
421 cached_data
.eq(Cat([cached_data
.q
for cached_data
in cached_datas
])),
422 cached_sel
.eq(Cat([cached_sel
.q
for cached_sel
in cached_sels
]))
426 class Converter(Module
):
429 This module is a wrapper for DownConverter and UpConverter.
430 It should preferably be used rather than direct instantiations
431 of specific converters.
433 def __init__(self
, master
, slave
):
439 dw_from
= len(master
.dat_r
)
440 dw_to
= len(slave
.dat_r
)
442 downconverter
= DownConverter(master
, slave
)
443 self
.submodules
+= downconverter
444 elif dw_from
< dw_to
:
445 upconverter
= UpConverter(master
, slave
)
446 self
.submodules
+= upconverter
448 Record
.connect(master
, slave
)
454 This module is a write-back wishbone cache that can be used as a L2 cache.
455 Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
457 def __init__(self
, cachesize
, master
, slave
):
463 dw_from
= len(master
.dat_r
)
464 dw_to
= len(slave
.dat_r
)
465 if dw_to
> dw_from
and (dw_to
% dw_from
) != 0:
466 raise ValueError("Slave data width must be a multiple of {dw}".format(dw
=dw_from
))
467 if dw_to
< dw_from
and (dw_from
% dw_to
) != 0:
468 raise ValueError("Master data width must be a multiple of {dw}".format(dw
=dw_to
))
471 # TAG | LINE NUMBER | LINE OFFSET
472 offsetbits
= log2_int(max(dw_to
//dw_from
, 1))
473 addressbits
= len(slave
.adr
) + offsetbits
474 linebits
= log2_int(cachesize
) - offsetbits
475 tagbits
= addressbits
- linebits
476 wordbits
= log2_int(max(dw_from
//dw_to
, 1))
477 adr_offset
, adr_line
, adr_tag
= split(master
.adr
, offsetbits
, linebits
, tagbits
)
478 word
= Signal(wordbits
) if wordbits
else None
481 data_mem
= Memory(dw_to
*2**wordbits
, 2**linebits
)
482 data_port
= data_mem
.get_port(write_capable
=True, we_granularity
=8)
483 self
.specials
+= data_mem
, data_port
485 write_from_slave
= Signal()
486 if adr_offset
is None:
489 adr_offset_r
= Signal(offsetbits
)
490 self
.sync
+= adr_offset_r
.eq(adr_offset
)
493 data_port
.adr
.eq(adr_line
),
495 displacer(slave
.dat_r
, word
, data_port
.dat_w
),
496 displacer(Replicate(1, dw_to
//8), word
, data_port
.we
)
498 data_port
.dat_w
.eq(Replicate(master
.dat_w
, max(dw_to
//dw_from
, 1))),
499 If(master
.cyc
& master
.stb
& master
.we
& master
.ack
,
500 displacer(master
.sel
, adr_offset
, data_port
.we
, 2**offsetbits
, reverse
=True)
503 chooser(data_port
.dat_r
, word
, slave
.dat_w
),
504 slave
.sel
.eq(2**(dw_to
//8)-1),
505 chooser(data_port
.dat_r
, adr_offset_r
, master
.dat_r
, reverse
=True)
510 tag_layout
= [("tag", tagbits
), ("dirty", 1)]
511 tag_mem
= Memory(layout_len(tag_layout
), 2**linebits
)
512 tag_port
= tag_mem
.get_port(write_capable
=True)
513 self
.specials
+= tag_mem
, tag_port
514 tag_do
= Record(tag_layout
)
515 tag_di
= Record(tag_layout
)
517 tag_do
.raw_bits().eq(tag_port
.dat_r
),
518 tag_port
.dat_w
.eq(tag_di
.raw_bits())
522 tag_port
.adr
.eq(adr_line
),
523 tag_di
.tag
.eq(adr_tag
)
526 self
.comb
+= slave
.adr
.eq(Cat(word
, adr_line
, tag_do
.tag
))
528 self
.comb
+= slave
.adr
.eq(Cat(adr_line
, tag_do
.tag
))
530 # slave word computation, word_clr and word_inc will be simplified
531 # at synthesis when wordbits=0
542 def word_is_last(word
):
544 return word
== 2**wordbits
-1
549 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
551 If(master
.cyc
& master
.stb
,
552 NextState("TEST_HIT")
557 If(tag_do
.tag
== adr_tag
,
568 NextState("REFILL_WRTAG")
579 If(word_is_last(word
),
580 NextState("REFILL_WRTAG")
584 fsm
.act("REFILL_WRTAG",
585 # Write the tag first to set the slave address
595 write_from_slave
.eq(1),
597 If(word_is_last(word
),
598 NextState("TEST_HIT"),
607 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
611 bus_data_width
= len(self
.bus
.dat_r
)
612 if isinstance(mem_or_size
, Memory
):
613 assert(mem_or_size
.width
<= bus_data_width
)
614 self
.mem
= mem_or_size
616 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
617 if read_only
is None:
618 if hasattr(self
.mem
, "bus_read_only"):
619 read_only
= self
.mem
.bus_read_only
626 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8)
627 self
.specials
+= self
.mem
, port
628 # generate write enable signal
630 self
.comb
+= [port
.we
[i
].eq(self
.bus
.cyc
& self
.bus
.stb
& self
.bus
.we
& self
.bus
.sel
[i
])
634 port
.adr
.eq(self
.bus
.adr
[:len(port
.adr
)]),
635 self
.bus
.dat_r
.eq(port
.dat_r
)
638 self
.comb
+= port
.dat_w
.eq(self
.bus
.dat_w
),
642 If(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
, self
.bus
.ack
.eq(1))
646 class CSRBank(csr
.GenericBank
):
647 def __init__(self
, description
, bus
=None):
654 csr
.GenericBank
.__init
__(self
, description
, len(self
.bus
.dat_w
))
656 for i
, c
in enumerate(self
.simple_csrs
):
658 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
659 c
.re
.eq(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
& self
.bus
.we
& \
660 (self
.bus
.adr
[:self
.decode_bits
] == i
))
663 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
665 Case(self
.bus
.adr
[:self
.decode_bits
], brcases
),
666 If(bus
.ack
, bus
.ack
.eq(0)).Elif(bus
.cyc
& bus
.stb
, bus
.ack
.eq(1))