예제 #1
0
    def _def_to_proto(self) -> edgir.Link:
        for cls in self._get_bases_of(
                BaseBlock
        ):  # type: ignore  # TODO avoid 'only concrete class' error
            assert issubclass(cls, Link)

        pb = self._populate_def_proto_block_base(edgir.Link())
        pb = self._populate_def_proto_block_contents(pb)
        pb = self._populate_def_proto_param_init(pb)
        # specifically ignore the port initializers

        # actually generate the links and connects
        ref_map = self._get_ref_map(edgir.LocalPath())
        self._connects.finalize()
        self._links_order: Dict[str, str] = self.Metadata({})
        for name, connect in self._connects.items_ordered():
            self._links_order[str(len(self._links_order))] = f"{name}"

            connect_elts = connect.generate_connections()
            assert connect_elts is not None and connect_elts.link_type is not None, "bad connect definition in link"

            link_path = edgir.localpath_concat(edgir.LocalPath(), name)
            pb.links[
                name].lib_elem.target.name = connect_elts.link_type._static_def_name(
                )

            for idx, (self_port, link_port_path) in enumerate(
                    connect_elts.bridged_connects):
                # TODO handle Vector types
                if isinstance(
                        self_port, DerivedVector
                ):  # TODO unify once we get rid of ref_map, especially to be more robust
                    pb.constraints[
                        f"(export){name}_{idx}"].exported.exterior_port.map_extract.container.ref.CopyFrom(
                            ref_map[self_port.base])
                    pb.constraints[
                        f"(export){name}_{idx}"].exported.exterior_port.map_extract.path.steps.add(
                        ).name = self_port.base._get_elt_sample()._name_of(
                            self_port.target)
                else:
                    pb.constraints[
                        f"(export){name}_{idx}"].exported.exterior_port.ref.CopyFrom(
                            ref_map[self_port])
                pb.constraints[
                    f"(export){name}_{idx}"].exported.internal_block_port.ref.CopyFrom(
                        edgir.localpath_concat(link_path, link_port_path))
                self._namespace_order.append(f"(export){name}_{idx}")

        return pb
예제 #2
0
    def _populate_def_proto_block_contents(self, pb: ProtoType) -> ProtoType:
        """Populates the contents of a block proto: constraints"""
        assert self._elaboration_state == BlockElaborationState.post_contents or \
               self._elaboration_state == BlockElaborationState.post_generate

        self._constraints.finalize()

        ref_map = self._get_ref_map(edgir.LocalPath())

        for (name, constraint) in self._constraints.items():
            pb.constraints[name].CopyFrom(constraint._expr_to_proto(ref_map))

        for (name, port) in self._ports.items():
            if port in self._required_ports:
                if isinstance(port, Port):
                    pb.constraints[f'(reqd){name}'].CopyFrom(
                        port.is_connected()._expr_to_proto(ref_map))
                elif isinstance(port, Vector):
                    pb.constraints[f'(reqd){name}'].CopyFrom(
                        (port.length() > 0)._expr_to_proto(ref_map))
                else:
                    raise ValueError(f"unknown non-optional port type {port}")
                self._namespace_order.append(f'(reqd){name}')

        return pb
예제 #3
0
 def generate_connections(self) -> ConnectedPorts.Connections:
     link_ref_map = self.link._get_ref_map_allocate(edgir.LocalPath())
     bridged_connects = [(port, link_ref_map[tar])
                         for port, tar in self.bridged_connects]
     direct_connects = [(port, link_ref_map[tar])
                        for port, tar in self.direct_connects]
     return ConnectedPorts.Connections(type(self.link),
                                       bridged_connects,
                                       direct_connects)
예제 #4
0
 def map_port_allocate(ref: Refable,
                       path: edgir.LocalPath) -> edgir.LocalPath:
     if isinstance(ref, BaseVector):
         new_path = edgir.LocalPath()
         new_path.CopyFrom(path)
         new_path.steps.append(
             edgir.LocalStep(reserved_param=edgir.ALLOCATE))
         return new_path
     else:
         return path
예제 #5
0
 def _parse_param_values(
         self, values: Iterable[Tuple[edgir.LocalPath,
                                      edgir.LitTypes]]) -> None:
     ref_map = self._get_ref_map(edgir.LocalPath())
     reverse_ref_map = {
         path.SerializeToString(): refable
         for refable, path in ref_map.items()
     }
     self._param_values = IdentityDict()
     for (path, value) in values:
         path_expr = reverse_ref_map[path.SerializeToString()]
         assert isinstance(path_expr, ConstraintExpr)
         self._param_values[path_expr] = value
예제 #6
0
 def _populate_def_proto_param_init(
     self,
     pb: ProtoType,
     ignore_params: IdentitySet[ConstraintExpr] = IdentitySet()
 ) -> ProtoType:
     ref_map = self._get_ref_map(edgir.LocalPath())  # TODO dedup ref_map
     for (name, param) in self._parameters.items():
         if param.initializer is not None and param not in ignore_params:
             pb.constraints[f'(init){name}'].CopyFrom(
                 AssignBinding.make_assign(param, param.initializer,
                                           ref_map))
             self._namespace_order.append(f'(init){name}')
     return pb
예제 #7
0
 def generate_connections(self) -> Optional[ConnectedPorts.Connections]:
     if self.connect is not None:
         return self.connect.generate_connections()
     elif len(self.ports) == 2:  # for direct exports
         exterior_port = [
             port for port in self.ports
             if port._block_parent() is self.parent
         ]
         internal_port = [
             port for port in self.ports
             if port._block_parent() is not self.parent
         ]
         assert len(exterior_port) == 1 and len(internal_port) == 1
         return self.Connections(
             None,
             [(exterior_port[0], edgir.LocalPath())
              ],  # TODO maybe have a separate type for bridged connections?
             [(internal_port[0], edgir.LocalPath())])
     elif len(self.ports) == 1:
         return None
     else:
         raise ValueError("internal error: bad connection state")
예제 #8
0
    def _populate_def_proto_port_init(
        self,
        pb: ProtoType,
        ignore_ports: IdentitySet[BasePort] = IdentitySet()
    ) -> ProtoType:
        # TODO this is structurally ugly!
        # TODO TODO: for non-generated exported initializers, check and assert default-ness
        ref_map = self._get_ref_map(edgir.LocalPath())  # TODO dedup ref_map

        def check_recursive_no_initializer(port: BasePort,
                                           path: List[str]) -> None:
            if isinstance(port, (Port, Bundle)):
                for (name, subparam) in port._parameters.items():
                    assert subparam.initializer is None, f"unexpected initializer in {port} at {path}"

            if isinstance(port, Bundle):
                for (name, subport) in port._ports.items():
                    check_recursive_no_initializer(subport, path + [name])
            elif isinstance(port, Vector):
                check_recursive_no_initializer(port._get_elt_sample(), path)
            # TODO needs to be something like sealed types for match comprehensiveness

        def process_port_inits(port: BasePort, path: List[str]) -> None:
            if port in ignore_ports:
                return

            if isinstance(port, (Port, Bundle)):
                for (name, subparam) in port._parameters.items():
                    if subparam.initializer is not None:
                        pb.constraints[
                            f"(init){'.'.join(path + [name])}"].CopyFrom(
                                AssignBinding.make_assign(
                                    subparam,
                                    subparam._to_expr_type(
                                        subparam.initializer), ref_map))
                        self._namespace_order.append(
                            f"(init){'.'.join(path + [name])}")

            if isinstance(port, Bundle):
                for (name, subport) in port._ports.items():
                    process_port_inits(subport, path + [name])
            elif isinstance(port, Vector):
                check_recursive_no_initializer(port._get_elt_sample(), path)
            # TODO needs to be something like sealed types for match comprehensiveness

        for (name, port) in self._ports.items():
            process_port_inits(port, [name])

        return pb
예제 #9
0
    def _populate_def_proto_block_base(self, pb: ProtoType) -> ProtoType:
        """Populates the structural parts of a block proto: parameters, ports, superclasses"""
        assert self._elaboration_state == BlockElaborationState.post_contents or \
               self._elaboration_state == BlockElaborationState.post_generate

        self._parameters.finalize()
        self._ports.finalize()

        if (self.__class__, 'abstract') in self._elt_properties:
            assert isinstance(pb, edgir.HierarchyBlock)
            pb.is_abstract = True

        pb.self_class.target.name = self._get_def_name()

        for cls in self._get_bases_of(
                BaseBlock
        ):  # type: ignore  # TODO avoid 'only concrete class' error
            super_pb = pb.superclasses.add()
            super_pb.target.name = cls._static_def_name()

        for (name, param) in self._parameters.items():
            assert isinstance(param.binding, ParamBinding)
            pb.params[name].CopyFrom(param._decl_to_proto())

        for (name, port) in self._ports.items():
            pb.ports[name].CopyFrom(port._instance_to_proto())

        self._constraints.finalize()  # needed for source locator generation

        # generate base-block order
        # TODO unified namespace order
        # TODO this also appends to end, which may not be desirable
        for name in chain(self._parameters.keys_ordered(),
                          self._ports.keys_ordered(),
                          self._constraints.keys_ordered()):
            self._namespace_order.append(name)

        ref_map = self._get_ref_map(edgir.LocalPath())
        pb.meta.CopyFrom(self._metadata_to_proto(self._metadata, [], ref_map))

        return pb
예제 #10
0
    def _populate_def_proto_block_generator(
            self, pb: edgir.HierarchyBlock) -> edgir.HierarchyBlock:
        assert self._generators, f"{self} did not define any generator functions"

        ref_map = self._get_ref_map(edgir.LocalPath())

        for (name, record) in self._generators.items():
            pb.generators[
                name]  # even if rest of the fields are empty, make sure to create a record
            # TODO maybe there should be done data here?
            for req_param in record.req_params:
                pb.generators[name].required_params.add().CopyFrom(
                    ref_map[req_param])
            for req_port in record.req_ports:
                pb.generators[name].required_ports.add().CopyFrom(
                    ref_map[req_port])
            for connect_block in record.connect_blocks:
                pb.generators[name].connected_blocks.add().CopyFrom(
                    ref_map[connect_block])

        return pb
예제 #11
0
 def _get_contained_ref_map(self) -> IdentityDict[Refable, edgir.LocalPath]:
     return self.elt_sample._get_ref_map(edgir.LocalPath())
예제 #12
0
    def _populate_def_proto_hierarchy(
            self, pb: edgir.HierarchyBlock) -> edgir.HierarchyBlock:
        self._blocks.finalize()
        self._connects.finalize()
        self._chains.finalize()

        ref_map = self._get_ref_map(edgir.LocalPath())

        # opportunistic check in the frontend that all internal ports marked connected are connected
        all_connected_ports = IdentitySet[BasePort]()
        for name, connect in self._connects.items():
            if len(connect.ports) > 1:
                all_connected_ports.update(connect.ports)

        for name, block in self._blocks.items():
            pb.blocks[name].lib_elem.target.name = block._get_def_name()

        # actually generate the links and connects
        link_chain_names = IdentityDict[
            ConnectedPorts, List[str]]()  # prefer chain name where applicable
        # TODO generate into primary data structures
        for name, chain in self._chains.items_ordered():
            for i, connect in enumerate(chain.links):
                link_chain_names.setdefault(connect, []).append(f"{name}_{i}")

        for name, connect in self._connects.items_ordered():
            if connect in link_chain_names:
                if not name.startswith('anon_'):
                    pass  # prefer a named link above all else
                else:
                    name = link_chain_names[connect][
                        0]  # arbitrarily pick the first one for now, TODO disambiguate?

            connect_elts = connect.generate_connections()
            if connect_elts is None:  # single port net - effectively discard
                pass
            elif connect_elts.link_type is None:  # generate direct export
                pb.constraints[
                    f"(conn){name}"].exported.exterior_port.ref.CopyFrom(
                        ref_map[connect_elts.bridged_connects[0][0]])
                pb.constraints[
                    f"(conn){name}"].exported.internal_block_port.ref.CopyFrom(
                        ref_map[connect_elts.direct_connects[0][0]])
                self._namespace_order.append(f"(conn){name}")
            else:  # generate link
                link_path = edgir.localpath_concat(edgir.LocalPath(), name)

                self._namespace_order.append(f"{name}")
                pb.links[
                    name].lib_elem.target.name = connect_elts.link_type._static_def_name(
                    )

                for idx, (self_port, link_port_path) in enumerate(
                        connect_elts.bridged_connects):
                    assert isinstance(self_port, Port)
                    assert self_port.bridge_type is not None

                    port_name = self._name_of(self_port)
                    pb.blocks[
                        f"(bridge){port_name}"].lib_elem.target.name = self_port.bridge_type._static_def_name(
                        )
                    self._namespace_order.append(f"(bridge){port_name}")
                    bridge_path = edgir.localpath_concat(
                        edgir.LocalPath(), f"(bridge){port_name}")

                    pb.constraints[
                        f"(bridge){name}_b{idx}"].exported.exterior_port.ref.CopyFrom(
                            ref_map[self_port])
                    pb.constraints[
                        f"(bridge){name}_b{idx}"].exported.internal_block_port.ref.CopyFrom(
                            edgir.localpath_concat(bridge_path, 'outer_port'))
                    self._namespace_order.append(f"(bridge){name}_b{idx}")

                    pb.constraints[
                        f"(conn){name}_b{idx}"].connected.block_port.ref.CopyFrom(
                            edgir.localpath_concat(bridge_path, 'inner_link'))
                    pb.constraints[
                        f"(conn){name}_b{idx}"].connected.link_port.ref.CopyFrom(
                            edgir.localpath_concat(link_path, link_port_path))
                    self._namespace_order.append(f"(conn){name}_b{idx}")

                for idx, (subelt_port, link_port_path) in enumerate(
                        connect_elts.direct_connects):
                    pb.constraints[
                        f"(conn){name}_d{idx}"].connected.block_port.ref.CopyFrom(
                            ref_map[subelt_port])
                    pb.constraints[
                        f"(conn){name}_d{idx}"].connected.link_port.ref.CopyFrom(
                            edgir.localpath_concat(link_path, link_port_path))
                    self._namespace_order.append(f"(conn){name}_d{idx}")

        # generate block initializers
        for (block_name, block) in self._blocks.items():
            for (block_param_name, block_param) in block._init_params.items():
                if block_param.initializer is not None:
                    pb.constraints[
                        f'(init){block_name}.{block_param_name}'].CopyFrom(  # TODO better name
                            AssignBinding.make_assign(
                                block_param,
                                block_param._to_expr_type(
                                    block_param.initializer), ref_map))
                    self._namespace_order.append(
                        f'(init){block_name}.{block_param_name}')

        # generate H-block-specific order
        for name in self._blocks.keys_ordered():
            self._namespace_order.append(name)

        return pb