From 69b63d93da766cfd6acd465500b423a475b33bba Mon Sep 17 00:00:00 2001 From: Johannes Wirth Date: Thu, 2 Oct 2025 12:46:32 +0200 Subject: [PATCH] Update file handling and descriptions --- .../com/minres/tgc/hammer/FileUtils.scala | 23 ++++++++++++++++ .../scala/com/minres/tgc/hammer/Global.scala | 2 ++ .../minres/tgc/hammer/cli/CoreSelection.scala | 2 +- .../minres/tgc/hammer/cli/HammerConf.scala | 15 +++-------- .../tgc/hammer/cli/LongnailSchedCommand.scala | 18 ++++++++----- .../minres/tgc/hammer/cli/MySubcommand.scala | 4 +-- .../tgc/hammer/cli/TreenailCommand.scala | 15 ++++++----- .../tgc/hammer/options/CommandGroup.scala | 3 +-- .../tgc/hammer/options/OptionGroup.scala | 2 -- .../com/minres/tgc/hammer/tasks/Task.scala | 3 --- .../tasks/longnail/SchedulingParameters.scala | 27 ++++++++++--------- 11 files changed, 66 insertions(+), 48 deletions(-) diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/FileUtils.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/FileUtils.scala index a19fb1c..237f2dd 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/FileUtils.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/FileUtils.scala @@ -1,6 +1,10 @@ package com.minres.tgc.hammer +import org.rogach.scallop.{ValueConverter, listArgConverter, singleArgConverter} import os.* +import Global.* + +import scala.collection.IterableOps object FileUtils { def changeExtension(path: os.Path, newExt: String): os.Path = { @@ -8,4 +12,23 @@ object FileUtils { val newName = s"$baseName.$newExt" path / os.up / newName } + + extension (x: String) + def asPath(relative: Path): Path = { + Path(x, relative) + } + def path(): Path = asPath(BASE_DIR) + + extension [T <: Iterable](x: IterableOps[String, T, T[String]]) + def asPath(relative: Path): T[Path] = { + x.map(_.asPath(relative)) + } + def path(): T[Path] = asPath(BASE_DIR) + + implicit val osPathRelBaseConverter: ValueConverter[Path] = { + singleArgConverter[Path](_.asPath(BASE_DIR)) + } + implicit val osPathRelBaseListConverter: ValueConverter[List[Path]] = { + listArgConverter[Path](_.asPath(BASE_DIR)) + } } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/Global.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/Global.scala index ef42a50..1e72418 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/Global.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/Global.scala @@ -1,5 +1,6 @@ package com.minres.tgc.hammer +import com.minres.tgc.hammer.FileUtils.* import os.Path object Global { @@ -9,5 +10,6 @@ object Global { lazy val TREENAIL: Path = HAMMER / "deps" / "treenail" lazy val LONGNAIL: Path = HAMMER / "deps" / "longnail" lazy val BASE_DIR: Path = os.pwd + lazy val OUT_DIR: Path = Main.conf.outputDirectory() lazy val CORE_DATASHEETS: Path = HAMMER / "coreDatasheets" } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/CoreSelection.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/CoreSelection.scala index 599c38b..6dbb977 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/CoreSelection.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/CoreSelection.scala @@ -4,7 +4,7 @@ import com.minres.tgc.hammer.Global.CORE_DATASHEETS import org.rogach.scallop.* trait CoreSelection { this: MySubcommand => - val core: ScallopOption[String] = opt[String](group = mainGroup) + val core: ScallopOption[String] = opt[String](group = mainGroup, required = true, descr = "The core to be extended; core datasheets are in coreDatasheets/") def getCoreDatasheet: os.Path = CORE_DATASHEETS / s"$core.yaml" } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/HammerConf.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/HammerConf.scala index 79656bd..7010035 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/HammerConf.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/HammerConf.scala @@ -1,22 +1,13 @@ package com.minres.tgc.hammer.cli -import com.minres.tgc.hammer.Global -import org.rogach.scallop.{ScallopConf, ScallopOption, ValueConverter, fileConverter, listArgConverter, singleArgConverter} +import org.rogach.scallop.* import os.Path - -import java.io.File +import com.minres.tgc.hammer.FileUtils.* class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) { + val outputDirectory: ScallopOption[Path] = opt[Path](default = Some("output".path()), descr = "The base output directory") addSubcommand(new TreenailCommand) addSubcommand(new LongnailSchedCommand) verify() } - -implicit val osPathConverter: ValueConverter[os.Path] = { - singleArgConverter[os.Path](os.Path(_, Global.BASE_DIR)) -} - -implicit val osPathListConverter: ValueConverter[List[os.Path]] = { - listArgConverter[os.Path](os.Path(_, Global.BASE_DIR)) -} diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/LongnailSchedCommand.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/LongnailSchedCommand.scala index 4046386..2ca2f2e 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/LongnailSchedCommand.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/LongnailSchedCommand.scala @@ -1,18 +1,22 @@ package com.minres.tgc.hammer.cli -import com.minres.tgc.hammer.FileUtils.changeExtension +import com.minres.tgc.hammer.FileUtils.* +import com.minres.tgc.hammer.Global.* import com.minres.tgc.hammer.tasks.longnail.{LongnailMergeTask, LongnailScheduleTask} import com.minres.tgc.hammer.tasks.{Task, TreenailTask} import com.minres.tgc.hammer.tasks.longnail.SchedulingParameters -import org.rogach.scallop.ScallopOption +import org.rogach.scallop.* import os.Path class LongnailSchedCommand extends MySubcommand("scheduleISAX") with CoreSelection { - val inputFiles: ScallopOption[List[Path]] = trailArg[List[Path]]("inputFiles", group = mainGroup) - val outputDirectory: ScallopOption[Path] = opt[Path](group = mainGroup) + val inputFiles: ScallopOption[List[Path]] = trailArg[List[Path]]("inputFiles", group = mainGroup, descr = "One or multiple input files; Both .core_desc as well as .mlir are supported (also mixed)") val schedParams: SchedulingParameters = addConfigElement(new SchedulingParameters) - validateOSPathIsDirectory(outputDirectory) + + banner( + """Generate Scheduling information for the provided ISAXes using Longnail + |Usage: tgc-hammer scheduleISAX -c VexRiscv isax.core_desc + |""".stripMargin) override def getRequiredTasks: Seq[Task] = { val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc") @@ -21,8 +25,8 @@ class LongnailSchedCommand extends MySubcommand("scheduleISAX") with CoreSelecti if (allMlirFiles.size == 1) { treenailTasks :+ LongnailScheduleTask(allMlirFiles.head, getCoreDatasheet, schedParams) } else { - val mergedInput = outputDirectory() / "merged.mlir" - val concatInput = outputDirectory() / "concat.mlir" + val mergedInput = OUT_DIR / "merged.mlir" + val concatInput = OUT_DIR / "concat.mlir" treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, mergedInput) :+ LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams) } } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/MySubcommand.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/MySubcommand.scala index 61ce6e5..20b05f8 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/MySubcommand.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/MySubcommand.scala @@ -1,10 +1,10 @@ package com.minres.tgc.hammer.cli -import com.minres.tgc.hammer.options.{BaseOption, ConfigElement, OptionGroup} +import com.minres.tgc.hammer.options.ConfigElement import com.minres.tgc.hammer.tasks.Task import org.rogach.scallop.{ScallopOption, ScallopOptionGroup, Subcommand, Util} -import java.nio.file.{Files, Path} +import java.nio.file.Files abstract class MySubcommand(name: String) extends Subcommand(name) { protected val mainGroup: ScallopOptionGroup = group() diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/TreenailCommand.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/TreenailCommand.scala index 30a25fa..e2c0a90 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/cli/TreenailCommand.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/cli/TreenailCommand.scala @@ -1,21 +1,22 @@ package com.minres.tgc.hammer.cli -import com.minres.tgc.hammer.Global +import com.minres.tgc.hammer.FileUtils.* import com.minres.tgc.hammer.tasks.{Task, TreenailTask} import org.rogach.scallop.* - -import java.io.File import os.Path class TreenailCommand extends MySubcommand("parseCoreDSL") { - val coreDSL: ScallopOption[File] = trailArg[File]("coreDSL") - val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some(os.Path("isax.mlir", Global.BASE_DIR))) + val coreDSL: ScallopOption[Path] = trailArg[Path]("coreDSL", descr = "The .core_desc input file to be converted") + val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("isax.mlir".path()), descr = "The .mlir file containing the converted ISAX") - validateFileIsFile(coreDSL) + banner( + """Parse a CoreDSL input using Treenail into the MLIR representation + |Usage: tgc-hammer parseCoreDSL -o isax.mlir isax.core_desc + |""".stripMargin) override def getRequiredTasks: Seq[Task] = { Seq( - new TreenailTask(Path(coreDSL(), os.pwd), Path(output(), os.pwd)) + TreenailTask(coreDSL(), output()) ) } } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/options/CommandGroup.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/options/CommandGroup.scala index a82ad6d..80ebcfe 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/options/CommandGroup.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/options/CommandGroup.scala @@ -5,8 +5,7 @@ import os.Shellable class CommandGroup(name: String) extends BaseGroup { override def getToolParameters: Seq[Shellable] = { - val sub = options.toSeq.map(_.getToolParameters.flatMap(_.value).mkString("=")).filter(!_.isEmpty) - println(sub) + val sub = options.toSeq.map(_.getToolParameters.flatMap(_.value).mkString("=")).filter(_.nonEmpty) Seq(s"$name=\'${sub.mkString(" ")}\'") } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/options/OptionGroup.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/options/OptionGroup.scala index ee37ea0..87fbdc8 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/options/OptionGroup.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/options/OptionGroup.scala @@ -6,8 +6,6 @@ import os.Shellable import scala.collection.mutable -export com.minres.tgc.hammer.cli.osPathConverter - trait BaseGroup extends ConfigElement { protected val options = mutable.ListBuffer[ConfigElement]() protected def add[T <: ConfigElement](option: T): T = { diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/Task.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/Task.scala index 9aca0ea..648945f 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/Task.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/Task.scala @@ -7,9 +7,6 @@ trait Task { def execute(): Unit def runExecutable(execPath: Path, args: Shellable*): os.CommandResult = { - println(s"Executing $execPath with") - println(args.flatMap(_.value).mkString(" ")) - println(args) val command = s"$execPath ${args.flatMap(_.value).mkString(" ")}" os.proc("bash", "-c", command).call(stdout = os.Inherit) } diff --git a/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/longnail/SchedulingParameters.scala b/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/longnail/SchedulingParameters.scala index 5deb0c5..4133a36 100644 --- a/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/longnail/SchedulingParameters.scala +++ b/toolflow/src/main/scala/com/minres/tgc/hammer/tasks/longnail/SchedulingParameters.scala @@ -1,27 +1,30 @@ package com.minres.tgc.hammer.tasks.longnail +import com.minres.tgc.hammer.FileUtils.* +import com.minres.tgc.hammer.Global.OUT_DIR import com.minres.tgc.hammer.options.* -import os.Path import org.rogach.scallop.* +import os.Path class SchedulingParameters extends OptionGroup { override def name: String = "Longnail Scheduling Args" add(new CommandGroup("--prepare-schedule-lil") { - choiceS(Seq("LEGACY", "MS", "PAMS", "PARAMS", "MI_MS", "MI_PAMS", "MI_PARAMS"), name = "schedulingAlgo", default = Some("LEGACY")) - value[Path](cliName = "cellLibrary", toolName = "library") - valueS[Path](name = "opTyLibrary") + choiceS(Seq("LEGACY", "MS", "PAMS", "PARAMS", "MI_MS", "MI_PAMS", "MI_PARAMS"), name = "schedulingAlgo", default = Some("LEGACY"), descr = + "Scheduling algorithm used by Longnail; Modulo Scheduling (MS) can be extended with Predicate-aware (PA) and Resource-aware (RA), Inter-Instruction sharing is activated in the MI variants") + value[Path](cliName = "cellLibrary", toolName = "library", descr = "The cell library used by Longnail (example: longnail/test/LILToHW/longnail*.yaml") + valueS[Path](name = "opTyLibrary", descr = "The operator type model used for detailed data (e.g. from OL SKY130 in longnail/opTyLibraries/OL2.yaml)") }) add(new CommandGroup("--schedule-lil") { - valueS[Int](name = "schedulingTimeout") - value[Int](cliName = "schedulingRefineTimeout", toolName = "schedRefineTimeout") - value[Path](cliName = "schedulingKconf", toolName = "solSelKconfPath") - choice(Seq("CBC", "GLPK", "SCIP", "HIGHS", "GUROBI", "CPLEX", "XPRESS", "COPT"), cliName = "ilpSolver", toolName = "solver", default = Some("CBC")) - toggle(cliName = "verboseSched", toolName = "verbose") - value[Int](cliName = "clockPeriod", toolName = "clockTime") + valueS[Int](name = "schedulingTimeout", default = Some(10), descr = "Longnail scheduling timeout in seconds") + value[Int](cliName = "schedulingRefineTimeout", toolName = "schedRefineTimeout", default = Some(10), descr = "Longnail schedule refinement timeout in seconds") + value[Path](cliName = "schedulingKconf", toolName = "solSelKconfPath", default = Some(OUT_DIR / "scheduling.KConfig"), descr = "Path for the created KConfig file for selecting a scheduling solution") + choice(Seq("CBC", "GLPK", "SCIP", "HIGHS", "GUROBI", "CPLEX", "XPRESS", "COPT"), cliName = "ilpSolver", toolName = "solver", default = Some("CBC"), descr = "The ILP solver used by Longnail; currently only CBC is tested") + toggle(cliName = "verboseSched", toolName = "verbose", descr = "Enable verbose ILP solver messages") + value[Int](cliName = "clockPeriod", toolName = "clockTime", descr = "The target clock period; uses same time unit as delays in opTyLibrary") }) - value[Int](cliName = "--maxLoopUnrollFactor", toolName = "max-unroll-factor") - value[Path](cliName = "--schedulingMLIR", toolName = "o") + value[Int](cliName = "--maxLoopUnrollFactor", toolName = "max-unroll-factor", default = Some(16), descr = "Longnail max loop unroll factor") + value[Path](cliName = "--schedulingMLIR", toolName = "o", default = Some(OUT_DIR / "scheduling_solutions.mlir"), descr = "Output file with different scheduling solutions") }