1 from collections
import OrderedDict
4 __all__
= ["Pins", "DiffPairs", "Attrs", "Clock", "Subsignal", "Resource", "Connector"]
8 def __init__(self
, names
, *, dir="io", conn
=None):
9 if not isinstance(names
, str):
10 raise TypeError("Names must be a whitespace-separated string, not {!r}"
15 conn_name
, conn_number
= conn
16 if not (isinstance(conn_name
, str) and isinstance(conn_number
, int)):
17 raise TypeError("Connector must be None or a pair of string and integer, not {!r}"
19 names
= ["{}_{}:{}".format(conn_name
, conn_number
, name
) for name
in names
]
21 if dir not in ("i", "o", "io", "oe"):
22 raise TypeError("Direction must be one of \"i\", \"o\", \"oe\", or \"io\", not {!r}"
29 return len(self
.names
)
32 return iter(self
.names
)
34 def map_names(self
, mapping
, resource
):
36 for name
in self
.names
:
38 if name
not in mapping
:
39 raise NameError("Resource {!r} refers to nonexistent connector pin {}"
40 .format(resource
, name
))
42 mapped_names
.append(name
)
46 return "(pins {} {})".format(self
.dir, " ".join(self
.names
))
50 def __init__(self
, p
, n
, *, dir="io", conn
=None):
51 self
.p
= Pins(p
, dir=dir, conn
=conn
)
52 self
.n
= Pins(n
, dir=dir, conn
=conn
)
54 if len(self
.p
.names
) != len(self
.n
.names
):
55 raise TypeError("Positive and negative pins must have the same width, but {!r} "
57 .format(self
.p
, self
.n
))
62 return len(self
.p
.names
)
65 return zip(self
.p
.names
, self
.n
.names
)
68 return "(diffpairs {} (p {}) (n {}))".format(
69 self
.dir, " ".join(self
.p
.names
), " ".join(self
.n
.names
))
72 class Attrs(OrderedDict
):
73 def __init__(self
, **attrs
):
74 for attr_key
, attr_value
in attrs
.items():
75 if not isinstance(attr_value
, str):
76 raise TypeError("Attribute value must be a string, not {!r}"
79 super().__init
__(**attrs
)
82 return "(attrs {})".format(" ".join("{}={}".format(k
, v
)
83 for k
, v
in self
.items()))
87 def __init__(self
, frequency
):
88 if not isinstance(frequency
, (float, int)):
89 raise TypeError("Clock frequency must be a number")
91 self
.frequency
= float(frequency
)
95 return 1 / self
.frequency
98 return "(clock {})".format(self
.frequency
)
102 def __init__(self
, name
, *args
):
109 raise ValueError("Missing I/O constraints")
111 if isinstance(arg
, (Pins
, DiffPairs
)):
115 raise TypeError("Pins and DiffPairs are incompatible with other location or "
116 "subsignal constraints, but {!r} appears after {!r}"
117 .format(arg
, self
.ios
[-1]))
118 elif isinstance(arg
, Subsignal
):
119 if not self
.ios
or isinstance(self
.ios
[-1], Subsignal
):
122 raise TypeError("Subsignal is incompatible with location constraints, but "
123 "{!r} appears after {!r}"
124 .format(arg
, self
.ios
[-1]))
125 elif isinstance(arg
, Attrs
):
126 self
.attrs
.update(arg
)
127 elif isinstance(arg
, Clock
):
128 if self
.ios
and isinstance(self
.ios
[-1], (Pins
, DiffPairs
)):
129 if self
.clock
is None:
132 raise ValueError("Clock constraint can be applied only once")
134 raise TypeError("Clock constraint can only be applied to Pins or DiffPairs, "
136 .format(self
.ios
[-1]))
138 raise TypeError("Constraint must be one of Pins, DiffPairs, Subsignal, Attrs, "
142 def _content_repr(self
):
145 parts
.append(repr(io
))
146 if self
.clock
is not None:
147 parts
.append(repr(self
.clock
))
149 parts
.append(repr(self
.attrs
))
150 return " ".join(parts
)
153 return "(subsignal {} {})".format(self
.name
, self
._content
_repr
())
156 class Resource(Subsignal
):
157 def __init__(self
, name
, number
, *args
):
158 super().__init
__(name
, *args
)
163 return "(resource {} {} {})".format(self
.name
, self
.number
, self
._content
_repr
())
167 def __init__(self
, name
, number
, io
):
170 self
.mapping
= OrderedDict()
172 if isinstance(io
, dict):
173 for conn_pin
, plat_pin
in io
.items():
174 if not isinstance(conn_pin
, str):
175 raise TypeError("Connector pin name must be a string, not {!r}"
177 if not isinstance(plat_pin
, str):
178 raise TypeError("Platform pin name must be a string, not {!r}"
180 self
.mapping
[conn_pin
] = plat_pin
182 elif isinstance(io
, str):
183 for conn_pin
, plat_pin
in enumerate(io
.split(), start
=1):
186 self
.mapping
[str(conn_pin
)] = plat_pin
189 raise TypeError("Connector I/Os must be a dictionary or a string, not {!r}"
193 return "(connector {} {} {})".format(self
.name
, self
.number
,
194 " ".join("{}=>{}".format(conn
, plat
)
195 for conn
, plat
in self
.mapping
.items()))
198 return len(self
.mapping
)
201 for conn_pin
, plat_pin
in self
.mapping
.items():
202 yield "{}_{}:{}".format(self
.name
, self
.number
, conn_pin
), plat_pin