Beispiel #1
0
def _compile_and_link(program_name: str, wiring: list, main_cpp: str):
    """Compiles and link the graph together with a provided top
    level file.

    Parameters
    ----------
    program_name: str
        Name of the program to generate.
    wiring: list
        Wired graph generated via cog.
    main_cpp: str
        Top level main file.
    """
    asyncio.run(_wait_for_build(wiring))
    _main_h = wiring[program_name + ".h"]
    _main_a = wiring[program_name + ".a"]

    # Converting the main.cpp into a BuildArtifact
    with HostEnv(dir=path.dirname(main_cpp)) as env:
        _main_cpp = BuildArtifact(name=path.basename(main_cpp), env=env)

    with CPPEnv() as cpp:
        main = cpp.compile_and_link(
            [_main_h],
            [_main_a],
            _main_cpp
        )

    return main
Beispiel #2
0
    def compile_and_link(self, headers, objects, main_cpp):
        """Run gcc to compile and link and produce a complete runtime binary.

        Parameters
        ----------
        headers : list
            :py:class:`BuildArtifact<deltasimulator.build_tools.BuildArtifact>`
            objects containing the header files.
        objects : list
            :py:class:`BuildArtifact<deltasimulator.build_tools.BuildArtifact>`
            objects containing the binary objects.
        main_cpp : BuildArtifact
            The C++ file for main.

        Returns
        -------
        BuildArtifact
            The main runtime binary.
        """
        input_files = self._write_files(headers+objects+[main_cpp])

        top_name = main_cpp.name.split(".")[0]
        comp_flag = self._run_gcc(module_name=top_name, after=[input_files])
        link_flag = self._link(
            top_name+".o", archive=objects, after=[comp_flag])
        main = BuildArtifact("main", env=self, after=link_flag)

        return main  # self._get_main(after=link_flag)
Beispiel #3
0
    def _get_rom_init(self, top_v, after):
        """Check if there are any ROM init files and if so return them.

        Parameters
        ----------
        top_v : BuildArtifact
            The Verilog code.
        after : Coroutine
            Process which builds the Verilated code.

        Returns
        -------
        list
            :class:`BuildArtifact<deltasimulator.build_tools.BuildArtifact>`
            objects for the ROM init files.
        """
        # Get the Verilog code and search for ROM init code by regex.
        # TODO: Find a nicer way of getting the init file name.
        data = asyncio.run(top_v.data)
        module_regex = b"([a-zA-Z0-9\\_]+)\\.init:\n"
        inits = []
        for match in re.finditer(module_regex, data):
            rom_name = match[0][:-2].decode("utf8")
            inits.append(BuildArtifact(name=rom_name, env=self, after=after))
        return inits
    def test_migen_node(self):
        with DeltaGraph() as test_graph:
            c1 = DUT1(tb_num_iter=2000, name='counter1').call(i1=return_1000())
            print_then_exit(c1.o1)

        _, serialised = serialize_graph(test_graph)

        top_v = BuildArtifact(
            name=f"{serialised.nodes[1].name}",
            data=serialised.bodies[1].migen.verilog.encode("utf-8"))

        with VerilatorEnv() as env:
            build_artifacts = env.verilate(top_v)

        asyncio.run(self.assert_build_correct(build_artifacts))
Beispiel #5
0
    def _get_archive(self, after, name="main"):
        """Get the .a archive.

        Parameters
        ----------
        after : Coroutine
            Coroutine to wait for before the archive is ready.
        name : Optional[str]
            Name of the .a file, by default "main"

        Returns
        -------
        BuildArtifact
            The content of the .a file.
        """
        return BuildArtifact(f"{name}.a", self, after=after)
Beispiel #6
0
    def _get_main(self, after, name="main"):
        """Gets main runtime binary.

        Parameters
        ----------
        after : Coroutine
            Coroutine to wait for before getting file.
        name : Optional[str]
            The name of the main runtime file, by default "main".

        Returns
        -------
        BuildArtifact
            The binary main runtime.
        """
        return BuildArtifact(name, self, after=after)
Beispiel #7
0
    def _get_h(self, top_p, after):
        """Get the Header file for the node.

        Parameters
        ----------
        top_p
            ``capnp`` object describing the node.
        after : Coroutine
            The process that constructs the Header file.

        Returns
        -------
        bool
            Returns True upon completion.
        """
        return BuildArtifact(f"{top_p.name}.h", self, after=after)
Beispiel #8
0
    def _get_py(self, top_p, after):
        """Get the node's Python script.

        Parameters
        ----------
        top_p
            ``capnp`` object describing the node.
        after : Coroutine
            Process that needs to complete before the Python script is ready.

        Returns
        -------
        BuildArtifact
            The Python script for this node.
        """
        return BuildArtifact(f"{top_p.name}.py", self, after=after)
Beispiel #9
0
    def _get_verilated_o(self, after):
        """Once verilated.o is built, return the file.

        Parameters
        ----------
        after : Coroutine
            :class:`Coroutine` which is building the verilated.o file.

        Returns
        -------
        BuildArtifact
            The verilated.o binary object.
        """
        return BuildArtifact(name="verilated.o",
                             path="obj_dir/",
                             env=self,
                             after=after)
Beispiel #10
0
    def _get_cpp(self, top_p, after):
        """Get the C++ code containing the node's SystemC module after
        it has been built.

        Parameters
        ----------
        top_p
            ``capnp`` object describing the node.
        after : Coroutine
            Process which builds the C++ code.

        Returns
        -------
        BuildArtifact
            The C++ code implementing the node's SystemC module.
        """
        return BuildArtifact(f"{top_p.name}.cpp", self, after=after)
Beispiel #11
0
    def _get_o(self, module_name, after):
        """After gcc is run, the binary object file is returned.

        Parameters
        ----------
        module_name : str
            The name of the module. Note the .o file type will be
            appended to the string, so is not needed here.
        after : Coroutine
            Coroutine to wait for before the file is ready. Usually
            the process which builds the file.

        Returns
        -------
        BuildArtifact
            The module's binary object.
        """
        return BuildArtifact(f"{module_name}.o", env=self, after=after)
Beispiel #12
0
    def _get_ALL_a(self, top_v, after):
        """Once the binary objects have been built return them in a .a archive.

        Parameters
        ----------
        top_v : BuildArtifact
            Verilog code file. Only used for the file name.
        after : Coroutine
            :class:`Coroutine` which builds the binary objects.

        Returns
        -------
        BuildArtifact
            The binary objects in a .a archive.
        """
        mod_name = top_v.name.split(".")[0]
        h_name = "V" + mod_name + "__ALL.a"
        h_path = "obj_dir"
        return BuildArtifact(name=h_name, path=h_path, env=self, after=after)
Beispiel #13
0
    def _get_h(self, top_v, after):
        """Get the header file generated by Verilator.

        Parameters
        ----------
        top_v : BuildArtifact
            The Verilog code.
        after : Coroutine
            Process to wait for before the header file is generated.

        Returns
        -------
        BuildArtifact
            The generated header file.
        """
        mod_name = top_v.name.split(".")[0]
        h_name = "V" + mod_name + ".h"
        h_path = "obj_dir"
        return BuildArtifact(name=h_name, path=h_path, after=after, env=self)
Beispiel #14
0
    def _get_cpp(self, top_v, after):
        """Returns the C++ file generated by Verilator.

        Parameters
        ----------
        top_v : BuildArtifact
            The Verilog code.
        after : Coroutine
            Process to wait for before the C++ code is ready.

        Returns
        -------
        BuildArtifact
            The C++ code generated.
        """
        mod_name = top_v.name.split(".")[0]
        cpp_name = "V" + mod_name + ".cpp"
        cpp_path = "obj_dir"
        return BuildArtifact(name=cpp_name,
                             path=cpp_path,
                             after=after,
                             env=self)
Beispiel #15
0
    # write artifacts to build repository
    for build_artifact_name, build_artifact_data in wiring.items():
        print(f"writing: {build_artifact_name} into {build_repo}")
        with open(build_repo + f"/{build_artifact_name}", "wb") as f:
            write(build_artifact_data, f)

    # write python bodies to build repository
    for py_build_artifact in node_bodies:
        print(f"py_build_artifact: {py_build_artifact}")
        print(f"py_build_artifact: {type(py_build_artifact)}")
        with open(build_repo + f"/{py_build_artifact.name}", "wb") as f:
            write(py_build_artifact, f)

    # write init roms to build repository
    for init_rom_artifact in node_inits:
        with open(build_repo + f"/{init_rom_artifact.name}", "wb") as f:
            write(init_rom_artifact, f)

    # start compilation step
    with HostEnv(dir=build_repo) as env:
        main_cpp = BuildArtifact(name=main_cpp_file, env=env)
        main_h = BuildArtifact(name=program_name + ".h", env=env)
        main_a = BuildArtifact(name=program_name + ".a", env=env)
        #verilated_o =  BuildArtifact(name="verilated.o", env=env)

    with CPPEnv() as cpp:
        main = cpp.compile_and_link([main_h], [main_a], main_cpp)

    # Compilation workaround - the ar becomes meaningless for another build in a different container.
    finalize_build()
Beispiel #16
0
def generate_wiring(
    program: _DynamicStructBuilder,
    excluded_body_tags: List[object] = None,
    preferred_body_tags: List[object] = None
):
    """Creates the wiring of the nodes defined in a program.

    Parameters
    ----------
    program: _DynamicStructBuilder
        A Deltaflow serialized graph.
    excluded_body_tags : typing.List[object]
        typing.List of keys to exclude from selection
    preferred_body_tags : typing.List[object]
        typing.List of keys to be preferred for selection if available

    Returns
    -------
    node_bodies: list
        The bodies of the extracted nodes.
    node_inits: list
        All the ROM files found in the migen nodes, extracted as strings.
        This solves an incompatibility between some migen generated outputs
        and verilator.
    wiring: dict
        The graph wiring, used to generate a SystemC top
        level to wire the graph.
    """
    node_headers = []
    node_bodies = []
    node_modules = []
    node_objects = []
    node_inits = []
    exclusions = excluded_body_tags if excluded_body_tags is not None else []
    preferred = preferred_body_tags if preferred_body_tags is not None else []
    verilated_o = None

    exclusions = set(excluded_body_tags if excluded_body_tags is not None else [])
    preferred = set(preferred_body_tags if preferred_body_tags is not None else [])

    selected_node_bodies = []
    for node in program.nodes:
        body_id = None
        if node.bodies:
            # If there are no node.bodies then it is what was previously
            # called a template node and cannot be pythonated

            not_excluded_list = []
            for body_id in node.bodies:
                # If body has no excluded tag
                body_tags = set(dill.loads(program.bodies[body_id].tags))
                if not exclusions & body_tags:
                    not_excluded_list.append(body_id)

            if not_excluded_list:
                for body_id in not_excluded_list:
                    # If body has a preferred tag
                    body_tags = set(dill.loads(program.bodies[body_id].tags))
                    if preferred & body_tags:
                        break  # use the first body_id where there is a match
                else:
                    body_id = not_excluded_list[0]
            else:
                raise AttributeError(
                    f"All usable bodies for node '{node.name}' have been excluded!"
                )

            which_body = program.bodies[body_id].which()

            if which_body in ['python', 'interactive']:
                with PythonatorEnv(program.bodies) as env:
                    build_artifacts = env.pythonate(node, body_id)
                    node_headers.append(build_artifacts["h"])
                    if "py" in build_artifacts:
                        node_bodies.append(build_artifacts["py"])
                    node_modules.append(build_artifacts["cpp"])
                    node_objects.append(build_artifacts["o"])

            elif which_body == 'migen':
                # This part is adopted from initial-example:
                top_v = BuildArtifact(
                    name=f"{node.name}.v",
                    data=program.bodies[body_id].migen.verilog.encode("utf8")
                )

                with VerilatorEnv() as env:
                    build_artifacts = env.verilate(top_v)

                node_headers.append(build_artifacts["h"])
                node_modules.append(build_artifacts["cpp"])
                node_objects.append(build_artifacts["ALL.a"])
                node_inits += build_artifacts["init"]
                if not verilated_o:
                    verilated_o = build_artifacts["verilated.o"]

        selected_node_bodies.append(body_id)

    with WiringEnv(program.nodes,
                   selected_node_bodies,
                   program.bodies,
                   node_headers,
                   node_objects,
                   verilated_o,
                   program.name) as env:
        wiring = env.wiring(program.graph)

    return node_bodies, node_inits, wiring