UNPKG

@specs-feup/clava

Version:

A C/C++ source-to-source compiler written in Typescript

190 lines (157 loc) 5.31 kB
import Clava from "../Clava.js"; import ProcessExecutor from "@specs-feup/lara/api/lara/util/ProcessExecutor.js"; import VitisHlsReportParser from "./VitisHlsReportParser.js"; import Tool from "@specs-feup/lara/api/lara/tool/Tool.js"; import ToolUtils from "@specs-feup/lara/api/lara/tool/ToolUtils.js"; import Io from "@specs-feup/lara/api/lara/Io.js"; export default class VitisHls extends Tool { topFunction: string; platform: string; clock!: number; vitisDir: string = "VitisHLS"; vitisProjName: string = "VitisHLSClavaProject"; sourceFiles: string[] = []; flowTarget: "vitis" | "vivado" = "vivado"; constructor( topFunction: string, clock: number = 10, platform: string = "xcvu5p-flva2104-1-e", disableWeaving: boolean = false ) { super("VITIS-HLS", disableWeaving); this.topFunction = topFunction; this.platform = platform; this.setClock(clock); } setTopFunction(topFunction: string) { this.topFunction = topFunction; return this; } setPlatform(platform: string) { this.platform = platform; return this; } setClock(clock: number) { if (clock <= 0) { throw new Error( `${this.getTimestamp()} Clock value must be a positive integer!` ); } else { this.clock = clock; } return this; } setFlowTarget(target: "vitis" | "vivado") { this.flowTarget = target; return this; } addSource(file: string) { this.sourceFiles.push(file); return this; } private getTimestamp() { const curr = new Date(); const res = `[${ this.toolName } ${curr.getHours()}:${curr.getMinutes()}:${curr.getSeconds()}]`; return res; } synthesize(verbose: boolean = true) { console.log(`${this.getTimestamp()} Setting up Vitis HLS executor`); this.clean(); this.generateTclFile(); this.executeVitis(verbose); return Io.isFile(this.getSynthesisReportPath()); } clean() { Io.deleteFolderContents(this.vitisDir); } private getSynthesisReportPath() { return ( this.vitisDir + "/" + this.vitisProjName + "/solution1/syn/report/csynth.xml" ); } private executeVitis(verbose: boolean) { console.log(`${this.getTimestamp()} Executing Vitis HLS`); const pe = new ProcessExecutor(); pe.setWorkingDir(this.vitisDir); pe.setPrintToConsole(verbose); pe.execute("vitis_hls", "-f", "script.tcl"); console.log(`${this.getTimestamp()} Finished executing Vitis HLS`); } private getTclInputFiles() { let str = ""; const weavingFolder = ToolUtils.parsePath(Clava.getWeavingFolder()); // make sure the files are woven Io.deleteFolderContents(weavingFolder); Clava.writeCode(weavingFolder); // if no files were added, we assume that every woven file should be used if (this.sourceFiles.length == 0) { console.log( `${this.getTimestamp()} No source files specified, assuming current AST is the input` ); for (const file of Io.getFiles(Clava.getWeavingFolder())) { const exts = [".c", ".cpp", ".h", ".hpp"]; const res = exts.some((ext) => file.name.includes(ext)); if (res) str += "add_files " + weavingFolder + "/" + file.name + "\n"; } } else { for (const file of this.sourceFiles) { str += "add_files " + weavingFolder + "/" + file + "\n"; } } return str; } private generateTclFile() { const cmd = ` open_project ${this.vitisProjName} set_top ${this.topFunction} ${this.getTclInputFiles()} open_solution "solution1" -flow_target ${this.flowTarget} set_part { ${this.platform}} create_clock -period ${this.clock} -name default csynth_design exit `; Io.writeFile(this.vitisDir + "/script.tcl", cmd); } getSynthesisReport() { console.log(`${this.getTimestamp()} Processing synthesis report`); const parser = new VitisHlsReportParser(this.getSynthesisReportPath()); const json = parser.getSanitizedJSON(); console.log(`${this.getTimestamp()} Finished processing synthesis report`); return json; } preciseStr(n: number, decimalPlaces?: number) { return (+n).toFixed(decimalPlaces); } prettyPrintReport( report: ReturnType<VitisHlsReportParser["getSanitizedJSON"]> ) { const period = this.preciseStr(report["clockEstim"], 2); const freq = this.preciseStr(report["fmax"], 2); const out = ` ---------------------------------------- Vitis HLS synthesis report Targeted a ${report["platform"]} with target clock ${freq} ns Achieved an estimated clock of ${period} ns (${freq} MHz) Estimated latency for top function ${report["topFun"]}: Worst case: ${report["latencyWorst"]} cycles Avg case: ${report["latencyAvg"]} cycles Best case: ${report["latencyBest"]} cycles Estimated execution time: Worst case: ${report["execTimeWorst"]} s Avg case: ${report["execTimeAvg"]} s Best case: ${report["execTimeBest"]} s Resource usage: FF: ${report["FF"]} (${this.preciseStr(report["perFF"] * 100, 2)}%) LUT: ${report["LUT"]} (${this.preciseStr(report["perLUT"] * 100, 2)}%) BRAM: ${report["BRAM"]} (${this.preciseStr(report["perBRAM"] * 100, 2)}%) DSP: ${report["DSP"]} (${this.preciseStr(report["perDSP"] * 100, 2)}%) ----------------------------------------`; console.log(out); } }