Commit 56b77300 authored by Jens Korinth's avatar Jens Korinth
Browse files

Merge branch '2018.1' into pe-local-memories

parents a2ce13bb 76275656
# create a dictionary of compatible VLNVs
source $::env(TAPASCO_HOME)/common/common_ip.tcl
#source $::env(TAPASCO_HOME)/common/common_ip.tcl
dict set stdcomps dualdma vlnv "esa.informatik.tu-darmstadt.de:user:dual_dma:1.10"
# create a dictionary of compatible VLNVs
source $::env(TAPASCO_HOME)/common/common_ip.tcl
#source $::env(TAPASCO_HOME)/common/common_ip.tcl
dict set stdcomps dualdma vlnv "esa.informatik.tu-darmstadt.de:user:dual_dma:1.11"
......@@ -48,42 +48,147 @@ foreach script [list @@TCL_FILES@@] { source $script }
# find top
set top [lindex [find_top] 0]
# synthesize and optimize netlist
synth_design \
-part @@PART@@ \
-top $top \
-mode out_of_context \
-directive AlternateRoutability \
-retiming \
-fanout_limit 400 \
-fsm_extraction one_hot \
-keep_equivalent_registers \
-resource_sharing off \
-no_lc \
-shreg_min_size 5
# read switching activity files (if any)
foreach saif [glob -nocomplain *.saif] {
read_saif $saif
# set parameters
set opt @@OPTIMIZATION@@
set target_opt @@OPTIMIZATION@@
set period @@PERIOD@@
set target_period @@PERIOD@@
if {@@OPTIMIZATION@@ == 42} {
# activate opt and period loops
set opt 3
set target_opt 0
set period 0.5
set target_period 10.0
}
# write design checkpoint
write_checkpoint -force @@SYNTH_CHECKPOINT@@
# set clock
set clock_ports [get_ports -filter {DIRECTION == IN && (NAME =~ *clk* || NAME =~ *CLK* || NAME =~ clock)}]
puts "clock_ports = $clock_ports"
create_clock -name clk -period @@PERIOD@@ $clock_ports
set_property HD.CLK_SRC BUFGCTRL_X0Y0 $clock_ports
# place and route
opt_design
place_design
phys_opt_design
route_design
set results_file [open [file join [file dirname "@@REPORT_TIMING@@"] "synthesis_results.tsv"] "w+"]
puts $results_file "TT\tTF\t\O\tWNS\tOT\tOF"
set runtimes_file [open [file join [file dirname "@@REPORT_TIMING@@"] "synthesis_runtimes.tsv"] "w+"]
puts $runtimes_file "TT\tTF\tO\tP\tS\t\E\tD"
#for {set period 0.5} {$period <= 5.0} {set period [expr $period + 0.125]} {
for {} {$period <= $target_period} {set period [expr $period + 0.25]} {
for {} {$opt >= $target_opt} {incr opt -1} {
set synth_start [clock seconds]
set synth_options [list @@SYNTH_OPTIONS@@]
lappend synth_options {-part} {@@PART@@} {-top} $top {-mode} {out_of_context}
# synthesize and optimize netlist
if {$opt >= 1} {
lappend synth_options {-retiming} {-fanout_limit} 400 {-shreg_min_size} 5
}
if {$opt >= 2} {
lappend synth_options {-fsm_extraction} {one_hot} {-flatten_hierarchy} {full}
}
if {$opt >= 3} {
lappend synth_options {-keep_equivalent_registers} {-resource_sharing} {off} {-no_lc}
}
synth_design {*}$synth_options
set opt_start [clock seconds]
opt_design -propconst -sweep -remap
set synth_finish [clock seconds]
set ur [file join [file dirname "@@REPORT_UTILIZATION@@"] "synth_utilization_period${period}_opt${opt}.rpt"]
puts "writing utilization report $ur ..."
report_utilization -quiet -file $ur
set tr [file join [file dirname "@@REPORT_TIMING@@"] "synth_timing_period${period}_opt${opt}.rpt"]
puts "writing timing report summary $tr ..."
report_timing_summary -quiet -file $tr
puts "synth_design for O$opt took [expr $synth_finish - $opt_start] sec, opt_design took [expr $opt_start - $synth_finish] sec."
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\tsynth_design\t$synth_start\t$opt_start\t[expr $opt_start - $synth_start]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\topt_design\t$opt_start\t$synth_finish\t[expr $synth_finish - $opt_start]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\ttotal_synth\t$synth_start\t$synth_finish\t[expr $synth_finish - $synth_start]"
# read switching activity files (if any)
foreach saif [glob -nocomplain *.saif] {
read_saif $saif
}
# write design checkpoint
#write_checkpoint -force "@@SYNTH_CHECKPOINT@@.O${opt}_P${period}.dcp"
# set clock
set clock_ports [get_ports -filter {DIRECTION == IN && (NAME =~ *clk* || NAME =~ *CLK* || NAME =~ clock)}]
puts "clock_ports = $clock_ports"
create_clock -name clk -period $period $clock_ports
set pnr_start [clock seconds]
# place and route
set opt_directive "RuntimeOptimized"
if {$opt >= 1} { set opt_directive "Default" }
if {$opt >= 2} { set opt_directive "Explore" }
if {$opt >= 3} { set opt_directive "ExploreWithRemap" }
puts "running opt_design -directive $opt_directive ..."
opt_design -directive $opt_directive
set opt_design_finish [clock seconds]
set place_directive "RuntimeOptimized"
if {$opt >= 1} { set place_directive "Default" }
if {$opt >= 2} { set place_directive "Explore" }
if {$opt >= 3} { set place_directive "ExtraTimingOpt" }
puts "running place_design -directive $place_directive ..."
place_design -directive $place_directive
set place_design_finish [clock seconds]
set physopt1_directive "RuntimeOptimized"
if {$opt >= 1} { set physopt1_directive "Explore" }
if {$opt >= 2} { set physopt1_directive "AggressiveExplore" }
if {$opt >= 3} { set physopt1_directive "AlternateFlowWithRetiming" }
puts "running phys_opt_design -directive $physopt1_directive ..."
phys_opt_design -directive $physopt1_directive
set physopt1_finish [clock seconds]
set route_directive "RuntimeOptimized"
if {$opt >= 1} { set route_directive "Default" }
if {$opt >= 2} { set route_directive "Explore" }
if {$opt >= 3} { set route_directive "MoreGlobalIterations" }
puts "running route_design -directive $route_directive ..."
route_design -directive $route_directive
set route_design_finish [clock seconds]
set physopt2_directive "Explore"
if {$opt >= 2} { set physopt2_directive "AggressiveExplore" }
if {$opt >= 3} { set physopt1_directive "AlternateFlowWithRetiming" }
if {$opt >= 2} {
puts "phys_opt_design -directive $physopt2_directive ..."
phys_opt_design -directive $physopt2_directive
set physopt2_finish [clock seconds]
}
set pnr_finish [clock seconds]
# report timing
set tr [file join [file dirname "@@REPORT_TIMING@@"] "pnr_timing_period${period}_opt${opt}.rpt"]
report_timing_summary -quiet -datasheet -file $tr
# report utilization
report_utilization -quiet -file [file join [file dirname "@@REPORT_UTILIZATION@@"] "pnr_utilization_period${period}_opt${opt}.rpt"]
set wns [tapasco::get_wns_from_timing_report $tr]
set clk [expr "$period - $wns"]
# write design checkpoint
#write_checkpoint -force "@@IMPL_CHECKPOINT@@.O${opt}_P${period}.dcp"
puts "O$opt RESULT: WNS = $wns PERIOD = $clk F = [expr 1000.0 / $clk]"
puts $results_file "$period\t[expr 1000.0/$period]\t$opt\t$wns\t$clk\t[expr 1000.0/$clk]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\tpnr_opt_design\t$pnr_start\t$opt_design_finish\t[expr $opt_design_finish - $pnr_start]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\tplace_design\t$opt_design_finish\t$place_design_finish\t[expr $place_design_finish - $opt_design_finish]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\tphys_opt_design\t$place_design_finish\t$physopt1_finish\t[expr $physopt1_finish - $place_design_finish]"
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\troute_design\t$physopt1_finish\t$route_design_finish\t[expr $route_design_finish - $physopt1_finish]"
if {$opt >= 2} {
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\tphys_opt_design2\t$route_design_finish\t$physopt2_finish\t[expr $physopt2_finish - $route_design_finish]"
}
puts $runtimes_file "$period\t[expr 1000.0/$period]\t$opt\ttotal_pnr\t$pnr_start\t$pnr_finish\t[expr $pnr_finish - $pnr_start]"
flush $runtimes_file
flush $results_file
}
if {$opt < 0} { set opt 3 }
}
# write design checkpoint
write_checkpoint -force @@IMPL_CHECKPOINT@@
close $runtimes_file
close $results_file
# report timing
report_timing_summary -quiet -datasheet -file @@REPORT_TIMING@@
......@@ -93,7 +198,7 @@ report_utilization -quiet -file @@REPORT_UTILIZATION@@
# recalculate achieved frequency and set new period (for realistic power values)
set wns [tapasco::get_wns_from_timing_report @@REPORT_TIMING@@]
if {$wns < 0} {
create_clock -name clk -period [expr "@@PERIOD@@ - $wns"] $clock_ports
create_clock -name clk -period [expr "$period - $wns"] $clock_ports
}
# report power
......
......@@ -113,7 +113,13 @@ object EvaluateIP {
/** Perform the evaluation.
* @return true if successful **/
def apply(zipFile: Path, targetPeriod: Double, targetPart: String, reportFile: Path)(implicit cfg: Configuration): Boolean = {
def apply(zipFile: Path,
targetPeriod: Double,
targetPart: String,
reportFile: Path,
optimization: Int,
synthOptions: Option[String] = None)
(implicit cfg: Configuration): Boolean = {
def deleteOnExit(f: java.io.File) = f.deleteOnExit
//def deleteOnExit(f: java.io.File) = f // keep files?
......@@ -123,7 +129,7 @@ object EvaluateIP {
// define report filenames
Files.createDirectories(reportFile.getParent)
val files = new Files(zipFile, reportFile)
writeTclScript(files, targetPart, targetPeriod)
writeTclScript(files, targetPart, targetPeriod, optimization, synthOptions)
val lt = new LogTrackingFileWatcher(Some(logger))
cfg.verbose foreach { _ => lt += files.logFile }
......@@ -139,7 +145,7 @@ object EvaluateIP {
// execute Vivado (max runtime: 1d)
val r = InterruptibleProcess(Process(vivadoCmd, files.baseDir.toFile),
waitMillis = Some(24 * 60 * 60 * 1000)).!(io)
waitMillis = Some((if (optimization == 42) 14 else 1) * 24 * 60 * 60 * 1000)).!(io)
cfg.verbose foreach { _ => lt.closeAll }
......@@ -171,7 +177,11 @@ object EvaluateIP {
* @param targetPart Part identifier of the target FPGA.
* @param targetPeriod Target operating period.
**/
private def writeTclScript(files: Files, targetPart: String, targetPeriod: Double): Unit = {
private def writeTclScript(files: Files,
targetPart: String,
targetPeriod: Double,
optimization: Int,
synthOptions: Option[String]): Unit = {
val needles: scala.collection.mutable.Map[String, String] = scala.collection.mutable.Map(
"SRC_FILES" -> (files.hdl_files map (_.toString) mkString " "),
"TCL_FILES" -> (files.tcl_files mkString " "),
......@@ -184,7 +194,9 @@ object EvaluateIP {
"REPORT_POWER" -> files.rpt_power.toString,
"SYNTH_CHECKPOINT" -> files.s_dcp.toString,
"IMPL_CHECKPOINT" -> files.i_dcp.toString,
"NETLIST" -> files.netlist.toString
"NETLIST" -> files.netlist.toString,
"OPTIMIZATION" -> optimization.toString,
"SYNTH_OPTIONS" -> (synthOptions getOrElse "")
)
// write Tcl script
......
......@@ -52,7 +52,8 @@ object Import {
* @param skipEval Do not perform out-of-context synthesis for resource estimation (optional).
* @param cfg Implicit [[base.Configuration]].
**/
def apply(zip: Path, id: Kernel.Id, t: Target, acc: Option[Int], skipEval: Option[Boolean])
def apply(zip: Path, id: Kernel.Id, t: Target, acc: Option[Int], skipEval: Option[Boolean],
optimization: Int, synthOptions: Option[String] = None)
(implicit cfg: Configuration): Boolean = {
// get VLNV from the file
val vlnv = VLNV.fromZip(zip)
......@@ -70,7 +71,7 @@ object Import {
// write core.json to output directory (as per config)
val p = cfg.outputDir(c, t).resolve("ipcore").resolve("core.json")
importCore(c, t, p, vlnv, skipEval)
importCore(c, t, p, vlnv, skipEval, optimization, synthOptions)
}
/**
......@@ -82,7 +83,8 @@ object Import {
* @param skipEval Skip out-of-context synthesis step (optional).
* @param cfg Implicit [[Configuration]].
**/
private def importCore(c: Core, t: Target, p: Path, vlnv: VLNV, skipEval: Option[Boolean])
private def importCore(c: Core, t: Target, p: Path, vlnv: VLNV, skipEval: Option[Boolean], optimization: Int,
synthOptions: Option[String])
(implicit cfg: Configuration): Boolean = {
Files.createDirectories(p.getParent)
logger.trace("created output directories: {}", p.getParent.toString)
......@@ -107,7 +109,7 @@ object Import {
}
// evaluate the ip core and store the report with the link
val res = skipEval.getOrElse(false) || evaluateCore(c, t)
val res = skipEval.getOrElse(false) || evaluateCore(c, t, optimization = optimization, synthOptions = synthOptions)
// write core.json
logger.debug("writing core description: {}", p.toString)
......@@ -120,11 +122,14 @@ object Import {
* place-and-route to produce area and Fmax estimates and the netlist.
* @param c Core description.
* @param t Target Architecture + Platform combination.
* @param optimization Positive integer optimization level.
* @param synthOptions Optional arguments for synth_design.
* @param cfg Implicit [[Configuration]].
**/
private def evaluateCore(c: Core, t: Target)(implicit cfg: Configuration): Boolean = {
private def evaluateCore(c: Core, t: Target, optimization: Int, synthOptions: Option[String] = None)
(implicit cfg: Configuration): Boolean = {
logger.trace("looking for SynthesisReport ...")
val period = 0.5
val period = 1.0
val report = cfg.outputDir(c, t).resolve("ipcore").resolve("%s_export.xml".format(c.name))
FileAssetManager.reports.synthReport(c.name, t) map { hls_report =>
logger.trace("found existing synthesis report: " + hls_report)
......@@ -134,7 +139,7 @@ object Import {
true
} getOrElse {
logger.info("SynthesisReport for {} not found, starting evaluation ...", c.name)
EvaluateIP(c.zipPath, period, t.pd.part, report)
EvaluateIP(c.zipPath, period, t.pd.part, report, optimization, synthOptions)
}
}
}
......@@ -90,9 +90,10 @@ class MultiFileWatcher(pollInterval: Int = MultiFileWatcher.POLL_INTERVAL) exten
_waitingFor.synchronized { _waitingFor -= p }
}
@scala.annotation.tailrec
private def readFrom(br: BufferedReader, ls: Seq[String] = Seq()): Seq[String] = {
val line = Option(br.readLine())
if (line.nonEmpty) readFrom(br, ls :+ line.get) else ls
val line = scala.util.Try(Option(br.readLine())).toOption.flatten
if (line.isEmpty) ls else readFrom(br, ls :+ line.get)
}
private def startWatchThread: Unit = {
......
......@@ -68,7 +68,7 @@ class CorePanelController extends {
val path = java.nio.file.Paths.get(ImportFileChooser.selectedFile.toString)
val tasks = for {
t <- Job.job.targets
} yield new ImportTask(path, t, 1, b => cores.update())(Config.configuration) // FIXME missing ID, clock cycles, skip eval
} yield new ImportTask(path, t, 1, b => cores.update(), None, None, None, 2)(Config.configuration) // FIXME missing ID, clock cycles, skip eval
tasks foreach (TaskScheduler.apply _)
}
}
......
......@@ -64,8 +64,10 @@ object JobExamples {
Some("Optional description of the core."),
Some(13124425),
Some(true),
Some("-retiming"),
Some(Seq("axi4mm")),
Some(Seq("zedboard", "zc706")))
Some(Seq("zedboard", "zc706")),
Some(3))
val jobs: Seq[Job] = Seq(bulkImportJob, composeJob, coreStatisticsJob, dseJob, hlsJob, importJob)
......
......@@ -226,8 +226,10 @@ final case class HighLevelSynthesisJob(
* @param description Description of the core (optional).
* @param averageClockCycles Clock cycles in an average job (optional).
* @param skipEvaluation Do not perform evaluation (optional).
* @param synthOptions Optional parameters for synth_design.
* @param _architectures Name list of [[base.Architecture]] instances.
* @param _platforms Name list of [[base.Platform]] instances.
* @param _optimization Positive integer optimization level.
**/
final case class ImportJob(
zipFile: Path,
......@@ -235,8 +237,10 @@ final case class ImportJob(
description: Option[String] = None,
averageClockCycles: Option[Int] = None,
skipEvaluation: Option[Boolean] = None,
synthOptions: Option[String] = None,
private val _architectures: Option[Seq[String]] = None,
private val _platforms: Option[Seq[String]] = None) extends Job("import") {
private val _platforms: Option[Seq[String]] = None,
private val _optimization: Option[Int] = None) extends Job("import") {
/** Returns the list of [[base.Architecture]] instances selected in this job. */
def architectures: Set[Architecture] =
FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)
......@@ -244,6 +248,9 @@ final case class ImportJob(
/** Returns the list of [[base.Platform]] instances selected in this job. */
def platforms: Set[Platform] =
FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)
/** Returns the optimization level. */
def optimization: Int = _optimization getOrElse 0
}
object BulkImportJob extends Builds[BulkImportJob]
......
......@@ -52,7 +52,7 @@ private object BulkImport extends Executor[BulkImportJob] {
a <- j.architectures
p <- j.platforms
t = Target(a, p)
} yield new ImportTask(j.zipFile, t, j.id, _ => signal.release(), j.averageClockCycles)(cfg)
} yield new ImportTask(j.zipFile, t, j.id, _ => signal.release(), j.averageClockCycles, None, None, 2)(cfg)
importTasks foreach { tsk.apply _ }
......
......@@ -70,7 +70,7 @@ protected object HighLevelSynthesis extends Executor[HighLevelSynthesisJob] {
if (avgCC.isEmpty && k.testbenchFiles.length > 0) {
logger.warn("executed HLS with co-sim for {}, but no co-simulation report was found", k)
}
Some(new ImportTask(zip, t, k.id, _ => signal.release(), avgCC)(cfg))
Some(new ImportTask(zip, t, k.id, _ => signal.release(), avgCC, None, None, 2)(cfg))
}
case _ => None
}
......
......@@ -51,7 +51,7 @@ object Import extends Executor[ImportJob] {
val tasks = jobs map { case (j, t) =>
val avgCC = FileAssetManager.reports.cosimReport(VLNV.fromZip(j.zipFile).name, t) map (_.latency.avg)
new ImportTask(j.zipFile, t, j.id, _ => signal.release(), avgCC, j.skipEvaluation)(cfg)
new ImportTask(j.zipFile, t, j.id, _ => signal.release(), avgCC, j.skipEvaluation, None, j.optimization)(cfg)
}
tasks foreach { tsk.apply _ }
......
......@@ -55,8 +55,10 @@ package object json {
(JsPath \ "Description").readNullable[String] ~
(JsPath \ "Average Clock Cycles").readNullable[Int] (verifying[Int](_ > 0)) ~
(JsPath \ "Skip Evaluation").readNullable[Boolean] ~
(JsPath \ "Synth Options").readNullable[String] ~
(JsPath \ "Architectures").readNullable[Seq[String]] ~
(JsPath \ "Platforms").readNullable[Seq[String]]
(JsPath \ "Platforms").readNullable[Seq[String]] ~
(JsPath \ "Optimization").readNullable[Int] (verifying[Int](_ >= 0))
) (ImportJob.apply _)
implicit val importJobWrites: Writes[ImportJob] = (
......@@ -66,8 +68,10 @@ package object json {
(JsPath \ "Description").writeNullable[String] ~
(JsPath \ "Average Clock Cycles").writeNullable[Int] ~
(JsPath \ "Skip Evaluation").writeNullable[Boolean] ~
(JsPath \ "Synth Options").writeNullable[String] ~
(JsPath \ "Architectures").writeNullable[Seq[String]] ~
(JsPath \ "Platforms").writeNullable[Seq[String]]
(JsPath \ "Platforms").writeNullable[Seq[String]] ~
(JsPath \ "Optimization").writeNullable[Int]
) (unlift(ImportJob.unapply _ andThen (_ map ("Import" +: _))))
/* ImportJob @} */
......
......@@ -37,7 +37,7 @@ private object ImportParser {
private val jobid = identity[ImportJob] _
private def options: Parser[ImportJob => ImportJob] =
(description | avgClockCycles | skipEval | architectures | platforms).rep map (opts =>
(description | avgClockCycles | skipEval | architectures | platforms | synthOptions | optimization).rep map (opts =>
(opts map (applyOption _) fold jobid) (_ andThen _))
private def description: Parser[(String, String)] =
......@@ -50,12 +50,20 @@ private object ImportParser {
private def skipEval: Parser[(String, Boolean)] =
(longOption("skipEvaluation", "SkipEval") ~ ws) map { case s => (s, true) }
private def synthOptions: Parser[(String, String)] =
longOption("synthOptions", "SynthOptions") ~ ws ~/ qstring.opaque("additional synth_design options as string") ~ ws
private def optimization: Parser[(String, Int)] =
longOption("optimization", "Optimization") ~ ws ~/ posint.opaque("positive integer optimization level") ~ ws
private def applyOption(opt: (String, _)): ImportJob => ImportJob = opt match {
case ("Description", d: String) => _.copy(description = Some(d))
case ("AvgCC", cc: Int) => _.copy(averageClockCycles = Some(cc))
case ("SkipEval", se: Boolean) => _.copy(skipEvaluation = Some(se))
case ("SynthOptions", so: String) => _.copy(synthOptions = Some(so))
case ("Architectures", as: Seq[String @unchecked]) => _.copy(_architectures = Some(as))
case ("Platforms", ps: Seq[String @unchecked]) => _.copy(_platforms = Some(ps))
case ("Optimization", lvl: Int) => _.copy(_optimization = Some(lvl))
case o => throw new Exception(s"parsed illegal option: $o")
}
}
......@@ -46,7 +46,9 @@ class ImportTask(val zip: Path,
val id: Kernel.Id,
val onComplete: Boolean => Unit,
val averageClockCycles: Option[Int] = None,
val skipEvaluation: Option[Boolean] = None)
val skipEvaluation: Option[Boolean] = None,
val synthOptions: Option[String] = None,
val optimization: Int)
(implicit val cfg: Configuration) extends Task with LogTracking {
private implicit val logger = de.tu_darmstadt.cs.esa.tapasco.Logging.logger(getClass)
private val name = try { Some(VLNV.fromZip(zip).name) } catch { case _: Throwable => None }
......@@ -59,7 +61,7 @@ class ImportTask(val zip: Path,
val appender = LogFileTracker.setupLogFileAppender(_logFile.toString)
logger.trace("current thread name: {}", Thread.currentThread.getName())
logger.info(description)
val result = activity.Import(zip, id, t, averageClockCycles, skipEvaluation)
val result = activity.Import(zip, id, t, averageClockCycles, skipEvaluation, optimization, synthOptions)
LogFileTracker.stopLogFileAppender(appender)
result
}
......
......@@ -46,11 +46,23 @@ private object ImportParserSpec {
Gen.posNum[Int] map (_.toString)
))
val synthOptionsGen: Gen[String] = join(Seq(
genLongOption("synthOptions"),
qstringGen
))
val optimizationGen: Gen[String] = join(Seq(
genLongOption("optimization"),
Gen.posNum[Int] map (_.toString)
))
val optionGen: Gen[String] = Gen.oneOf(
descriptionGen,
avgClockCyclesGen,
architecturesGen,
platformsGen
platformsGen,
synthOptionsGen,
optimizationGen
)
val optionsGen: Gen[String] = for {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment