Beispiel #1
0
    def extract_data_step(self):
        """
        Step 4: Extract either VCD or DAT information from run.
        """
        # switch later stages based on whether we are outputing vcd or mem files
        extract = Step(SourceType.Nothing)
        if self.vcd:

            def f(_inp, ctx):
                f = (Path(ctx["tmpdir"]) / "output.vcd").open("rb")
                return (Source(f, SourceType.File), None, 0)

            extract.set_func(f, "Read output.vcd.")
        else:

            def f(_inp, ctx):
                # Simulated 91 cycles
                r = re.search(r"Simulated (\d+) cycles",
                              _inp.data.read().decode("ascii"))
                data = {
                    "cycles": int(r.group(1)),
                    "memories": convert2json(ctx["tmpdir"], "out"),
                }
                buf = BytesIO(
                    json.dumps(data, indent=2, sort_keys=True).encode("UTF-8"))
                return (Source(buf, SourceType.File), None, 0)

            extract.set_func(f, "Convert output memories to json.")

        return extract
Beispiel #2
0
    def _output_dir(self, steps):
        # output directory
        output = Step(SourceType.Nothing)

        def f(_, ctx):
            return (Source(ctx["tmpdir_obj"], SourceType.TmpDir), None, 0)

        output.set_func(f, "Output synthesis directory.")
        steps.append(output)
Beispiel #3
0
    def cleanup_step(self):
        """
        Step 5: Cleanup the temporary directory
        """
        cleanup = Step(SourceType.File)

        def f(inp, ctx):
            ctx["tmpdir_obj"].cleanup()
            return (inp, None, 0)

        cleanup.set_func(f, "Cleanup tmp directory.")

        return cleanup
Beispiel #4
0
    def _define(self):
        # extract
        extract = Step(SourceType.Nothing)

        def f(inp, _):
            res = None
            if inp.source_type == SourceType.TmpDir:
                res = futil_extract(Path(inp.data.name))
            else:
                res = futil_extract(Path(inp.data))
            return (Source(BytesIO(res.encode("UTF-8")), SourceType.File), None, 0)

        extract.set_func(f, "Extract information.")

        return [extract]
Beispiel #5
0
    def _establish_connection(self, steps):
        # maybe establish ssh connection
        if self.use_ssh:
            ssh_connection = Step(SourceType.Nothing)

            def f(inp, ctx):
                if self.use_ssh:
                    ssh = self.ssh_client()
                    ssh.load_system_host_keys()
                    ssh.connect(self.ssh_host, username=self.ssh_user)
                    ctx["ssh_client"] = ssh
                return (inp, None, 0)

            ssh_connection.set_func(f, "Connect to server over SSH")
            steps.append(ssh_connection)
Beispiel #6
0
    def mktmp_step(self):
        """
        Step 1: Make a temporary directory.
        """
        # Step 1: Make a new temporary directory.
        mktmp = Step(SourceType.Nothing)

        def f(inp, ctx):
            tmpdir = TemporaryDirectory()
            ctx["tmpdir"] = tmpdir.name
            ctx["tmpdir_obj"] = tmpdir
            return (inp, None, 0)

        mktmp.set_func(f, "Make temporary directory.")

        return mktmp
Beispiel #7
0
    def _mktmp(self, steps):
        # make temporary directory
        mktmp = Step(SourceType.Nothing)

        def f(inp, ctx):
            if self.use_ssh:
                _, stdout, _ = ctx["ssh_client"].exec_command("mktemp -d")
                tmpdir = stdout.read().decode("ascii").strip()
                ctx["tmpdir"] = tmpdir
            else:
                tmpdir = TemporaryDirectory()
                ctx["tmpdir"] = tmpdir.name
                ctx["tmpdir_obj"] = tmpdir
            return (inp, None, 0)

        mktmp.set_func(f, "Make temporary directory.")
        steps.append(mktmp)
Beispiel #8
0
    def _run_vivado(self, steps):
        vivado = Step(SourceType.Path)
        if self.use_ssh:

            def f(inp, ctx):
                _, stdout, _ = ctx["ssh_client"].exec_command(
                    " ".join(
                        [
                            f"cd {ctx['tmpdir']}",
                            "&&",
                            "vivado -mode batch -source synth.tcl",
                        ]
                    )
                )
                for chunk in iter(lambda: stdout.readline(2048), ""):
                    logging.debug(chunk.strip())

                return (inp, None, 0)

            ssh_addr = f"{self.ssh_user}@{self.ssh_host}"
            vivado.set_func(
                f,
                " ".join(
                    [
                        f"ssh {ssh_addr} 'cd {{ctx[tmpdir]}}",
                        "&&",
                        "vivado -mode batch -source synth.tcl'",
                    ]
                ),
            )
        else:
            vivado.set_cmd(
                " ".join(
                    [
                        "cd {ctx[tmpdir]}",
                        "&&",
                        "vivado -mode batch -source synth.tcl >&2",
                    ]
                )
            )
        steps.append(vivado)
Beispiel #9
0
    def _run_vivado_hls(self, steps):
        vivado_hls = Step(SourceType.Path)
        if self.use_ssh:

            def f(inp, ctx):
                _, stdout, _ = ctx["ssh_client"].exec_command(
                    f'cd {ctx["tmpdir"]} && vivado_hls -f hls.tcl'
                )
                for chunk in iter(lambda: stdout.readline(2048), ""):
                    logging.debug(chunk.strip())

                return (inp, None, 0)

            ssh_addr = f"{self.ssh_user}@{self.ssh_host}"
            vivado_hls.set_func(
                f, f'ssh {ssh_addr} cd {{ctx["tmpdir"]}} && vivado_hls -f hls.tcl'
            )
        else:
            vivado_hls.set_cmd(
                " ".join(["cd {ctx[tmpdir]}", "&&", "vivado_hls -f hls.tcl >&2"])
            )
        steps.append(vivado_hls)
Beispiel #10
0
    def _move_files(self, steps, device_files, src_file):
        # copy over files
        move = Step(SourceType.Path)
        if self.use_ssh:

            def f(inp, ctx):
                with self.scp_client(ctx["ssh_client"].get_transport()) as scp:
                    scp.put(device_files, remote_path=ctx["tmpdir"])
                    scp.put(inp.data,
                            remote_path=f'{ctx["tmpdir"]}/{src_file}')
                return (inp, None, 0)

            move.set_func(f, "Copy synth files over SCP.")
        else:
            move.set_cmd(" ".join([
                "cp",
                " ".join(device_files),
                "{ctx[tmpdir]}",
                "&&",
                f"cp {{ctx[input_path]}} {{ctx[tmpdir]}}/{src_file}",
            ]))
        steps.append(move)
Beispiel #11
0
    def _finalize_ssh(self, steps):
        if self.use_ssh:
            copy = Step(SourceType.Nothing)

            def f(inp, ctx):
                if self.use_ssh:
                    tmpdir = TemporaryDirectory()
                    with self.scp_client(
                            ctx["ssh_client"].get_transport()) as scp:
                        scp.get(ctx["tmpdir"],
                                local_path=f"{tmpdir.name}",
                                recursive=True)
                        ctx["old_tmpdir"] = ctx["tmpdir"]
                        ctx["tmpdir"] = tmpdir.name
                        ctx["tmpdir_obj"] = tmpdir
                    return (inp, None, 0)

            copy.set_func(f, "Copy files back.")
            steps.append(copy)

            close_ssh = Step(SourceType.Nothing)

            def f(inp, ctx):
                if self.use_ssh:
                    ctx["ssh_client"].exec_command(f'rm -r {ctx["tmpdir"]}')
                    ctx["ssh_client"].close()
                return (inp, None, 0)

            close_ssh.set_func(f, "Close SSH")
            steps.append(close_ssh)

            restructure_tmp = Step(SourceType.Nothing)
            restructure_tmp.set_cmd(" ".join([
                "mv {ctx[tmpdir]}/tmp.*/* {ctx[tmpdir]}",
                "&&",
                "rm -r {ctx[tmpdir]}/tmp.*",
            ]))
            steps.append(restructure_tmp)
Beispiel #12
0
    def json_to_dat_step(self):
        """
        Step 2: Transform data from JSON to Dat.
        """
        data = Step(SourceType.Path)
        data_path = self.config["stages", self.name, "data"]

        def f(inp, ctx):
            if data_path is None:
                with open(inp.data, "r") as verilog_src:
                    # the verilog expects data, but none has been provided
                    if "readmemh" in verilog_src.read():
                        raise errors.MissingDynamicConfiguration(
                            "verilog.data")
                    ctx["data_prefix"] = ""
            else:
                with open(data_path) as f:
                    convert2dat(ctx["tmpdir"], json.load(f), "dat")
                    ctx["data_prefix"] = f'DATA={ctx["tmpdir"]}'
            return (inp, None, 0)

        data.set_func(f, "Convert json data to directory of .dat files.")

        return data
Beispiel #13
0
    def _define(self):
        mktmp = Step(SourceType.Nothing)

        def f(inp, ctx):
            tmpdir = TemporaryDirectory()
            ctx['tmpdir'] = tmpdir.name
            ctx['tmpdir_obj'] = tmpdir
            return (inp, None, 0)

        mktmp.set_func(f, "Make temporary directory.")

        data = Step(SourceType.Path)
        data_path = self.config['stages', self.name, 'data']

        def f(inp, ctx):
            if data_path is None:
                with open(inp.data, 'r') as verilog_src:
                    # the verilog expects data, but none has been provided
                    if 'readmemh' in verilog_src.read():
                        raise errors.MissingDynamicConfiguration(
                            'verilog.data')
                    ctx['data_prefix'] = ''
            else:
                with open(data_path) as f:
                    convert2dat(ctx['tmpdir'], json.load(f), 'dat')
                    ctx['data_prefix'] = f'DATA={ctx["tmpdir"]}'
            return (inp, None, 0)

        data.set_func(f, "Convert json data to directory of .dat files.")

        verilator = Step(SourceType.Path)
        testbench_files = [
            str(
                Path(self.config['global', 'futil_directory']) / 'fud' /
                'sim' / 'testbench.cpp'),
            str(
                Path(self.config['global', 'futil_directory']) / 'fud' /
                'sim' / 'wrapper.cpp'),
        ]
        verilator.set_cmd(" ".join([
            self.cmd,
            '-cc',
            # Don't trace if we're only looking at memory outputs
            '--trace',
            '{ctx[input_path]}',
            "--exe " + " --exe ".join(testbench_files),
            '--top-module main',  # TODO: make this use dynamic config
            '--Mdir',
            '{ctx[tmpdir]}',
            '1>&2'
        ]))

        make = Step(SourceType.Nothing)
        make.set_cmd("make -j -C {ctx[tmpdir]} -f Vmain.mk Vmain 1>&2")

        run = Step(SourceType.Nothing)
        run.set_cmd(" ".join([
            '{ctx[data_prefix]}', '{ctx[tmpdir]}/Vmain',
            '{ctx[tmpdir]}/output.vcd',
            str(self.cycle_limit), '--trace' if self.vcd else '', '1>&2'
        ]))

        # switch later stages based on whether we are outputing vcd or mem files
        extract = Step(SourceType.Nothing)
        if self.vcd:

            def f(_inp, ctx):
                f = (Path(ctx['tmpdir']) / 'output.vcd').open('rb')
                return (Source(f, SourceType.File), None, 0)

            extract.set_func(f, "Read output.vcd.")
        else:

            def f(_inp, ctx):
                mem = convert2json(ctx['tmpdir'], 'out')
                buf = BytesIO(
                    json.dumps(mem, indent=2, sort_keys=True).encode('UTF-8'))
                return (Source(buf, SourceType.File), None, 0)

            extract.set_func(f, "Convert output memories to json.")

        cleanup = Step(SourceType.File)

        def f(inp, ctx):
            ctx['tmpdir_obj'].cleanup()
            return (inp, None, 0)

        cleanup.set_func(f, "Cleanup tmp directory.")

        return [mktmp, data, verilator, make, run, extract, cleanup]