build: add DSL for defining platform resources.
[nmigen.git] / nmigen / build / dsl.py
1 __all__ = ["Pins", "Subsignal", "DiffPairs", "Resource"]
2
3
4 class Pins:
5 def __init__(self, names, dir="io"):
6 if not isinstance(names, str):
7 raise TypeError("Names must be a whitespace-separated string, not {!r}"
8 .format(names))
9 self.names = names.split()
10
11 if dir not in ("i", "o", "io"):
12 raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not {!r}"
13 .format(dir))
14 self.dir = dir
15
16 def __repr__(self):
17 return "(pins {} {})".format(" ".join(self.names), self.dir)
18
19
20 class DiffPairs:
21 def __init__(self, p, n, dir="io"):
22 self.p = Pins(p, dir=dir)
23 self.n = Pins(n, dir=dir)
24
25 if len(self.p.names) != len(self.n.names):
26 raise TypeError("Positive and negative pins must have the same width, but {!r} "
27 "and {!r} do not"
28 .format(self.p, self.n))
29
30 self.dir = self.p.dir
31
32 def __repr__(self):
33 return "(diffpairs {} {})".format(self.p, self.n)
34
35
36 class Subsignal:
37 def __init__(self, name, *io, extras=()):
38 self.name = name
39
40 if not io:
41 raise TypeError("Missing I/O constraints")
42 for c in io:
43 if not isinstance(c, (Pins, DiffPairs, Subsignal)):
44 raise TypeError("I/O constraint must be one of Pins, DiffPairs or Subsignal, "
45 "not {!r}"
46 .format(c))
47 if isinstance(io[0], (Pins, DiffPairs)) and len(io) > 1:
48 raise TypeError("Pins and DiffPairs cannot be followed by more I/O constraints, but "
49 "{!r} is followed by {!r}"
50 .format(io[0], io[1]))
51 if isinstance(io[0], Subsignal):
52 for c in io[1:]:
53 if not isinstance(c, Subsignal):
54 raise TypeError("A Subsignal can only be followed by more Subsignals, but "
55 "{!r} is followed by {!r}"
56 .format(io[0], c))
57 self.io = io
58
59 for c in extras:
60 if not isinstance(c, str):
61 raise TypeError("Extra constraint must be a string, not {!r}".format(c))
62 self.extras = list(extras)
63
64 if isinstance(self.io[0], Subsignal):
65 for sub in self.io:
66 sub.extras += self.extras
67
68 def __repr__(self):
69 return "(subsignal {} {} {})".format(self.name,
70 " ".join(map(repr, self.io)),
71 " ".join(self.extras))
72
73
74 class Resource(Subsignal):
75 def __init__(self, name, number, *io, extras=()):
76 self.number = number
77 super().__init__(name, *io, extras=extras)
78
79 def __repr__(self):
80 return "(resource {} {} {} {})".format(self.name, self.number,
81 " ".join(map(repr, self.io)),
82 " ".join(self.extras))