import migen in litex/gen
[litex.git] / litex / soc / misoc / interconnect / wishbone.py
1 from functools import reduce
2 from operator import or_
3
4 from migen import *
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
9
10 from misoc.interconnect import csr
11
12 # TODO: rewrite without FlipFlop and Counter
13
14
15 _layout = [
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)
27 ]
28
29
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))
35
36 def _do_transaction(self):
37 yield self.cyc.eq(1)
38 yield self.stb.eq(1)
39 yield
40 while not (yield self.ack):
41 yield
42 yield self.cyc.eq(0)
43 yield self.stb.eq(0)
44
45 def write(self, adr, dat, sel=None):
46 if sel is 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)
51 yield self.we.eq(1)
52 yield from self._do_transaction()
53
54 def read(self, adr):
55 yield self.adr.eq(adr)
56 yield self.we.eq(0)
57 yield from self._do_transaction()
58 return (yield self.dat_r)
59
60
61 class InterconnectPointToPoint(Module):
62 def __init__(self, master, slave):
63 self.comb += master.connect(slave)
64
65
66 class Arbiter(Module):
67 def __init__(self, masters, target):
68 self.submodules.rr = roundrobin.RoundRobin(len(masters))
69
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])
75
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))
84 else:
85 self.comb += dest.eq(source)
86
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))
90
91
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):
100 ns = len(slaves)
101 slave_sel = Signal(ns)
102 slave_sel_r = Signal(ns)
103
104 # decode slave addresses
105 self.comb += [slave_sel[i].eq(fun(master.adr))
106 for i, (fun, bus) in enumerate(slaves)]
107 if register:
108 self.sync += slave_sel_r.eq(slave_sel)
109 else:
110 self.comb += slave_sel_r.eq(slave_sel)
111
112 # connect master->slaves signals except cyc
113 for slave in slaves:
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))
117
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)]
121
122 # generate master ack (resp. err) by ORing all slave acks (resp. errs)
123 self.comb += [
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]))
126 ]
127
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))
131
132
133 class InterconnectShared(Module):
134 def __init__(self, masters, slaves, register=False):
135 shared = Interface()
136 self.submodules += Arbiter(masters, shared)
137 self.submodules += Decoder(shared, slaves, register)
138
139
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)
151
152
153 class DownConverter(Module):
154 """DownConverter
155
156 This module splits Wishbone accesses from a master interface to a smaller
157 slave interface.
158
159 Writes:
160 Writes from master are splitted N writes to the slave. Access is acked when the last
161 access is acked by the slave.
162
163 Reads:
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.
166
167 TODO:
168 Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
169 """
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
174
175 # # #
176
177 read = Signal()
178 write = Signal()
179
180 counter = Counter(max=ratio)
181 self.submodules += counter
182 counter_done = Signal()
183 self.comb += counter_done.eq(counter.value == ratio-1)
184
185 # Main FSM
186 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
187 fsm.act("IDLE",
188 counter.reset.eq(1),
189 If(master.stb & master.cyc,
190 If(master.we,
191 NextState("WRITE")
192 ).Else(
193 NextState("READ")
194 )
195 )
196 )
197 fsm.act("WRITE",
198 write.eq(1),
199 slave.we.eq(1),
200 slave.cyc.eq(1),
201 If(master.stb & master.cyc,
202 slave.stb.eq(1),
203 If(slave.ack,
204 counter.ce.eq(1),
205 If(counter_done,
206 master.ack.eq(1),
207 NextState("IDLE")
208 )
209 )
210 ).Elif(~master.cyc,
211 NextState("IDLE")
212 )
213 )
214 fsm.act("READ",
215 read.eq(1),
216 slave.cyc.eq(1),
217 If(master.stb & master.cyc,
218 slave.stb.eq(1),
219 If(slave.ack,
220 counter.ce.eq(1),
221 If(counter_done,
222 master.ack.eq(1),
223 NextState("IDLE")
224 )
225 )
226 ).Elif(~master.cyc,
227 NextState("IDLE")
228 )
229 )
230
231 # Address
232 self.comb += [
233 If(counter_done,
234 slave.cti.eq(7) # indicate end of burst
235 ).Else(
236 slave.cti.eq(2)
237 ),
238 slave.adr.eq(Cat(counter.value, master.adr))
239 ]
240
241 # Datapath
242 cases = {}
243 for i in range(ratio):
244 cases[i] = [
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])
247 ]
248 self.comb += Case(counter.value, cases)
249
250
251 cached_data = Signal(dw_from)
252 self.comb += master.dat_r.eq(Cat(cached_data[dw_to:], slave.dat_r))
253 self.sync += \
254 If(read & counter.ce,
255 cached_data.eq(master.dat_r)
256 )
257
258
259 class UpConverter(Module):
260 """UpConverter
261
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.
264
265 Writes:
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
268 addressing.
269
270 Reads:
271 Cache is refilled only at the beginning of each burst, the subsequent
272 reads of a burst use the cached data.
273
274 TODO:
275 Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
276 """
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)
282
283 # # #
284
285 write = Signal()
286 evict = Signal()
287 refill = Signal()
288 read = Signal()
289
290 address = FlipFlop(30)
291 self.submodules += address
292 self.comb += address.d.eq(master.adr)
293
294 counter = Counter(max=ratio)
295 self.submodules += counter
296 counter_offset = Signal(max=ratio)
297 counter_done = Signal()
298 self.comb += [
299 counter_offset.eq(address.q),
300 counter_done.eq((counter.value + counter_offset) == ratio-1)
301 ]
302
303 cached_data = Signal(dw_to)
304 cached_sel = Signal(dw_to//8)
305
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)))
309
310
311 need_refill = FlipFlop(reset=1)
312 self.submodules += need_refill
313 self.comb += [
314 need_refill.reset.eq(end_of_burst),
315 need_refill.d.eq(0)
316 ]
317
318 # Main FSM
319 self.submodules.fsm = fsm = FSM()
320 fsm.act("IDLE",
321 counter.reset.eq(1),
322 If(master.stb & master.cyc,
323 address.ce.eq(1),
324 If(master.we,
325 NextState("WRITE")
326 ).Else(
327 If(need_refill.q,
328 NextState("REFILL")
329 ).Else(
330 NextState("READ")
331 )
332 )
333 )
334 )
335 fsm.act("WRITE",
336 If(master.stb & master.cyc,
337 write.eq(1),
338 counter.ce.eq(1),
339 master.ack.eq(1),
340 If(counter_done,
341 NextState("EVICT")
342 )
343 ).Elif(~master.cyc,
344 NextState("EVICT")
345 )
346 )
347 fsm.act("EVICT",
348 evict.eq(1),
349 slave.stb.eq(1),
350 slave.we.eq(1),
351 slave.cyc.eq(1),
352 slave.dat_w.eq(cached_data),
353 slave.sel.eq(cached_sel),
354 If(slave.ack,
355 NextState("IDLE")
356 )
357 )
358 fsm.act("REFILL",
359 refill.eq(1),
360 slave.stb.eq(1),
361 slave.cyc.eq(1),
362 If(slave.ack,
363 need_refill.ce.eq(1),
364 NextState("READ")
365 )
366 )
367 fsm.act("READ",
368 read.eq(1),
369 If(master.stb & master.cyc,
370 master.ack.eq(1)
371 ),
372 NextState("IDLE")
373 )
374
375 # Address
376 self.comb += [
377 slave.cti.eq(7), # we are not able to generate bursts since up-converting
378 slave.adr.eq(address.q[ratiobits:])
379 ]
380
381 # Datapath
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
385
386 cases = {}
387 for i in range(ratio):
388 write_sel = Signal()
389 cases[i] = write_sel.eq(1)
390 self.comb += [
391 cached_sels[i].reset.eq(counter.reset),
392 If(write,
393 cached_datas[i].d.eq(master.dat_w),
394 ).Else(
395 cached_datas[i].d.eq(slave.dat_r[dw_from*i:dw_from*(i+1)])
396 ),
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)
401 )
402 ]
403 self.comb += Case(counter.value + counter_offset, cases)
404
405 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)
409
410 self.comb += [
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]))
413 ]
414
415
416 class Converter(Module):
417 """Converter
418
419 This module is a wrapper for DownConverter and UpConverter.
420 It should preferably be used rather than direct instantiations
421 of specific converters.
422 """
423 def __init__(self, master, slave):
424 self.master = master
425 self.slave = slave
426
427 # # #
428
429 dw_from = len(master.dat_r)
430 dw_to = len(slave.dat_r)
431 if dw_from > dw_to:
432 downconverter = DownConverter(master, slave)
433 self.submodules += downconverter
434 elif dw_from < dw_to:
435 upconverter = UpConverter(master, slave)
436 self.submodules += upconverter
437 else:
438 Record.connect(master, slave)
439
440
441 class Cache(Module):
442 """Cache
443
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
446 """
447 def __init__(self, cachesize, master, slave):
448 self.master = master
449 self.slave = slave
450
451 ###
452
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))
459
460 # Split address:
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
469
470 # Data memory
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
474
475 write_from_slave = Signal()
476 if adr_offset is None:
477 adr_offset_r = None
478 else:
479 adr_offset_r = Signal(offsetbits)
480 self.sync += adr_offset_r.eq(adr_offset)
481
482 self.comb += [
483 data_port.adr.eq(adr_line),
484 If(write_from_slave,
485 displacer(slave.dat_r, word, data_port.dat_w),
486 displacer(Replicate(1, dw_to//8), word, data_port.we)
487 ).Else(
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)
491 )
492 ),
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)
496 ]
497
498
499 # Tag memory
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)
506 self.comb += [
507 tag_do.raw_bits().eq(tag_port.dat_r),
508 tag_port.dat_w.eq(tag_di.raw_bits())
509 ]
510
511 self.comb += [
512 tag_port.adr.eq(adr_line),
513 tag_di.tag.eq(adr_tag)
514 ]
515 if word is not None:
516 self.comb += slave.adr.eq(Cat(word, adr_line, tag_do.tag))
517 else:
518 self.comb += slave.adr.eq(Cat(adr_line, tag_do.tag))
519
520 # slave word computation, word_clr and word_inc will be simplified
521 # at synthesis when wordbits=0
522 word_clr = Signal()
523 word_inc = Signal()
524 if word is not None:
525 self.sync += \
526 If(word_clr,
527 word.eq(0),
528 ).Elif(word_inc,
529 word.eq(word+1)
530 )
531
532 def word_is_last(word):
533 if word is not None:
534 return word == 2**wordbits-1
535 else:
536 return 1
537
538 # Control FSM
539 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
540 fsm.act("IDLE",
541 If(master.cyc & master.stb,
542 NextState("TEST_HIT")
543 )
544 )
545 fsm.act("TEST_HIT",
546 word_clr.eq(1),
547 If(tag_do.tag == adr_tag,
548 master.ack.eq(1),
549 If(master.we,
550 tag_di.dirty.eq(1),
551 tag_port.we.eq(1)
552 ),
553 NextState("IDLE")
554 ).Else(
555 If(tag_do.dirty,
556 NextState("EVICT")
557 ).Else(
558 NextState("REFILL_WRTAG")
559 )
560 )
561 )
562
563 fsm.act("EVICT",
564 slave.stb.eq(1),
565 slave.cyc.eq(1),
566 slave.we.eq(1),
567 If(slave.ack,
568 word_inc.eq(1),
569 If(word_is_last(word),
570 NextState("REFILL_WRTAG")
571 )
572 )
573 )
574 fsm.act("REFILL_WRTAG",
575 # Write the tag first to set the slave address
576 tag_port.we.eq(1),
577 word_clr.eq(1),
578 NextState("REFILL")
579 )
580 fsm.act("REFILL",
581 slave.stb.eq(1),
582 slave.cyc.eq(1),
583 slave.we.eq(0),
584 If(slave.ack,
585 write_from_slave.eq(1),
586 word_inc.eq(1),
587 If(word_is_last(word),
588 NextState("TEST_HIT"),
589 ).Else(
590 NextState("REFILL")
591 )
592 )
593 )
594
595
596 class SRAM(Module):
597 def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
598 if bus is None:
599 bus = Interface()
600 self.bus = bus
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
605 else:
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
610 else:
611 read_only = False
612
613 ###
614
615 # memory
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
619 if not read_only:
620 self.comb += [port.we[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i])
621 for i in range(4)]
622 # address and data
623 self.comb += [
624 port.adr.eq(self.bus.adr[:len(port.adr)]),
625 self.bus.dat_r.eq(port.dat_r)
626 ]
627 if not read_only:
628 self.comb += port.dat_w.eq(self.bus.dat_w),
629 # generate ack
630 self.sync += [
631 self.bus.ack.eq(0),
632 If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1))
633 ]
634
635
636 class CSRBank(csr.GenericBank):
637 def __init__(self, description, bus=None):
638 if bus is None:
639 bus = Interface()
640 self.bus = bus
641
642 ###
643
644 csr.GenericBank.__init__(self, description, len(self.bus.dat_w))
645
646 for i, c in enumerate(self.simple_csrs):
647 self.comb += [
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))
651 ]
652
653 brcases = dict((i, self.bus.dat_r.eq(c.w)) for i, c in enumerate(self.simple_csrs))
654 self.sync += [
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))
657 ]