add fabric compatibility mode
[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 from nmigen.utils import log2_int
5
6
7 __all__ = ["Cycle", "make_wb_layout", "WishboneArbiter"]
8
9
10 class Cycle:
11 CLASSIC = 0
12 CONSTANT = 1
13 INCREMENT = 2
14 END = 7
15
16
17 def make_wb_layout(spec, cti=True):
18 addr_wid, mask_wid, data_wid = spec.addr_wid, spec.mask_wid, spec.reg_wid
19 adr_lsbs = log2_int(mask_wid) # LSBs of addr covered by mask
20 badwid = spec.addr_wid-adr_lsbs # MSBs (not covered by mask)
21 # test if microwatt compatibility is to be enabled
22 microwatt_compat = (hasattr(spec, "microwatt_compat") and
23 (spec.microwatt_compat == True))
24 # test if fabric compatibility is to be enabled
25 fabric_compat = (hasattr(spec, "fabric_compat") and
26 (spec.fabric_compat == True))
27
28 res = [
29 ("adr", badwid , DIR_FANOUT),
30 ("dat_w", data_wid, DIR_FANOUT),
31 ("dat_r", data_wid, DIR_FANIN),
32 ("sel", mask_wid, DIR_FANOUT),
33 ("cyc", 1, DIR_FANOUT),
34 ("stb", 1, DIR_FANOUT),
35 ("ack", 1, DIR_FANIN),
36 ("we", 1, DIR_FANOUT),
37 ("err", 1, DIR_FANIN)
38 ]
39 # microwatt needs a stall signal (operates in pipeline mode)
40 if microwatt_compat or fabric_compat:
41 res.append(("stall", 1, DIR_FANIN))
42 if not cti:
43 return res
44 return res + [
45 ("cti", 3, DIR_FANOUT),
46 ("bte", 2, DIR_FANOUT),
47 ]
48
49
50 class WishboneArbiter(Elaboratable):
51 def __init__(self, pspec):
52 self.bus = Record(make_wb_layout(pspec))
53 self._port_map = dict()
54
55 def port(self, priority):
56 if not isinstance(priority, int) or priority < 0:
57 raise TypeError("Priority must be a non-negative "\
58 "integer, not '{!r}'" .format(priority))
59 if priority in self._port_map:
60 raise ValueError("Conflicting priority: '{!r}'".format(priority))
61 port = self._port_map[priority] = Record.like(self.bus)
62 return port
63
64 def elaborate(self, platform):
65 m = Module()
66
67 ports = [port for priority, port in sorted(self._port_map.items())]
68
69 for port in ports:
70 m.d.comb += port.dat_r.eq(self.bus.dat_r)
71
72 bus_pe = m.submodules.bus_pe = PriorityEncoder(len(ports))
73 with m.If(~self.bus.cyc):
74 for j, port in enumerate(ports):
75 m.d.sync += bus_pe.i[j].eq(port.cyc)
76
77 source = Array(ports)[bus_pe.o]
78 m.d.comb += [
79 self.bus.adr.eq(source.adr),
80 self.bus.dat_w.eq(source.dat_w),
81 self.bus.sel.eq(source.sel),
82 self.bus.cyc.eq(source.cyc),
83 self.bus.stb.eq(source.stb),
84 self.bus.we.eq(source.we),
85 self.bus.cti.eq(source.cti),
86 self.bus.bte.eq(source.bte),
87 source.ack.eq(self.bus.ack),
88 source.err.eq(self.bus.err)
89 ]
90
91 return m