start putting LDSTSplitter together
[soc.git] / src / soc / minerva / wishbone.py
1 from nmigen import Array, Elaboratable, Module, Record, Signal
2 from nmigen.hdl.rec import DIR_FANIN, DIR_FANOUT, DIR_NONE
3 from nmigen.lib.coding import PriorityEncoder
4
5
6 __all__ = ["Cycle", "wishbone_layout", "WishboneArbiter"]
7
8
9 class Cycle:
10 CLASSIC = 0
11 CONSTANT = 1
12 INCREMENT = 2
13 END = 7
14
15
16 wishbone_layout = [
17 ("adr", 30, DIR_FANOUT),
18 ("dat_w", 32, DIR_FANOUT),
19 ("dat_r", 32, DIR_FANIN),
20 ("sel", 4, DIR_FANOUT),
21 ("cyc", 1, DIR_FANOUT),
22 ("stb", 1, DIR_FANOUT),
23 ("ack", 1, DIR_FANIN),
24 ("we", 1, DIR_FANOUT),
25 ("cti", 3, DIR_FANOUT),
26 ("bte", 2, DIR_FANOUT),
27 ("err", 1, DIR_FANIN)
28 ]
29
30
31 class WishboneArbiter(Elaboratable):
32 def __init__(self):
33 self.bus = Record(wishbone_layout)
34 self._port_map = dict()
35
36 def port(self, priority):
37 if not isinstance(priority, int) or priority < 0:
38 raise TypeError("Priority must be a non-negative integer, not '{!r}'"
39 .format(priority))
40 if priority in self._port_map:
41 raise ValueError("Conflicting priority: '{!r}'".format(priority))
42 port = self._port_map[priority] = Record.like(self.bus)
43 return port
44
45 def elaborate(self, platform):
46 m = Module()
47
48 ports = [port for priority, port in sorted(self._port_map.items())]
49
50 for port in ports:
51 m.d.comb += port.dat_r.eq(self.bus.dat_r)
52
53 bus_pe = m.submodules.bus_pe = PriorityEncoder(len(ports))
54 with m.If(~self.bus.cyc):
55 for j, port in enumerate(ports):
56 m.d.sync += bus_pe.i[j].eq(port.cyc)
57
58 source = Array(ports)[bus_pe.o]
59 m.d.comb += [
60 self.bus.adr.eq(source.adr),
61 self.bus.dat_w.eq(source.dat_w),
62 self.bus.sel.eq(source.sel),
63 self.bus.cyc.eq(source.cyc),
64 self.bus.stb.eq(source.stb),
65 self.bus.we.eq(source.we),
66 self.bus.cti.eq(source.cti),
67 self.bus.bte.eq(source.bte),
68 source.ack.eq(self.bus.ack),
69 source.err.eq(self.bus.err)
70 ]
71
72 return m