1 from functools
import reduce
2 from operator
import or_
5 from migen
.genlib
import roundrobin
6 from migen
.genlib
.record
import *
7 from migen
.genlib
.misc
import split
, displacer
, chooser
8 from migen
.genlib
.fsm
import FSM
, NextState
10 from misoc
.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 Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
170 def __init__(self
, master
, slave
):
171 dw_from
= len(master
.dat_r
)
172 dw_to
= len(slave
.dat_w
)
173 ratio
= dw_from
//dw_to
180 counter
= Counter(max=ratio
)
181 self
.submodules
+= counter
182 counter_done
= Signal()
183 self
.comb
+= counter_done
.eq(counter
.value
== ratio
-1)
186 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
189 If(master
.stb
& master
.cyc
,
201 If(master
.stb
& master
.cyc
,
217 If(master
.stb
& master
.cyc
,
234 slave
.cti
.eq(7) # indicate end of burst
238 slave
.adr
.eq(Cat(counter
.value
, master
.adr
))
243 for i
in range(ratio
):
245 slave
.sel
.eq(master
.sel
[i
*dw_to
//8:(i
+1)*dw_to
]),
246 slave
.dat_w
.eq(master
.dat_w
[i
*dw_to
:(i
+1)*dw_to
])
248 self
.comb
+= Case(counter
.value
, cases
)
251 cached_data
= Signal(dw_from
)
252 self
.comb
+= master
.dat_r
.eq(Cat(cached_data
[dw_to
:], slave
.dat_r
))
254 If(read
& counter
.ce
,
255 cached_data
.eq(master
.dat_r
)
259 class UpConverter(Module
):
262 This module up-converts wishbone accesses and bursts from a master interface
263 to a wider slave interface. This allows efficient use wishbone bursts.
266 Wishbone writes are cached before being written to the slave. Access to
267 the slave is done at the end of a burst or when address reach end of burst
271 Cache is refilled only at the beginning of each burst, the subsequent
272 reads of a burst use the cached data.
275 Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
277 def __init__(self
, master
, slave
):
278 dw_from
= len(master
.dat_r
)
279 dw_to
= len(slave
.dat_w
)
280 ratio
= dw_to
//dw_from
281 ratiobits
= log2_int(ratio
)
290 address
= FlipFlop(30)
291 self
.submodules
+= address
292 self
.comb
+= address
.d
.eq(master
.adr
)
294 counter
= Counter(max=ratio
)
295 self
.submodules
+= counter
296 counter_offset
= Signal(max=ratio
)
297 counter_done
= Signal()
299 counter_offset
.eq(address
.q
),
300 counter_done
.eq((counter
.value
+ counter_offset
) == ratio
-1)
303 cached_data
= Signal(dw_to
)
304 cached_sel
= Signal(dw_to
//8)
306 end_of_burst
= Signal()
307 self
.comb
+= end_of_burst
.eq(~master
.cyc |
308 (master
.stb
& master
.cyc
& master
.ack
& ((master
.cti
== 7) | counter_done
)))
311 need_refill
= FlipFlop(reset
=1)
312 self
.submodules
+= need_refill
314 need_refill
.reset
.eq(end_of_burst
),
319 self
.submodules
.fsm
= fsm
= FSM()
322 If(master
.stb
& master
.cyc
,
336 If(master
.stb
& master
.cyc
,
352 slave
.dat_w
.eq(cached_data
),
353 slave
.sel
.eq(cached_sel
),
363 need_refill
.ce
.eq(1),
369 If(master
.stb
& master
.cyc
,
377 slave
.cti
.eq(7), # we are not able to generate bursts since up-converting
378 slave
.adr
.eq(address
.q
[ratiobits
:])
382 cached_datas
= [FlipFlop(dw_from
) for i
in range(ratio
)]
383 cached_sels
= [FlipFlop(dw_from
//8) for i
in range(ratio
)]
384 self
.submodules
+= cached_datas
, cached_sels
387 for i
in range(ratio
):
389 cases
[i
] = write_sel
.eq(1)
391 cached_sels
[i
].reset
.eq(counter
.reset
),
393 cached_datas
[i
].d
.eq(master
.dat_w
),
395 cached_datas
[i
].d
.eq(slave
.dat_r
[dw_from
*i
:dw_from
*(i
+1)])
397 cached_sels
[i
].d
.eq(master
.sel
),
398 If((write
& write_sel
) | refill
,
399 cached_datas
[i
].ce
.eq(1),
400 cached_sels
[i
].ce
.eq(1)
403 self
.comb
+= Case(counter
.value
+ counter_offset
, cases
)
406 for i
in range(ratio
):
407 cases
[i
] = master
.dat_r
.eq(cached_datas
[i
].q
)
408 self
.comb
+= Case(address
.q
[:ratiobits
], cases
)
411 cached_data
.eq(Cat([cached_data
.q
for cached_data
in cached_datas
])),
412 cached_sel
.eq(Cat([cached_sel
.q
for cached_sel
in cached_sels
]))
416 class Converter(Module
):
419 This module is a wrapper for DownConverter and UpConverter.
420 It should preferably be used rather than direct instantiations
421 of specific converters.
423 def __init__(self
, master
, slave
):
429 dw_from
= len(master
.dat_r
)
430 dw_to
= len(slave
.dat_r
)
432 downconverter
= DownConverter(master
, slave
)
433 self
.submodules
+= downconverter
434 elif dw_from
< dw_to
:
435 upconverter
= UpConverter(master
, slave
)
436 self
.submodules
+= upconverter
438 Record
.connect(master
, slave
)
444 This module is a write-back wishbone cache that can be used as a L2 cache.
445 Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
447 def __init__(self
, cachesize
, master
, slave
):
453 dw_from
= len(master
.dat_r
)
454 dw_to
= len(slave
.dat_r
)
455 if dw_to
> dw_from
and (dw_to
% dw_from
) != 0:
456 raise ValueError("Slave data width must be a multiple of {dw}".format(dw
=dw_from
))
457 if dw_to
< dw_from
and (dw_from
% dw_to
) != 0:
458 raise ValueError("Master data width must be a multiple of {dw}".format(dw
=dw_to
))
461 # TAG | LINE NUMBER | LINE OFFSET
462 offsetbits
= log2_int(max(dw_to
//dw_from
, 1))
463 addressbits
= len(slave
.adr
) + offsetbits
464 linebits
= log2_int(cachesize
) - offsetbits
465 tagbits
= addressbits
- linebits
466 wordbits
= log2_int(max(dw_from
//dw_to
, 1))
467 adr_offset
, adr_line
, adr_tag
= split(master
.adr
, offsetbits
, linebits
, tagbits
)
468 word
= Signal(wordbits
) if wordbits
else None
471 data_mem
= Memory(dw_to
*2**wordbits
, 2**linebits
)
472 data_port
= data_mem
.get_port(write_capable
=True, we_granularity
=8)
473 self
.specials
+= data_mem
, data_port
475 write_from_slave
= Signal()
476 if adr_offset
is None:
479 adr_offset_r
= Signal(offsetbits
)
480 self
.sync
+= adr_offset_r
.eq(adr_offset
)
483 data_port
.adr
.eq(adr_line
),
485 displacer(slave
.dat_r
, word
, data_port
.dat_w
),
486 displacer(Replicate(1, dw_to
//8), word
, data_port
.we
)
488 data_port
.dat_w
.eq(Replicate(master
.dat_w
, max(dw_to
//dw_from
, 1))),
489 If(master
.cyc
& master
.stb
& master
.we
& master
.ack
,
490 displacer(master
.sel
, adr_offset
, data_port
.we
, 2**offsetbits
, reverse
=True)
493 chooser(data_port
.dat_r
, word
, slave
.dat_w
),
494 slave
.sel
.eq(2**(dw_to
//8)-1),
495 chooser(data_port
.dat_r
, adr_offset_r
, master
.dat_r
, reverse
=True)
500 tag_layout
= [("tag", tagbits
), ("dirty", 1)]
501 tag_mem
= Memory(layout_len(tag_layout
), 2**linebits
)
502 tag_port
= tag_mem
.get_port(write_capable
=True)
503 self
.specials
+= tag_mem
, tag_port
504 tag_do
= Record(tag_layout
)
505 tag_di
= Record(tag_layout
)
507 tag_do
.raw_bits().eq(tag_port
.dat_r
),
508 tag_port
.dat_w
.eq(tag_di
.raw_bits())
512 tag_port
.adr
.eq(adr_line
),
513 tag_di
.tag
.eq(adr_tag
)
516 self
.comb
+= slave
.adr
.eq(Cat(word
, adr_line
, tag_do
.tag
))
518 self
.comb
+= slave
.adr
.eq(Cat(adr_line
, tag_do
.tag
))
520 # slave word computation, word_clr and word_inc will be simplified
521 # at synthesis when wordbits=0
532 def word_is_last(word
):
534 return word
== 2**wordbits
-1
539 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
541 If(master
.cyc
& master
.stb
,
542 NextState("TEST_HIT")
547 If(tag_do
.tag
== adr_tag
,
558 NextState("REFILL_WRTAG")
569 If(word_is_last(word
),
570 NextState("REFILL_WRTAG")
574 fsm
.act("REFILL_WRTAG",
575 # Write the tag first to set the slave address
585 write_from_slave
.eq(1),
587 If(word_is_last(word
),
588 NextState("TEST_HIT"),
597 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
601 bus_data_width
= len(self
.bus
.dat_r
)
602 if isinstance(mem_or_size
, Memory
):
603 assert(mem_or_size
.width
<= bus_data_width
)
604 self
.mem
= mem_or_size
606 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
607 if read_only
is None:
608 if hasattr(self
.mem
, "bus_read_only"):
609 read_only
= self
.mem
.bus_read_only
616 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8)
617 self
.specials
+= self
.mem
, port
618 # generate write enable signal
620 self
.comb
+= [port
.we
[i
].eq(self
.bus
.cyc
& self
.bus
.stb
& self
.bus
.we
& self
.bus
.sel
[i
])
624 port
.adr
.eq(self
.bus
.adr
[:len(port
.adr
)]),
625 self
.bus
.dat_r
.eq(port
.dat_r
)
628 self
.comb
+= port
.dat_w
.eq(self
.bus
.dat_w
),
632 If(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
, self
.bus
.ack
.eq(1))
636 class CSRBank(csr
.GenericBank
):
637 def __init__(self
, description
, bus
=None):
644 csr
.GenericBank
.__init
__(self
, description
, len(self
.bus
.dat_w
))
646 for i
, c
in enumerate(self
.simple_csrs
):
648 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
649 c
.re
.eq(self
.bus
.cyc
& self
.bus
.stb
& ~self
.bus
.ack
& self
.bus
.we
& \
650 (self
.bus
.adr
[:self
.decode_bits
] == i
))
653 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
655 Case(self
.bus
.adr
[:self
.decode_bits
], brcases
),
656 If(bus
.ack
, bus
.ack
.eq(0)).Elif(bus
.cyc
& bus
.stb
, bus
.ack
.eq(1))