build.dsl: replace extras= with Attrs().
This change proved more tricky than expected due to downstream dependencies, so it also includes some secondary refactoring.
This commit is contained in:
		
							parent
							
								
									c52cd72d3e
								
							
						
					
					
						commit
						ab3f103e5a
					
				|  | @ -1,3 +1,3 @@ | |||
| from .dsl import Pins, DiffPairs, Subsignal, Resource, Connector | ||||
| from .res import ConstraintError | ||||
| from .dsl import Pins, DiffPairs, Attrs, Subsignal, Resource, Connector | ||||
| from .res import ResourceError | ||||
| from .plat import Platform, TemplatedPlatform | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| from collections import OrderedDict | ||||
| 
 | ||||
| 
 | ||||
| __all__ = ["Pins", "DiffPairs", "Subsignal", "Resource", "Connector"] | ||||
| __all__ = ["Pins", "DiffPairs", "Attrs", "Subsignal", "Resource", "Connector"] | ||||
| 
 | ||||
| 
 | ||||
| class Pins: | ||||
|  | @ -32,13 +32,15 @@ class Pins: | |||
|         return iter(self.names) | ||||
| 
 | ||||
|     def map_names(self, mapping, resource): | ||||
|         mapped_names = [] | ||||
|         for name in self.names: | ||||
|             while ":" in name: | ||||
|                 if name not in mapping: | ||||
|                     raise NameError("Resource {!r} refers to nonexistent connector pin {}" | ||||
|                                     .format(resource, name)) | ||||
|                 name = mapping[name] | ||||
|             yield name | ||||
|             mapped_names.append(name) | ||||
|         return mapped_names | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "(pins {} {})".format(self.dir, " ".join(self.names)) | ||||
|  | @ -67,65 +69,66 @@ class DiffPairs: | |||
|             self.dir, " ".join(self.p.names), " ".join(self.n.names)) | ||||
| 
 | ||||
| 
 | ||||
| class Attrs(OrderedDict): | ||||
|     def __init__(self, **attrs): | ||||
|         for attr_key, attr_value in attrs.items(): | ||||
|             if not isinstance(attr_value, str): | ||||
|                 raise TypeError("Attribute value must be a string, not {!r}" | ||||
|                                 .format(attr_value)) | ||||
| 
 | ||||
|         super().__init__(**attrs) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "(attrs {})".format(" ".join("{}={}".format(k, v) | ||||
|                                     for k, v in self.items())) | ||||
| 
 | ||||
| 
 | ||||
| class Subsignal: | ||||
|     def __init__(self, name, *io, extras=None): | ||||
|         self.name = name | ||||
|     def __init__(self, name, *args): | ||||
|         self.name  = name | ||||
|         self.ios   = [] | ||||
|         self.attrs = Attrs() | ||||
| 
 | ||||
|         if not io: | ||||
|             raise TypeError("Missing I/O constraints") | ||||
|         for c in io: | ||||
|             if not isinstance(c, (Pins, DiffPairs, Subsignal)): | ||||
|                 raise TypeError("I/O constraint must be one of Pins, DiffPairs or Subsignal, " | ||||
|                                 "not {!r}" | ||||
|                                 .format(c)) | ||||
|         if isinstance(io[0], (Pins, DiffPairs)) and len(io) > 1: | ||||
|             raise TypeError("Pins and DiffPairs cannot be followed by more I/O constraints, but " | ||||
|                             "{!r} is followed by {!r}" | ||||
|                             .format(io[0], io[1])) | ||||
|         if isinstance(io[0], Subsignal): | ||||
|             for c in io[1:]: | ||||
|                 if not isinstance(c, Subsignal): | ||||
|                     raise TypeError("A Subsignal can only be followed by more Subsignals, but " | ||||
|                                     "{!r} is followed by {!r}" | ||||
|                                     .format(io[0], c)) | ||||
|         self.io     = io | ||||
|         self.extras = {} | ||||
| 
 | ||||
|         if extras is not None: | ||||
|             if not isinstance(extras, dict): | ||||
|                 raise TypeError("Extra constraints must be a dict, not {!r}" | ||||
|                                 .format(extras)) | ||||
|             for extra_key, extra_value in extras.items(): | ||||
|                 if not isinstance(extra_key, str): | ||||
|                     raise TypeError("Extra constraint key must be a string, not {!r}" | ||||
|                                     .format(extra_key)) | ||||
|                 if not isinstance(extra_value, str): | ||||
|                     raise TypeError("Extra constraint value must be a string, not {!r}" | ||||
|                                     .format(extra_value)) | ||||
|                 self.extras[extra_key] = extra_value | ||||
| 
 | ||||
|         if isinstance(self.io[0], Subsignal): | ||||
|             for sub in self.io: | ||||
|                 sub.extras.update(self.extras) | ||||
|         if not args: | ||||
|             raise ValueError("Missing I/O constraints") | ||||
|         for arg in args: | ||||
|             if isinstance(arg, (Pins, DiffPairs)): | ||||
|                 if not self.ios: | ||||
|                     self.ios.append(arg) | ||||
|                 else: | ||||
|                     raise TypeError("Pins and DiffPairs are incompatible with other location or " | ||||
|                                     "subsignal constraints, but {!r} appears after {!r}" | ||||
|                                     .format(arg, self.ios[-1])) | ||||
|             elif isinstance(arg, Subsignal): | ||||
|                 if not self.ios or isinstance(self.ios[-1], Subsignal): | ||||
|                     self.ios.append(arg) | ||||
|                 else: | ||||
|                     raise TypeError("Subsignal is incompatible with location constraints, but " | ||||
|                                     "{!r} appears after {!r}" | ||||
|                                     .format(arg, self.ios[-1])) | ||||
|             elif isinstance(arg, Attrs): | ||||
|                 self.attrs.update(arg) | ||||
|             else: | ||||
|                 raise TypeError("I/O constraint must be one of Pins, DiffPairs, Subsignal, " | ||||
|                                 "or Attrs, not {!r}" | ||||
|                                 .format(arg)) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "(subsignal {} {} {})".format(self.name, | ||||
|                                              " ".join(map(repr, self.io)), | ||||
|                                              " ".join("{}={}".format(k, v) | ||||
|                                                       for k, v in self.extras.items())) | ||||
|                                              " ".join(map(repr, self.ios)), | ||||
|                                              repr(self.attrs)) | ||||
| 
 | ||||
| 
 | ||||
| class Resource(Subsignal): | ||||
|     def __init__(self, name, number, *io, extras=None): | ||||
|         super().__init__(name, *io, extras=extras) | ||||
|     def __init__(self, name, number, *args): | ||||
|         super().__init__(name, *args) | ||||
| 
 | ||||
|         self.number = number | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "(resource {} {} {} {})".format(self.name, self.number, | ||||
|                                                " ".join(map(repr, self.io)), | ||||
|                                                " ".join("{}={}".format(k, v) | ||||
|                                                         for k, v in self.extras.items())) | ||||
|                                                " ".join(map(repr, self.ios)), | ||||
|                                                repr(self.attrs)) | ||||
| 
 | ||||
| 
 | ||||
| class Connector: | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ from .run import * | |||
| __all__ = ["Platform", "TemplatedPlatform"] | ||||
| 
 | ||||
| 
 | ||||
| class Platform(ConstraintManager, metaclass=ABCMeta): | ||||
| class Platform(ResourceManager, metaclass=ABCMeta): | ||||
|     resources  = abstractproperty() | ||||
|     connectors = abstractproperty() | ||||
|     clocks     = abstractproperty() | ||||
|  | @ -67,25 +67,25 @@ class Platform(ConstraintManager, metaclass=ABCMeta): | |||
|                 pin_fragment.flatten = True | ||||
|             fragment.add_subfragment(pin_fragment, name="pin_{}".format(pin.name)) | ||||
| 
 | ||||
|         for pin, port, extras in self.iter_single_ended_pins(): | ||||
|         for pin, port, attrs in self.iter_single_ended_pins(): | ||||
|             if pin.dir == "i": | ||||
|                 add_pin_fragment(pin, self.get_input(pin, port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_input(pin, port, attrs)) | ||||
|             if pin.dir == "o": | ||||
|                 add_pin_fragment(pin, self.get_output(pin, port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_output(pin, port, attrs)) | ||||
|             if pin.dir == "oe": | ||||
|                 add_pin_fragment(pin, self.get_tristate(pin, port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_tristate(pin, port, attrs)) | ||||
|             if pin.dir == "io": | ||||
|                 add_pin_fragment(pin, self.get_input_output(pin, port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_input_output(pin, port, attrs)) | ||||
| 
 | ||||
|         for pin, p_port, n_port, extras in self.iter_differential_pins(): | ||||
|         for pin, p_port, n_port, attrs in self.iter_differential_pins(): | ||||
|             if pin.dir == "i": | ||||
|                 add_pin_fragment(pin, self.get_diff_input(pin, p_port, n_port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_diff_input(pin, p_port, n_port, attrs)) | ||||
|             if pin.dir == "o": | ||||
|                 add_pin_fragment(pin, self.get_diff_output(pin, p_port, n_port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_diff_output(pin, p_port, n_port, attrs)) | ||||
|             if pin.dir == "oe": | ||||
|                 add_pin_fragment(pin, self.get_diff_tristate(pin, p_port, n_port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_diff_tristate(pin, p_port, n_port, attrs)) | ||||
|             if pin.dir == "io": | ||||
|                 add_pin_fragment(pin, self.get_diff_input_output(pin, p_port, n_port, extras)) | ||||
|                 add_pin_fragment(pin, self.get_diff_input_output(pin, p_port, n_port, attrs)) | ||||
| 
 | ||||
|         return self.toolchain_prepare(fragment, name, **kwargs) | ||||
| 
 | ||||
|  | @ -104,7 +104,7 @@ class Platform(ConstraintManager, metaclass=ABCMeta): | |||
|         raise NotImplementedError("Platform {} does not support programming" | ||||
|                                   .format(self.__class__.__name__)) | ||||
| 
 | ||||
|     def _check_feature(self, feature, pin, extras, valid_xdrs, valid_extras): | ||||
|     def _check_feature(self, feature, pin, attrs, valid_xdrs, valid_attrs): | ||||
|         if not valid_xdrs: | ||||
|             raise NotImplementedError("Platform {} does not support {}" | ||||
|                                       .format(self.__class__.__name__, feature)) | ||||
|  | @ -112,29 +112,29 @@ class Platform(ConstraintManager, metaclass=ABCMeta): | |||
|             raise NotImplementedError("Platform {} does not support {} for XDR {}" | ||||
|                                       .format(self.__class__.__name__, feature, pin.xdr)) | ||||
| 
 | ||||
|         if not valid_extras and extras: | ||||
|             raise NotImplementedError("Platform {} does not support extras for {}" | ||||
|         if not valid_attrs and attrs: | ||||
|             raise NotImplementedError("Platform {} does not support attributes for {}" | ||||
|                                       .format(self.__class__.__name__, feature)) | ||||
| 
 | ||||
|     def get_input(self, pin, port, extras): | ||||
|         self._check_feature("single-ended input", pin, extras, | ||||
|                             valid_xdrs=(0,), valid_extras=None) | ||||
|     def get_input(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended input", pin, attrs, | ||||
|                             valid_xdrs=(0,), valid_attrs=None) | ||||
| 
 | ||||
|         m = Module() | ||||
|         m.d.comb += pin.i.eq(port) | ||||
|         return m | ||||
| 
 | ||||
|     def get_output(self, pin, port, extras): | ||||
|         self._check_feature("single-ended output", pin, extras, | ||||
|                             valid_xdrs=(0,), valid_extras=None) | ||||
|     def get_output(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended output", pin, attrs, | ||||
|                             valid_xdrs=(0,), valid_attrs=None) | ||||
| 
 | ||||
|         m = Module() | ||||
|         m.d.comb += port.eq(pin.o) | ||||
|         return m | ||||
| 
 | ||||
|     def get_tristate(self, pin, port, extras): | ||||
|         self._check_feature("single-ended tristate", pin, extras, | ||||
|                             valid_xdrs=(0,), valid_extras=None) | ||||
|     def get_tristate(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended tristate", pin, attrs, | ||||
|                             valid_xdrs=(0,), valid_attrs=None) | ||||
| 
 | ||||
|         m = Module() | ||||
|         m.submodules += Instance("$tribuf", | ||||
|  | @ -145,9 +145,9 @@ class Platform(ConstraintManager, metaclass=ABCMeta): | |||
|         ) | ||||
|         return m | ||||
| 
 | ||||
|     def get_input_output(self, pin, port, extras): | ||||
|         self._check_feature("single-ended input/output", pin, extras, | ||||
|                             valid_xdrs=(0,), valid_extras=None) | ||||
|     def get_input_output(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended input/output", pin, attrs, | ||||
|                             valid_xdrs=(0,), valid_attrs=None) | ||||
| 
 | ||||
|         m = Module() | ||||
|         m.submodules += Instance("$tribuf", | ||||
|  | @ -159,21 +159,21 @@ class Platform(ConstraintManager, metaclass=ABCMeta): | |||
|         m.d.comb += pin.i.eq(port) | ||||
|         return m | ||||
| 
 | ||||
|     def get_diff_input(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential input", pin, extras, | ||||
|                             valid_xdrs=(), valid_extras=None) | ||||
|     def get_diff_input(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential input", pin, attrs, | ||||
|                             valid_xdrs=(), valid_attrs=None) | ||||
| 
 | ||||
|     def get_diff_output(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential output", pin, extras, | ||||
|                             valid_xdrs=(), valid_extras=None) | ||||
|     def get_diff_output(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential output", pin, attrs, | ||||
|                             valid_xdrs=(), valid_attrs=None) | ||||
| 
 | ||||
|     def get_diff_tristate(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential tristate", pin, extras, | ||||
|                             valid_xdrs=(), valid_extras=None) | ||||
|     def get_diff_tristate(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential tristate", pin, attrs, | ||||
|                             valid_xdrs=(), valid_attrs=None) | ||||
| 
 | ||||
|     def get_diff_input_output(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential input/output", pin, extras, | ||||
|                             valid_xdrs=(), valid_extras=None) | ||||
|     def get_diff_input_output(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential input/output", pin, attrs, | ||||
|                             valid_xdrs=(), valid_attrs=None) | ||||
| 
 | ||||
| 
 | ||||
| class TemplatedPlatform(Platform): | ||||
|  |  | |||
|  | @ -7,21 +7,24 @@ from ..lib.io import * | |||
| from .dsl import * | ||||
| 
 | ||||
| 
 | ||||
| __all__ = ["ConstraintError", "ConstraintManager"] | ||||
| __all__ = ["ResourceError", "ResourceManager"] | ||||
| 
 | ||||
| 
 | ||||
| class ConstraintError(Exception): | ||||
| class ResourceError(Exception): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| class ConstraintManager: | ||||
| class ResourceManager: | ||||
|     def __init__(self, resources, connectors, clocks): | ||||
|         self.resources  = OrderedDict() | ||||
|         self._requested = OrderedDict() | ||||
| 
 | ||||
|         self.connectors = OrderedDict() | ||||
|         self._conn_pins = OrderedDict() | ||||
| 
 | ||||
|         self.clocks     = OrderedDict() | ||||
| 
 | ||||
|         self._mapping   = OrderedDict() | ||||
|         self._requested = OrderedDict() | ||||
|         # Constraint lists | ||||
|         self._ports     = [] | ||||
| 
 | ||||
|         self.add_resources(resources) | ||||
|  | @ -50,36 +53,36 @@ class ConstraintManager: | |||
|             self.connectors[conn.name, conn.number] = conn | ||||
| 
 | ||||
|             for conn_pin, plat_pin in conn: | ||||
|                 assert conn_pin not in self._mapping | ||||
|                 self._mapping[conn_pin] = plat_pin | ||||
|                 assert conn_pin not in self._conn_pins | ||||
|                 self._conn_pins[conn_pin] = plat_pin | ||||
| 
 | ||||
|     def add_clock(self, name, number, frequency): | ||||
|         resource = self.lookup(name, number) | ||||
|         if isinstance(resource.io[0], Subsignal): | ||||
|         if isinstance(resource.ios[0], Subsignal): | ||||
|             raise TypeError("Cannot constrain frequency of resource {}#{} because it has " | ||||
|                             "subsignals" | ||||
|                             .format(resource.name, resource.number, frequency)) | ||||
|         if (resource.name, resource.number) in self.clocks: | ||||
|             other = self.clocks[resource.name, resource.number] | ||||
|             raise ConstraintError("Resource {}#{} is already constrained to a frequency of " | ||||
|                                   "{:f} MHz" | ||||
|                                   .format(resource.name, resource.number, other / 1e6)) | ||||
|             raise ResourceError("Resource {}#{} is already constrained to a frequency of " | ||||
|                                 "{:f} MHz" | ||||
|                                 .format(resource.name, resource.number, other / 1e6)) | ||||
|         self.clocks[resource.name, resource.number] = frequency | ||||
| 
 | ||||
|     def lookup(self, name, number=0): | ||||
|         if (name, number) not in self.resources: | ||||
|             raise ConstraintError("Resource {}#{} does not exist" | ||||
|             raise ResourceError("Resource {}#{} does not exist" | ||||
|                                   .format(name, number)) | ||||
|         return self.resources[name, number] | ||||
| 
 | ||||
|     def request(self, name, number=0, *, dir=None, xdr=None): | ||||
|         resource = self.lookup(name, number) | ||||
|         if (resource.name, resource.number) in self._requested: | ||||
|             raise ConstraintError("Resource {}#{} has already been requested" | ||||
|                                   .format(name, number)) | ||||
|             raise ResourceError("Resource {}#{} has already been requested" | ||||
|                                 .format(name, number)) | ||||
| 
 | ||||
|         def merge_options(subsignal, dir, xdr): | ||||
|             if isinstance(subsignal.io[0], Subsignal): | ||||
|             if isinstance(subsignal.ios[0], Subsignal): | ||||
|                 if dir is None: | ||||
|                     dir = dict() | ||||
|                 if xdr is None: | ||||
|  | @ -92,52 +95,54 @@ class ConstraintManager: | |||
|                     raise TypeError("Data rate must be a dict, not {!r}, because {!r} " | ||||
|                                     "has subsignals" | ||||
|                                     .format(xdr, subsignal)) | ||||
|                 for sub in subsignal.io: | ||||
|                 for sub in subsignal.ios: | ||||
|                     sub_dir = dir.get(sub.name, None) | ||||
|                     sub_xdr = xdr.get(sub.name, None) | ||||
|                     dir[sub.name], xdr[sub.name] = merge_options(sub, sub_dir, sub_xdr) | ||||
|             else: | ||||
|                 if dir is None: | ||||
|                     dir = subsignal.io[0].dir | ||||
|                     dir = subsignal.ios[0].dir | ||||
|                 if xdr is None: | ||||
|                     xdr = 0 | ||||
|                 if dir not in ("i", "o", "oe", "io", "-"): | ||||
|                     raise TypeError("Direction must be one of \"i\", \"o\", \"oe\", \"io\", " | ||||
|                                     "or \"-\", not {!r}" | ||||
|                                     .format(dir)) | ||||
|                 if dir != subsignal.io[0].dir and not (subsignal.io[0].dir == "io" or dir == "-"): | ||||
|                 if dir != subsignal.ios[0].dir and \ | ||||
|                         not (subsignal.ios[0].dir == "io" or dir == "-"): | ||||
|                     raise ValueError("Direction of {!r} cannot be changed from \"{}\" to \"{}\"; " | ||||
|                                      "direction can be changed from \"io\" to \"i\", \"o\", or " | ||||
|                                      "\"oe\", or from anything to \"-\"" | ||||
|                                      .format(subsignal.io[0], subsignal.io[0].dir, dir)) | ||||
|                                      .format(subsignal.ios[0], subsignal.ios[0].dir, dir)) | ||||
|                 if not isinstance(xdr, int) or xdr < 0: | ||||
|                     raise ValueError("Data rate of {!r} must be a non-negative integer, not {!r}" | ||||
|                                      .format(subsignal.io[0], xdr)) | ||||
|                                      .format(subsignal.ios[0], xdr)) | ||||
|             return dir, xdr | ||||
| 
 | ||||
|         def resolve(subsignal, dir, xdr, name): | ||||
|             if isinstance(subsignal.io[0], Subsignal): | ||||
|         def resolve(resource, dir, xdr, name, attrs): | ||||
|             if isinstance(resource.ios[0], Subsignal): | ||||
|                 fields = OrderedDict() | ||||
|                 for sub in subsignal.io: | ||||
|                 for sub in resource.ios: | ||||
|                     fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name], | ||||
|                                                  name="{}__{}".format(name, sub.name)) | ||||
|                                                name="{}__{}".format(name, sub.name), | ||||
|                                                attrs={**attrs, **sub.attrs}) | ||||
|                 return Record([ | ||||
|                     (f_name, f.layout) for (f_name, f) in fields.items() | ||||
|                 ], fields=fields, name=name) | ||||
| 
 | ||||
|             elif isinstance(subsignal.io[0], (Pins, DiffPairs)): | ||||
|                 phys = subsignal.io[0] | ||||
|             elif isinstance(resource.ios[0], (Pins, DiffPairs)): | ||||
|                 phys = resource.ios[0] | ||||
|                 if isinstance(phys, Pins): | ||||
|                     port = Record([("io", len(phys))], name=name) | ||||
|                 if isinstance(phys, DiffPairs): | ||||
|                     port = Record([("p", len(phys)), | ||||
|                                    ("n", len(phys))], name=name) | ||||
|                 if dir == "-": | ||||
|                     self._ports.append((subsignal, None, port)) | ||||
|                     self._ports.append((resource, None, port, attrs)) | ||||
|                     return port | ||||
|                 else: | ||||
|                     pin  = Pin(len(phys), dir, xdr, name=name) | ||||
|                     self._ports.append((subsignal, pin, port)) | ||||
|                     self._ports.append((resource, pin, port, attrs)) | ||||
|                     return pin | ||||
| 
 | ||||
|             else: | ||||
|  | @ -145,51 +150,61 @@ class ConstraintManager: | |||
| 
 | ||||
|         value = resolve(resource, | ||||
|             *merge_options(resource, dir, xdr), | ||||
|             name="{}_{}".format(resource.name, resource.number)) | ||||
|             name="{}_{}".format(resource.name, resource.number), | ||||
|             attrs=resource.attrs) | ||||
|         self._requested[resource.name, resource.number] = value | ||||
|         return value | ||||
| 
 | ||||
|     def iter_single_ended_pins(self): | ||||
|         for res, pin, port in self._ports: | ||||
|         for res, pin, port, attrs in self._ports: | ||||
|             if pin is None: | ||||
|                 continue | ||||
|             if isinstance(res.io[0], Pins): | ||||
|                 yield pin, port.io, res.extras | ||||
|             if isinstance(res.ios[0], Pins): | ||||
|                 yield pin, port.io, attrs | ||||
| 
 | ||||
|     def iter_differential_pins(self): | ||||
|         for res, pin, port in self._ports: | ||||
|         for res, pin, port, attrs in self._ports: | ||||
|             if pin is None: | ||||
|                 continue | ||||
|             if isinstance(res.io[0], DiffPairs): | ||||
|                 yield pin, port.p, port.n, res.extras | ||||
|             if isinstance(res.ios[0], DiffPairs): | ||||
|                 yield pin, port.p, port.n, attrs | ||||
| 
 | ||||
|     def should_skip_port_component(self, port, attrs, component): | ||||
|         return False | ||||
| 
 | ||||
|     def iter_ports(self): | ||||
|         for res, pin, port in self._ports: | ||||
|             if isinstance(res.io[0], Pins): | ||||
|                 yield port.io | ||||
|             elif isinstance(res.io[0], DiffPairs): | ||||
|                 yield port.p | ||||
|                 yield port.n | ||||
|         for res, pin, port, attrs in self._ports: | ||||
|             if isinstance(res.ios[0], Pins): | ||||
|                 if not self.should_skip_port_component(port, attrs, "io"): | ||||
|                     yield port.io | ||||
|             elif isinstance(res.ios[0], DiffPairs): | ||||
|                 if not self.should_skip_port_component(port, attrs, "p"): | ||||
|                     yield port.p | ||||
|                 if not self.should_skip_port_component(port, attrs, "n"): | ||||
|                     yield port.n | ||||
|             else: | ||||
|                 assert False | ||||
| 
 | ||||
|     def iter_port_constraints(self): | ||||
|         for res, pin, port in self._ports: | ||||
|             if isinstance(res.io[0], Pins): | ||||
|                 yield port.io.name, list(res.io[0].map_names(self._mapping, res)), res.extras | ||||
|             elif isinstance(res.io[0], DiffPairs): | ||||
|                 yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras | ||||
|                 yield port.n.name, list(res.io[0].n.map_names(self._mapping, res)), res.extras | ||||
|         for res, pin, port, attrs in self._ports: | ||||
|             if isinstance(res.ios[0], Pins): | ||||
|                 if not self.should_skip_port_component(port, attrs, "io"): | ||||
|                     yield port.io.name, res.ios[0].map_names(self._conn_pins, res), attrs | ||||
|             elif isinstance(res.ios[0], DiffPairs): | ||||
|                 if not self.should_skip_port_component(port, attrs, "p"): | ||||
|                     yield port.p.name, res.ios[0].p.map_names(self._conn_pins, res), attrs | ||||
|                 if not self.should_skip_port_component(port, attrs, "n"): | ||||
|                     yield port.n.name, res.ios[0].n.map_names(self._conn_pins, res), attrs | ||||
|             else: | ||||
|                 assert False | ||||
| 
 | ||||
|     def iter_port_constraints_bits(self): | ||||
|         for port_name, pin_names, extras in self.iter_port_constraints(): | ||||
|         for port_name, pin_names, attrs in self.iter_port_constraints(): | ||||
|             if len(pin_names) == 1: | ||||
|                 yield port_name, pin_names[0], extras | ||||
|                 yield port_name, pin_names[0], attrs | ||||
|             else: | ||||
|                 for bit, pin_name in enumerate(pin_names): | ||||
|                     yield "{}[{}]".format(port_name, bit), pin_name, extras | ||||
|                     yield "{}[{}]".format(port_name, bit), pin_name, attrs | ||||
| 
 | ||||
|     def iter_clock_constraints(self): | ||||
|         for name, number in self.clocks.keys() & self._requested.keys(): | ||||
|  | @ -197,12 +212,12 @@ class ConstraintManager: | |||
|             period   = self.clocks[name, number] | ||||
|             pin      = self._requested[name, number] | ||||
|             if pin.dir == "io": | ||||
|                 raise ConstraintError("Cannot constrain frequency of resource {}#{} because " | ||||
|                                       "it has been requested as a tristate buffer" | ||||
|                                       .format(name, number)) | ||||
|             if isinstance(resource.io[0], Pins): | ||||
|                 raise ResourceError("Cannot constrain frequency of resource {}#{} because " | ||||
|                                     "it has been requested as a tristate buffer" | ||||
|                                     .format(name, number)) | ||||
|             if isinstance(resource.ios[0], Pins): | ||||
|                 port_name = "{}__io".format(pin.name) | ||||
|             elif isinstance(resource.io[0], DiffPairs): | ||||
|             elif isinstance(resource.ios[0], DiffPairs): | ||||
|                 port_name = "{}__p".format(pin.name) | ||||
|             else: | ||||
|                 assert False | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ class PinsTestCase(FHDLTestCase): | |||
|             "pmod_0:1": "A1", | ||||
|             "pmod_0:2": "A2", | ||||
|         } | ||||
|         self.assertEqual(list(p.map_names(mapping, p)), ["A0", "A1", "A2"]) | ||||
|         self.assertEqual(p.map_names(mapping, p), ["A0", "A1", "A2"]) | ||||
| 
 | ||||
|     def test_map_names_recur(self): | ||||
|         p = Pins("0", conn=("pmod", 0)) | ||||
|  | @ -31,7 +31,7 @@ class PinsTestCase(FHDLTestCase): | |||
|             "pmod_0:0": "ext_0:1", | ||||
|             "ext_0:1":  "A1", | ||||
|         } | ||||
|         self.assertEqual(list(p.map_names(mapping, p)), ["A1"]) | ||||
|         self.assertEqual(p.map_names(mapping, p), ["A1"]) | ||||
| 
 | ||||
|     def test_wrong_names(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|  | @ -51,7 +51,7 @@ class PinsTestCase(FHDLTestCase): | |||
|         with self.assertRaises(NameError, | ||||
|                 msg="Resource (pins io pmod_0:0 pmod_0:1 pmod_0:2) refers to nonexistent " | ||||
|                     "connector pin pmod_0:1"): | ||||
|             list(p.map_names(mapping, p)) | ||||
|             p.map_names(mapping, p) | ||||
| 
 | ||||
| 
 | ||||
| class DiffPairsTestCase(FHDLTestCase): | ||||
|  | @ -84,81 +84,90 @@ class DiffPairsTestCase(FHDLTestCase): | |||
|             dp = DiffPairs("A0", "B0 B1") | ||||
| 
 | ||||
| 
 | ||||
| class AttrsTestCase(FHDLTestCase): | ||||
|     def test_basic(self): | ||||
|         a = Attrs(IO_STANDARD="LVCMOS33", PULLUP="1") | ||||
|         self.assertEqual(a["IO_STANDARD"], "LVCMOS33") | ||||
|         self.assertEqual(repr(a), "(attrs IO_STANDARD=LVCMOS33 PULLUP=1)") | ||||
| 
 | ||||
|     def test_wrong_value(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Attribute value must be a string, not 1"): | ||||
|             a = Attrs(FOO=1) | ||||
| 
 | ||||
| 
 | ||||
| class SubsignalTestCase(FHDLTestCase): | ||||
|     def test_basic_pins(self): | ||||
|         s = Subsignal("a", Pins("A0"), extras={"IOSTANDARD": "LVCMOS33"}) | ||||
|         self.assertEqual(repr(s), "(subsignal a (pins io A0) IOSTANDARD=LVCMOS33)") | ||||
|         s = Subsignal("a", Pins("A0"), Attrs(IOSTANDARD="LVCMOS33")) | ||||
|         self.assertEqual(repr(s), | ||||
|             "(subsignal a (pins io A0) (attrs IOSTANDARD=LVCMOS33))") | ||||
| 
 | ||||
|     def test_basic_diffpairs(self): | ||||
|         s = Subsignal("a", DiffPairs("A0", "B0")) | ||||
|         self.assertEqual(repr(s), "(subsignal a (diffpairs io (p A0) (n B0)) )") | ||||
|         self.assertEqual(repr(s), | ||||
|             "(subsignal a (diffpairs io (p A0) (n B0)) (attrs ))") | ||||
| 
 | ||||
|     def test_basic_subsignals(self): | ||||
|         s = Subsignal("a", | ||||
|                 Subsignal("b", Pins("A0")), | ||||
|                 Subsignal("c", Pins("A1"))) | ||||
|         self.assertEqual(repr(s), | ||||
|                 "(subsignal a (subsignal b (pins io A0) ) (subsignal c (pins io A1) ) )") | ||||
|             "(subsignal a (subsignal b (pins io A0) (attrs )) " | ||||
|                          "(subsignal c (pins io A1) (attrs )) (attrs ))") | ||||
| 
 | ||||
|     def test_extras(self): | ||||
|     def test_attrs(self): | ||||
|         s = Subsignal("a", | ||||
|                 Subsignal("b", Pins("A0")), | ||||
|                 Subsignal("c", Pins("A0"), extras={"SLEW": "FAST"}), | ||||
|                 extras={"IOSTANDARD": "LVCMOS33"}) | ||||
|         self.assertEqual(s.extras, {"IOSTANDARD": "LVCMOS33"}) | ||||
|         self.assertEqual(s.io[0].extras, {"IOSTANDARD": "LVCMOS33"}) | ||||
|         self.assertEqual(s.io[1].extras, {"SLEW": "FAST", "IOSTANDARD": "LVCMOS33"}) | ||||
|                 Subsignal("c", Pins("A0"), Attrs(SLEW="FAST")), | ||||
|                 Attrs(IOSTANDARD="LVCMOS33")) | ||||
|         self.assertEqual(s.attrs, {"IOSTANDARD": "LVCMOS33"}) | ||||
|         self.assertEqual(s.ios[0].attrs, {}) | ||||
|         self.assertEqual(s.ios[1].attrs, {"SLEW": "FAST"}) | ||||
| 
 | ||||
|     def test_empty_io(self): | ||||
|         with self.assertRaises(TypeError, msg="Missing I/O constraints"): | ||||
|     def test_attrs_many(self): | ||||
|         s = Subsignal("a", Pins("A0"), Attrs(SLEW="FAST"), Attrs(PULLUP="1")) | ||||
|         self.assertEqual(s.attrs, {"SLEW": "FAST", "PULLUP": "1"}) | ||||
| 
 | ||||
|     def test_wrong_empty_io(self): | ||||
|         with self.assertRaises(ValueError, msg="Missing I/O constraints"): | ||||
|             s = Subsignal("a") | ||||
| 
 | ||||
|     def test_wrong_io(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="I/O constraint must be one of Pins, DiffPairs or Subsignal, not 'wrong'"): | ||||
|                 msg="I/O constraint must be one of Pins, DiffPairs, Subsignal, or Attrs, " | ||||
|                     "not 'wrong'"): | ||||
|             s = Subsignal("a", "wrong") | ||||
| 
 | ||||
|     def test_wrong_pins(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Pins and DiffPairs cannot be followed by more I/O constraints, but " | ||||
|                     "(pins io A0) is followed by (pins io A1)"): | ||||
|                 msg="Pins and DiffPairs are incompatible with other location or subsignal " | ||||
|                     "constraints, but (pins io A1) appears after (pins io A0)"): | ||||
|             s = Subsignal("a", Pins("A0"), Pins("A1")) | ||||
| 
 | ||||
|     def test_wrong_diffpairs(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Pins and DiffPairs cannot be followed by more I/O constraints, but " | ||||
|                     "(diffpairs io (p A0) (n B0)) is followed by " | ||||
|                     "(pins io A1)"): | ||||
|                 msg="Pins and DiffPairs are incompatible with other location or subsignal " | ||||
|                     "constraints, but (pins io A1) appears after (diffpairs io (p A0) (n B0))"): | ||||
|             s = Subsignal("a", DiffPairs("A0", "B0"), Pins("A1")) | ||||
| 
 | ||||
|     def test_wrong_subsignals(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="A Subsignal can only be followed by more Subsignals, but " | ||||
|                     "(subsignal b (pins io A0) ) is followed by (pins io B0)"): | ||||
|                 msg="Pins and DiffPairs are incompatible with other location or subsignal " | ||||
|                     "constraints, but (pins io B0) appears after (subsignal b (pins io A0) " | ||||
|                     "(attrs ))"): | ||||
|             s = Subsignal("a", Subsignal("b", Pins("A0")), Pins("B0")) | ||||
| 
 | ||||
|     def test_wrong_extras(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Extra constraints must be a dict, not [(pins io B0)]"): | ||||
|             s = Subsignal("a", Pins("A0"), extras=[Pins("B0")]) | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Extra constraint key must be a string, not 1"): | ||||
|             s = Subsignal("a", Pins("A0"), extras={1: 2}) | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Extra constraint value must be a string, not 2"): | ||||
|             s = Subsignal("a", Pins("A0"), extras={"1": 2}) | ||||
| 
 | ||||
| 
 | ||||
| class ResourceTestCase(FHDLTestCase): | ||||
|     def test_basic(self): | ||||
|         r = Resource("serial", 0, | ||||
|                 Subsignal("tx", Pins("A0", dir="o")), | ||||
|                 Subsignal("rx", Pins("A1", dir="i")), | ||||
|                 extras={"IOSTANDARD": "LVCMOS33"}) | ||||
|                 Attrs(IOSTANDARD="LVCMOS33")) | ||||
|         self.assertEqual(repr(r), "(resource serial 0" | ||||
|                                   " (subsignal tx (pins o A0) IOSTANDARD=LVCMOS33)" | ||||
|                                   " (subsignal rx (pins i A1) IOSTANDARD=LVCMOS33)" | ||||
|                                   " IOSTANDARD=LVCMOS33)") | ||||
|                                   " (subsignal tx (pins o A0) (attrs ))" | ||||
|                                   " (subsignal rx (pins i A1) (attrs ))" | ||||
|                                   " (attrs IOSTANDARD=LVCMOS33))") | ||||
| 
 | ||||
| 
 | ||||
| class ConnectorTestCase(FHDLTestCase): | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ from ..build.res import * | |||
| from .tools import * | ||||
| 
 | ||||
| 
 | ||||
| class ConstraintManagerTestCase(FHDLTestCase): | ||||
| class ResourceManagerTestCase(FHDLTestCase): | ||||
|     def setUp(self): | ||||
|         self.resources = [ | ||||
|             Resource("clk100", 0, DiffPairs("H1", "H2", dir="i")), | ||||
|  | @ -20,14 +20,14 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|         self.connectors = [ | ||||
|             Connector("pmod", 0, "B0 B1 B2 B3 - -"), | ||||
|         ] | ||||
|         self.cm = ConstraintManager(self.resources, self.connectors, []) | ||||
|         self.cm = ResourceManager(self.resources, self.connectors, []) | ||||
| 
 | ||||
|     def test_basic(self): | ||||
|         self.clocks = [ | ||||
|             ("clk100",      100), | ||||
|             (("clk50", 0),  50), | ||||
|         ] | ||||
|         self.cm = ConstraintManager(self.resources, self.connectors, self.clocks) | ||||
|         self.cm = ResourceManager(self.resources, self.connectors, self.clocks) | ||||
|         self.assertEqual(self.cm.resources, { | ||||
|             ("clk100",   0): self.resources[0], | ||||
|             ("clk50",    0): self.resources[1], | ||||
|  | @ -177,8 +177,8 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
| 
 | ||||
|     def test_wrong_resources_duplicate(self): | ||||
|         with self.assertRaises(NameError, | ||||
|                 msg="Trying to add (resource user_led 0 (pins o A1) ), but " | ||||
|                     "(resource user_led 0 (pins o A0) ) has the same name and number"): | ||||
|                 msg="Trying to add (resource user_led 0 (pins o A1) (attrs )), but " | ||||
|                     "(resource user_led 0 (pins o A0) (attrs )) has the same name and number"): | ||||
|             self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))]) | ||||
| 
 | ||||
|     def test_wrong_connectors(self): | ||||
|  | @ -192,7 +192,7 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|             self.cm.add_connectors([Connector("pmod", 0, "1 2")]) | ||||
| 
 | ||||
|     def test_wrong_lookup(self): | ||||
|         with self.assertRaises(ConstraintError, | ||||
|         with self.assertRaises(ResourceError, | ||||
|                 msg="Resource user_led#1 does not exist"): | ||||
|             r = self.cm.lookup("user_led", 1) | ||||
| 
 | ||||
|  | @ -203,7 +203,7 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|             self.cm.add_clock("i2c", 0, 10e6) | ||||
| 
 | ||||
|     def test_wrong_frequency_tristate(self): | ||||
|         with self.assertRaises(ConstraintError, | ||||
|         with self.assertRaises(ResourceError, | ||||
|                 msg="Cannot constrain frequency of resource clk50#0 because " | ||||
|                     "it has been requested as a tristate buffer"): | ||||
|             self.cm.add_clock("clk50", 0, 20e6) | ||||
|  | @ -211,13 +211,13 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|             list(self.cm.iter_clock_constraints()) | ||||
| 
 | ||||
|     def test_wrong_frequency_duplicate(self): | ||||
|         with self.assertRaises(ConstraintError, | ||||
|         with self.assertRaises(ResourceError, | ||||
|                 msg="Resource clk100#0 is already constrained to a frequency of 10.000000 MHz"): | ||||
|             self.cm.add_clock("clk100", 0, 10e6) | ||||
|             self.cm.add_clock("clk100", 0, 5e6) | ||||
| 
 | ||||
|     def test_wrong_request_duplicate(self): | ||||
|         with self.assertRaises(ConstraintError, | ||||
|         with self.assertRaises(ResourceError, | ||||
|                 msg="Resource user_led#0 has already been requested"): | ||||
|             self.cm.request("user_led", 0) | ||||
|             self.cm.request("user_led", 0) | ||||
|  | @ -238,7 +238,8 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|     def test_wrong_request_with_dir_dict(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Directions must be a dict, not 'i', because (resource i2c 0 (subsignal scl " | ||||
|                     "(pins o N10) ) (subsignal sda (pins io N11) ) ) has subsignals"): | ||||
|                     "(pins o N10) (attrs )) (subsignal sda (pins io N11) (attrs )) (attrs )) " | ||||
|                     "has subsignals"): | ||||
|             i2c = self.cm.request("i2c", 0, dir="i") | ||||
| 
 | ||||
|     def test_wrong_request_with_wrong_xdr(self): | ||||
|  | @ -249,5 +250,6 @@ class ConstraintManagerTestCase(FHDLTestCase): | |||
|     def test_wrong_request_with_xdr_dict(self): | ||||
|         with self.assertRaises(TypeError, | ||||
|                 msg="Data rate must be a dict, not 2, because (resource i2c 0 (subsignal scl " | ||||
|                     "(pins o N10) ) (subsignal sda (pins io N11) ) ) has subsignals"): | ||||
|                     "(pins o N10) (attrs )) (subsignal sda (pins io N11) (attrs )) (attrs )) " | ||||
|                     "has subsignals"): | ||||
|             i2c = self.cm.request("i2c", 0, xdr=2) | ||||
|  |  | |||
							
								
								
									
										102
									
								
								nmigen/vendor/lattice_ice40.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										102
									
								
								nmigen/vendor/lattice_ice40.py
									
									
									
									
										vendored
									
									
								
							|  | @ -70,7 +70,7 @@ class LatticeICE40Platform(TemplatedPlatform): | |||
|         """, | ||||
|         "{{name}}.pcf": r""" | ||||
|             # {{autogenerated}} | ||||
|             {% for port_name, pin_name, extras in platform.iter_port_constraints_bits() -%} | ||||
|             {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%} | ||||
|                 set_io {{port_name}} {{pin_name}} | ||||
|             {% endfor %} | ||||
|         """, | ||||
|  | @ -110,33 +110,17 @@ class LatticeICE40Platform(TemplatedPlatform): | |||
|         """ | ||||
|     ] | ||||
| 
 | ||||
|     def iter_ports(self): | ||||
|         for res, pin, port in self._ports: | ||||
|             if isinstance(res.io[0], Pins): | ||||
|                 yield port.io | ||||
|             elif isinstance(res.io[0], DiffPairs): | ||||
|                 if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT": | ||||
|                     yield port.p | ||||
|                 else: | ||||
|                     yield port.p | ||||
|                     yield port.n | ||||
|             else: | ||||
|                 assert False | ||||
|     def should_skip_port_component(self, port, attrs, component): | ||||
|         # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for | ||||
|         # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs | ||||
|         # between LP/HX and UP series: | ||||
|         #  * for LP/HX, z=0 is DPxxB   (B is non-inverting, A is inverting) | ||||
|         #  * for UP,    z=0 is IOB_xxA (A is non-inverting, B is inverting) | ||||
|         if attrs.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT" and component == "n": | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def iter_port_constraints(self): | ||||
|         for res, pin, port in self._ports: | ||||
|             if isinstance(res.io[0], Pins): | ||||
|                 yield port.io.name, list(res.io[0].map_names(self._mapping, res)), res.extras | ||||
|             elif isinstance(res.io[0], DiffPairs): | ||||
|                 if res.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT": | ||||
|                     yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras | ||||
|                 else: | ||||
|                     yield port.p.name, list(res.io[0].p.map_names(self._mapping, res)), res.extras | ||||
|                     yield port.n.name, list(res.io[0].n.map_names(self._mapping, res)), res.extras | ||||
|             else: | ||||
|                 assert False | ||||
| 
 | ||||
|     def _get_io_buffer(self, m, pin, port, extras, o_invert=None): | ||||
|     def _get_io_buffer(self, m, pin, port, attrs, o_invert=None): | ||||
|         def _get_dff(clk, d, q): | ||||
|             m.submodules += Instance("$dff", | ||||
|                 p_CLK_POLARITY=0, | ||||
|  | @ -160,9 +144,9 @@ class LatticeICE40Platform(TemplatedPlatform): | |||
|                         o_O=y[bit]) | ||||
|                 return y | ||||
| 
 | ||||
|         if "GLOBAL" in extras: | ||||
|             is_global_input = bool(extras["GLOBAL"]) | ||||
|             del extras["GLOBAL"] | ||||
|         if "GLOBAL" in attrs: | ||||
|             is_global_input = bool(attrs["GLOBAL"]) | ||||
|             del attrs["GLOBAL"] | ||||
|         else: | ||||
|             is_global_input = False | ||||
| 
 | ||||
|  | @ -185,7 +169,7 @@ class LatticeICE40Platform(TemplatedPlatform): | |||
|         for bit in range(len(port)): | ||||
|             io_args = [ | ||||
|                 ("io", "PACKAGE_PIN", port[bit]), | ||||
|                 *(("p", key, value) for key, value in extras.items()), | ||||
|                 *(("p", key, value) for key, value in attrs.items()), | ||||
|             ] | ||||
| 
 | ||||
|             if "i" not in pin.dir: | ||||
|  | @ -242,56 +226,52 @@ class LatticeICE40Platform(TemplatedPlatform): | |||
|             else: | ||||
|                 m.submodules += Instance("SB_IO", *io_args) | ||||
| 
 | ||||
|     def get_input(self, pin, port, extras): | ||||
|         self._check_feature("single-ended input", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|     def get_input(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended input", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         self._get_io_buffer(m, pin, port, extras) | ||||
|         self._get_io_buffer(m, pin, port, attrs) | ||||
|         return m | ||||
| 
 | ||||
|     def get_output(self, pin, port, extras): | ||||
|         self._check_feature("single-ended output", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|     def get_output(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended output", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         self._get_io_buffer(m, pin, port, extras) | ||||
|         self._get_io_buffer(m, pin, port, attrs) | ||||
|         return m | ||||
| 
 | ||||
|     def get_tristate(self, pin, port, extras): | ||||
|         self._check_feature("single-ended tristate", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|     def get_tristate(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended tristate", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         self._get_io_buffer(m, pin, port, extras) | ||||
|         self._get_io_buffer(m, pin, port, attrs) | ||||
|         return m | ||||
| 
 | ||||
|     def get_input_output(self, pin, port, extras): | ||||
|         self._check_feature("single-ended input/output", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|     def get_input_output(self, pin, port, attrs): | ||||
|         self._check_feature("single-ended input/output", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         self._get_io_buffer(m, pin, port, extras) | ||||
|         self._get_io_buffer(m, pin, port, attrs) | ||||
|         return m | ||||
| 
 | ||||
|     def get_diff_input(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential input", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|         # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for | ||||
|         # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs | ||||
|         # between LP/HX and UP series: | ||||
|         #  * for LP/HX, z=0 is DPxxB   (B is non-inverting, A is inverting) | ||||
|         #  * for UP,    z=0 is IOB_xxA (A is non-inverting, B is inverting) | ||||
|     def get_diff_input(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential input", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         self._get_io_buffer(m, pin, p_port, extras) | ||||
|         # See comment in should_skip_port_component above. | ||||
|         self._get_io_buffer(m, pin, p_port, attrs) | ||||
|         return m | ||||
| 
 | ||||
|     def get_diff_output(self, pin, p_port, n_port, extras): | ||||
|         self._check_feature("differential output", pin, extras, | ||||
|                             valid_xdrs=(0, 1, 2), valid_extras=True) | ||||
|     def get_diff_output(self, pin, p_port, n_port, attrs): | ||||
|         self._check_feature("differential output", pin, attrs, | ||||
|                             valid_xdrs=(0, 1, 2), valid_attrs=True) | ||||
|         m = Module() | ||||
|         # Note that the non-inverting output pin is not driven the same way as a regular | ||||
|         # output pin. The inverter introduces a delay, so for a non-inverting output pin, | ||||
|         # an identical delay is introduced by instantiating a LUT. This makes the waveform | ||||
|         # perfectly symmetric in the xdr=0 case. | ||||
|         self._get_io_buffer(m, pin, p_port, extras, o_invert=False) | ||||
|         self._get_io_buffer(m, pin, n_port, extras, o_invert=True) | ||||
|         self._get_io_buffer(m, pin, p_port, attrs, o_invert=False) | ||||
|         self._get_io_buffer(m, pin, n_port, attrs, o_invert=True) | ||||
|         return m | ||||
| 
 | ||||
|     # Tristate and bidirectional buffers are not supported on iCE40 because it requires external | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 whitequark
						whitequark