| """ | |
| This module provides a structure to define the fuzz environment | |
| """ | |
| import os | |
| from os import path | |
| from string import Template | |
| import diamond | |
| class FuzzConfig: | |
| def __init__(self, job, family, device, tiles, ncl, mapargs=None): | |
| """ | |
| :param job: user-friendly job name, used for folder naming etc | |
| :param family: Target family name | |
| :param device: Target device name | |
| :param tiles: List of tiles to consider during fuzzing | |
| :param ncl: Minimal NCL file to use as a base for interconnect fuzzing | |
| """ | |
| self.job = job | |
| self.family = family | |
| self.device = device | |
| self.tiles = tiles | |
| self.ncl = ncl | |
| self.ncd_specimen = None | |
| self.mapargs = mapargs | |
| @property | |
| def workdir(self): | |
| return path.join(".", "work", self.job) | |
| def make_workdir(self): | |
| """Create the working directory for this job, if it doesn't exist already""" | |
| os.makedirs(self.workdir, exist_ok=True) | |
| def setup(self, skip_specimen=False): | |
| """ | |
| Create a working directory, and run Diamond on a minimal ncl file to create a ncd/prf for Tcl usage | |
| """ | |
| self.make_workdir() | |
| if not skip_specimen: | |
| self.build_design(self.ncl, {}) | |
| def build_design(self, des_template, substitutions, prefix="", no_trce=True, backanno=False, substitute=True): | |
| """ | |
| Run Diamond on a given design template, applying a map of substitutions, plus some standard substitutions | |
| if not overriden. | |
| :param des_template: path to template NCL/Verilog file | |
| :param substitutions: dictionary containing template subsitutions to apply to NCL/Verilog file | |
| :param prefix: prefix to append to filename, for running concurrent jobs without collisions | |
| Returns the path to the output bitstream | |
| """ | |
| subst = dict(substitutions) | |
| if "route" not in subst: | |
| subst["route"] = "" | |
| if "sysconfig" not in subst: | |
| subst["sysconfig"] = "" | |
| ext = des_template.split(".")[-1] | |
| lpf_template = des_template.replace("." + ext, ".lpf") | |
| prf_template = des_template.replace("." + ext, ".prf") | |
| desfile = path.join(self.workdir, prefix + "design." + ext) | |
| bitfile = path.join(self.workdir, prefix + "design.bit") | |
| lpffile = path.join(self.workdir, prefix + "design.lpf") | |
| prffile = path.join(self.workdir, prefix + "design.prf") | |
| if path.exists(bitfile): | |
| os.remove(bitfile) | |
| with open(des_template, "r") as inf: | |
| with open(desfile, "w") as ouf: | |
| if substitute: | |
| ouf.write(Template(inf.read()).substitute(**subst)) | |
| else: | |
| ouf.write(inf.read()) | |
| if path.exists(lpf_template): | |
| with open(lpf_template, "r") as inf: | |
| with open(lpffile, "w") as ouf: | |
| if substitute: | |
| ouf.write(Template(inf.read()).substitute(**subst)) | |
| else: | |
| ouf.write(inf.read()) | |
| if path.exists(prf_template): | |
| with open(prf_template, "r") as inf: | |
| with open(prffile, "w") as ouf: | |
| ouf.write(Template(inf.read()).substitute(**subst)) | |
| diamond.run(self.device, desfile, no_trce=no_trce, backanno=backanno, mapargs=self.mapargs) | |
| if ext == "ncl" and self.ncd_specimen is None: | |
| self.ncd_specimen = path.join(self.workdir, prefix + "design.tmp", "par_impl.ncd") | |
| return bitfile | |
| @property | |
| def ncd_prf(self): | |
| """ | |
| A (ncd, prf) file tuple for Tcl. build_design must have been run at least once prior to accessing this property | |
| """ | |
| assert self.ncd_specimen is not None | |
| prf = self.ncd_specimen.replace("par_impl.ncd", "synth_impl.prf") | |
| return self.ncd_specimen, prf |