def get_template(self, name): """Get template name from filesystem (first local, then repo).""" if shutil2.exists(shutil2.join(self.dir, "templates", name)): return shutil2.join(self.dir, "templates", name) else: return shutil2.join(self.impl.repo, "templates", name)
def export_sw(args, swdir, link): prj = args.prj swdir = swdir if swdir is not None else prj.basedir + ".sw" log.info("Export software to project directory '" + prj.dir + "'") dictionary = {} dictionary["NAME"] = prj.name.lower() dictionary["CFLAGS"] = prj.impl.cflags dictionary["LDFLAGS"] = prj.impl.ldflags dictionary["LDLIBS"] = prj.impl.ldlibs dictionary["NUM_SLOTS"] = prj.shuffler.slots dictionary["DEVICE"] = "zynqmp" if "xczu" in prj.impl.part else "zynq" srcs = shutil2.join(prj.dir, "src", "application") dictionary["SOURCES"] = [srcs] log.info("Generating export files ...") templ = "artico3_app_" + prj.impl.os prj.apply_template(templ, dictionary, swdir, link) dictionary = {} dictionary["REPO_REL"] = shutil2.relpath(prj.impl.repo, swdir) dictionary["OBJS"] = [{ "Source": shutil2.trimext(_) + ".o" } for _ in shutil2.listfiles(swdir, True, "c[p]*$") if "artico3" not in _] template.preproc(shutil2.join(swdir, "Makefile"), dictionary, "overwrite", force=True)
def _export_hw(prj, hwdir, link): ''' Generates a Vivado project using TCL scripts. It first compiles the configuration dictionary and then processes the templates according to the configuration dictionary. hwdir gives the name of the project directory link boolean; if true files will be linked instead of copied ''' hwdir = hwdir if hwdir is not None else prj.basedir + ".hw" log.info("Export hardware to directory '" + hwdir + "'") dictionary = get_dict(prj) log.info("Generating export files...") tmpl = "ref_" + prj.impl.os + "_" + "_".join(prj.impl.board) + "_" + prj.impl.design + "_" + prj.impl.xil[0] + "_" + prj.impl.xil[1] if not shutil2.isdir(shutil2.join(prj.impl.repo, "templates", tmpl)): log.error("Template directory not found") sys.exit(1) print("[A3DK] Using template directory " + tmpl) prj.apply_template(tmpl, dictionary, hwdir, link) log.info("Generating ARTICo\u00b3 kernels...") for kernel in prj.kerns: export_hw_kernel(prj, shutil2.join(hwdir, "pcores"), link, kernel.name) print("[A3DK] Calling TCL script to generate Vivado IP Repository") try: # NOTE: for some reason, using the subprocess module as in the # original RDK does not work (does not recognize source and, # therefore, Vivado is not started). subprocess.run(""" bash -c "source /opt/Xilinx/Vivado/{1}/settings64.sh && cd {0} && vivado -mode batch -notrace -nojournal -nolog -source create_ip_library.tcl" """.format(hwdir, prj.impl.xil[1]), shell=True, check=True) except: log.error("Generation of Vivado IP repository failed (check .cfg for unkown components)") sys.exit(1) print("[A3DK] Calling TCL script to generate ARTICo\u00b3 system in Vivado IP Integrator") try: # NOTE: for some reason, using the subprocess module as in the # original RDK does not work (does not recognize source and, # therefore, Vivado is not started). subprocess.run(""" bash -c "source /opt/Xilinx/Vivado/{1}/settings64.sh && cd {0} && vivado -mode batch -notrace -nojournal -nolog -source export.tcl -tclargs -proj_name myARTICo3 -proj_path ." """.format(hwdir, prj.impl.xil[1]), shell=True, check=True) except: log.error("Could not generate design in Vivado IP Integrator") sys.exit(1)
def prefile(filepath, dictionary): old = shutil2.basename(filepath) reg = r"<a3<(?P<key>[A-Za-z0-9_]+)>a3>" def repl(m): if m.group("key") in dictionary: return str(dictionary[m.group("key")]) else: return m.string[m.start():m.end()] new = re.sub(reg, repl, old) if (new != old): old = shutil2.join(shutil2.dirname(filepath), old) new = shutil2.join(shutil2.dirname(filepath), new) if shutil2.exists(new): shutil2.rmtree(new) shutil2.rename(old, new)
def _parse_shuffler(self): """Parses ARTICo\u00b3 Shuffler configuration.""" # Get current template tmpl = "ref_" + self.impl.os + "_" + "_".join(self.impl.board) + "_" + self.impl.design + "_" + self.impl.xil[0] + "_" + self.impl.xil[1] # Get configuration file for current template filepath = shutil2.join(self.impl.repo, "templates", tmpl, "artico3.cfg") a3cfg = configparser.RawConfigParser() a3cfg.optionxform = str ret = a3cfg.read(filepath) if not ret: log.error("ARTICo\u00b3 config file '" + filepath + "' not found") sys.exit(1) # Assign configuration self.shuffler.slots = int(a3cfg.get("Shuffler", "Slots")) self.shuffler.stages = int(a3cfg.get("Shuffler", "PipeDepth")) self.shuffler.clkbuf = a3cfg.get("Shuffler", "ClkBuffer") self.shuffler.rstbuf = a3cfg.get("Shuffler", "RstBuffer")
def _export_hw_kernel(prj, hwdir, link, kernel): ''' Generates sources for one ARTICo\u00b3 Kernel in Vivado. It checks whether vhdl or hls sources shall be used and generates the hardware accelerator from the source templates. hwdir gives the name of the project directory link boolean; if true files will be linked instead of copied kernel is the name of the hardware accelerator to generate ''' hwdir = hwdir if hwdir is not None else prj.basedir + ".hw" + "." + kernel.lower() log.info("Exporting kernel " + kernel + " to directory '" + hwdir + "'") kerns = [_ for _ in prj.kerns if _.name == kernel] if (len(kerns) == 1): kernel = kerns[0] if kernel.hwsrc is None: log.info("No hardware source specified") else: log.error("Kernel '" + kernel + "' not found") return if (kernel.hwsrc == "vhdl") or (kernel.hwsrc == "verilog"): dictionary = {} dictionary["NAME"] = kernel.name.lower() dictionary["HWSRC"] = kernel.hwsrc dictionary["RST_POL"] = kernel.rstpol dictionary["NUMREGS"] = kernel.regs dictionary["MEMBYTES"] = kernel.membytes dictionary["MEMBANKS"] = kernel.membanks dictionary["REGS"] = [] for i in range(kernel.regs): d = {} d["rid"] = i dictionary["REGS"].append(d) dictionary["PORTS"] = [] for i in range(kernel.membanks): d = {} d["pid"] = i dictionary["PORTS"].append(d) src = shutil2.join(prj.dir, "src", "a3_" + kernel.name.lower(), kernel.hwsrc) dictionary["SOURCES"] = [src] incl = shutil2.listfiles(src, True) dictionary["INCLUDES"] = [{"File": shutil2.trimext(_)} for _ in incl] log.info("Generating export files ...") prj.apply_template("artico3_kernel_hdl_pcore", dictionary, hwdir, link) elif kernel.hwsrc == "hls": tmp = tempfile.TemporaryDirectory() dictionary = {} dictionary["PART"] = prj.impl.part dictionary["NAME"] = kernel.name.lower() dictionary["HWSRC"] = kernel.hwsrc dictionary["MEMBYTES"] = kernel.membytes src = shutil2.join(prj.dir, "src", "a3_" + kernel.name.lower(), kernel.hwsrc) dictionary["SOURCES"] = [src] files = shutil2.listfiles(src, True) dictionary["FILES"] = [{"File": _} for _ in files] # Get info from user defined ports with open(shutil2.join(src, kernel.name.lower()) + ".cpp") as fp: data = fp.read() reg = r"A3_KERNEL\((?P<ports>[^\)]+)\)" match = re.search(reg, data) aux = match.group("ports") aux = re.sub(r"[\n\r]", "", aux) # Remove line breaks aux = re.sub(r"\s{2,}", " ", aux) # Replace more than 2 spaces with 1 aux = re.sub(r"a3\w+_t ", "", aux) # Remove port tags dictionary["ARGS"] = aux.strip() # Remove heading and trailing spaces # Generate list with sorted input/output ports # # NOTE: in order to comply with bank orderings (especially # relevant for DMA transfers), memory ports are sorted # in alphabetical order and then arranged as C-I-IO-O. # argsC = [] argsI = [] argsO = [] argsIO = [] argsR = [] for arg in match.group("ports").split(","): if "a3const_t" in arg.split(): argsC.append(arg.split()) if "a3in_t" in arg.split(): argsI.append(arg.split()) if "a3out_t" in arg.split(): argsO.append(arg.split()) if "a3inout_t" in arg.split(): argsIO.append(arg.split()) if "a3reg_t" in arg.split(): argsR.append(arg.split()) argsI.sort() argsO.sort() argsIO.sort() argsM = argsC + argsI + argsIO + argsO; argsR.sort() dictionary["REGS"] = [] for i in range(len(argsR)): d = {} d["rname"] = argsR[i][1] d["rid"] = i dictionary["REGS"].append(d) dictionary["PORTS"] = [] for i in range(len(argsM)): d = {} d["pname"] = argsM[i][1] d["pid"] = i dictionary["PORTS"].append(d) # Get info from register numbers and check consistency dictionary["NUMREGS"] = len(dictionary["REGS"]) if dictionary["NUMREGS"] != kernel.regs: log.warning("Inconsistent use of Regs (.cfg) and A3_KERNEL (.cpp), will generate run-time errors") # Get info from the number of memory elements in each bank dictionary["MEMBANKS"] = len(dictionary["PORTS"]) if dictionary["MEMBANKS"] != kernel.membanks: log.warning("Inconsistent use of MemBanks (.cfg) and A3_KERNEL (.cpp), will generate run-time errors") dictionary["MEMPOS"] = int((kernel.membytes / kernel.membanks) / 4) log.info("Generating temporary HLS project in " + tmp.name + " ...") prj.apply_template("artico3_kernel_hls_build", dictionary, tmp.name) #~ # Fix header file (parser generates excesive \n that need to be removed) #~ with open(shutil2.join(tmp.name, "artico3.h")) as fp: #~ data = fp.read() #~ def repl(match): #~ return ",\\\n" + match.group("data") #~ reg = r",\\[\n]+(?P<data>\s*uint32_t values\))" #~ data = re.sub(reg, repl, data, 0, re.DOTALL) #~ with open(shutil2.join(tmp.name, "artico3.h"), "w") as fp: #~ fp.write(data) #~ # DEBUG #~ with open(shutil2.join(tmp.name, "artico3.h")) as fp: #~ data = fp.read() #~ print(data) #~ sys.exit(1) #~ # END DEBUG log.info("Starting Vivado HLS ...") # NOTE: for some reason, using the subprocess module as in the # original RDK does not work (does not recognize source and, # therefore, Vivado is not started). subprocess.run(""" bash -c "source /opt/Xilinx/Vivado/{1}/settings64.sh && cd {0} && vivado_hls -f csynth.tcl" """.format(tmp.name, prj.impl.xil[1]), shell=True, check=True) src = shutil2.join(tmp.name, "a3_kernel", "sol", "syn", "vhdl") dictionary["SOURCES"] = [src] incl = shutil2.listfiles(src, True) dictionary["INCLUDES"] = [{"File": shutil2.trimext(_)} for _ in incl] log.info("Generating export files ...") prj.apply_template("artico3_kernel_hdl_pcore", dictionary, hwdir) path = shutil2.join(hwdir, "a3_" + kernel.name.lower() + "_v1_00_a", "hls") shutil2.rmtree(path) shutil2.mkdir(path) shutil2.copytree(tmp.name, path)