blob: 1ef2b6cf19ed06da06ae06249a28b8e440905289 [file] [log] [blame]
"""
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