Compare commits
18 Commits
47614ad47f
...
main
Author | SHA1 | Date | |
---|---|---|---|
25c93b8a73 | |||
4dcb6efcef | |||
420e50f23a | |||
6c7e7f496b | |||
44ab3f4622 | |||
2738df3bff | |||
80c9d458b4 | |||
1b450758d3 | |||
7954a9dbe3 | |||
3824dd4d29 | |||
32e626a5a1 | |||
e6f3474fd9 | |||
5218ed37b1 | |||
3d981d16ed | |||
9d0c71dedd | |||
3858761e66 | |||
be691c96be | |||
22a1f31683 |
@@ -1,3 +1,5 @@
|
|||||||
# TGC Hammer
|
# TGC Hammer
|
||||||
|
|
||||||
This is TGC-Hammer, the HLS flow for custom ISA-Extensions.
|
This is the base repo TGC-Hammer, the HLS flow for custom ISA-Extensions. It is used for building the toolflow executable, as well as the various tools (Longnail, SCAIE-V, ...).
|
||||||
|
|
||||||
|
To use it, create a new workspace folder by calling the `init-workspace.sh` script from an empty folder. This will create the base workspace structure, including a README about usage details. The workspace will always use the executables from this repo, so if you rebuild them, the new ones will automatically be used.
|
@@ -29,7 +29,7 @@ else
|
|||||||
echo "export TGC_HAMMER_WORKDIR=\"$PWD\"" >> source.sh
|
echo "export TGC_HAMMER_WORKDIR=\"$PWD\"" >> source.sh
|
||||||
echo "export PATH=\"${TGC_HAMMER_HOME}/toolflow/target/universal/stage/bin:$PATH\"" >> source.sh
|
echo "export PATH=\"${TGC_HAMMER_HOME}/toolflow/target/universal/stage/bin:$PATH\"" >> source.sh
|
||||||
|
|
||||||
echo "source source.sh" > .envrc
|
cp -r ${TGC_HAMMER_HOME}/wsTemplate/. $PWD
|
||||||
|
|
||||||
mkdir -p output
|
mkdir -p output
|
||||||
fi
|
fi
|
@@ -11,5 +11,7 @@ lazy val root = project
|
|||||||
|
|
||||||
libraryDependencies += "org.rogach" %% "scallop" % "5.2.0",
|
libraryDependencies += "org.rogach" %% "scallop" % "5.2.0",
|
||||||
libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.5",
|
libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.5",
|
||||||
|
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.6",
|
||||||
|
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.5.19",
|
||||||
libraryDependencies += "org.scalameta" %% "munit" % "1.2.0" % Test
|
libraryDependencies += "org.scalameta" %% "munit" % "1.2.0" % Test
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package com.minres.tgc.hammer
|
package com.minres.tgc.hammer
|
||||||
|
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
|
||||||
import os.Path
|
import os.Path
|
||||||
|
|
||||||
object Global {
|
object Global {
|
||||||
@@ -10,7 +9,8 @@ object Global {
|
|||||||
lazy val TREENAIL: Path = HAMMER / "deps" / "treenail"
|
lazy val TREENAIL: Path = HAMMER / "deps" / "treenail"
|
||||||
lazy val LONGNAIL: Path = HAMMER / "deps" / "longnail"
|
lazy val LONGNAIL: Path = HAMMER / "deps" / "longnail"
|
||||||
lazy val BASE_DIR: Path = os.pwd
|
lazy val BASE_DIR: Path = os.pwd
|
||||||
lazy val OUT_DIR: Path = Main.conf.outputDirectory()
|
def OUT_DIR: Path = Main.conf.outputDirectory()
|
||||||
lazy val TMP_DIR: Path = OUT_DIR / "tmp"
|
def TMP_DIR: Path = OUT_DIR / "tmp"
|
||||||
|
def LOG_DIR: Path = OUT_DIR / "logs"
|
||||||
lazy val CORE_DATASHEETS: Path = HAMMER / "coreDatasheets"
|
lazy val CORE_DATASHEETS: Path = HAMMER / "coreDatasheets"
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
package com.minres.tgc.hammer
|
package com.minres.tgc.hammer
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level
|
||||||
import com.minres.tgc.hammer.cli.{HammerConf, MySubcommand}
|
import com.minres.tgc.hammer.cli.{HammerConf, MySubcommand}
|
||||||
|
import com.minres.tgc.hammer.util.AssertException
|
||||||
|
import com.typesafe.scalalogging.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
import scala.compiletime.uninitialized
|
import scala.compiletime.uninitialized
|
||||||
|
|
||||||
@@ -8,14 +12,41 @@ object Main {
|
|||||||
var conf: HammerConf = uninitialized
|
var conf: HammerConf = uninitialized
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
|
val logger = Logger("TGCHammer")
|
||||||
conf = new HammerConf(args.toIndexedSeq)
|
conf = new HammerConf(args.toIndexedSeq)
|
||||||
|
|
||||||
|
val logLevel = conf.verbose() match {
|
||||||
|
case 0 => Level.INFO
|
||||||
|
case 1 => Level.INFO
|
||||||
|
case 2 => Level.DEBUG
|
||||||
|
case _ => Level.TRACE
|
||||||
|
}
|
||||||
|
LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[ch.qos.logback.classic.Logger].setLevel(logLevel)
|
||||||
|
|
||||||
|
logger.trace(s"Creating output directory ${Global.OUT_DIR}")
|
||||||
|
if (conf.emptyOutputDir()) os.remove.all(Global.OUT_DIR)
|
||||||
|
os.makeDir.all(Global.OUT_DIR)
|
||||||
|
os.makeDir.all(Global.LOG_DIR)
|
||||||
|
logger.trace(s"Creating temp directory ${Global.TMP_DIR}")
|
||||||
|
os.makeDir.all(Global.TMP_DIR)
|
||||||
conf.subcommand match {
|
conf.subcommand match {
|
||||||
case Some(c: MySubcommand) =>
|
case Some(c: MySubcommand) =>
|
||||||
|
logger.info(s"Executing subcommand ${c.name}")
|
||||||
val tasks = c.getRequiredTasks
|
val tasks = c.getRequiredTasks
|
||||||
tasks.foreach(_.validate())
|
logger.debug(s"Subcommand requires ${tasks.size} tasks")
|
||||||
tasks.foreach(_.execute())
|
try {
|
||||||
|
tasks.foreach(_.run())
|
||||||
|
c.cleanup()
|
||||||
|
} catch {
|
||||||
|
case e: AssertException =>
|
||||||
|
logger.error(s"Error during task execution, see above!")
|
||||||
|
case e: Exception =>
|
||||||
|
logger.error(s"General exception ${e.getMessage}")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
logger.error(s"Found no subcommand, see help below")
|
||||||
|
conf.printHelp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,13 @@ import org.rogach.scallop.*
|
|||||||
|
|
||||||
trait CoreSelection { this: MySubcommand =>
|
trait CoreSelection { this: MySubcommand =>
|
||||||
val core: ScallopOption[String] = opt[String](group = mainGroup, required = true, descr = "The core to be extended; core datasheets are in coreDatasheets/")
|
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"
|
||||||
|
|
||||||
def getCoreDatasheet: os.Path = CORE_DATASHEETS / s"$core.yaml"
|
addValidation {
|
||||||
|
if (os.isFile(getCoreDatasheet)) {
|
||||||
|
Right(())
|
||||||
|
} else {
|
||||||
|
Left(s"Core ${core()} not supported, no core datasheet at ${getCoreDatasheet}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,28 @@
|
|||||||
package com.minres.tgc.hammer.cli
|
package com.minres.tgc.hammer.cli
|
||||||
|
|
||||||
|
import com.minres.tgc.hammer.Global.LOG_DIR
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
import os.Path
|
import os.Path
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
|
|
||||||
class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
||||||
val outputDirectory: ScallopOption[Path] = opt[Path](default = Some("output".path()), descr = "The base output directory")
|
val outputDirectory: ScallopOption[Path] = opt[Path](default = Some("output".path()), descr = "The base output directory")
|
||||||
|
val verbose: ScallopOption[Int] = tally(short = 'v', descr = "Controls the logging of tgc-hammer itself, using it multiple times (-vv) will print more. (0x => WARN, 1x => INFO, 2x => DEBUG, 3x => TRACE)")
|
||||||
|
val emptyOutputDir: ScallopOption[Boolean] = toggle(default = Some(true), descrYes = "Whether to empty the output directory at the start; defaults to true")
|
||||||
|
val printToolOutput: ScallopOption[Boolean] = toggle(descrYes = s"Whether to directly print all output of the underlying tools to the terminal. Otherwise the output will be written to files in `logs` folder in the selected outputDirectory", default = Some(false))
|
||||||
addSubcommand(new LongnailCommand)
|
addSubcommand(new LongnailCommand)
|
||||||
addSubcommand(new TreenailCommand)
|
addSubcommand(new TreenailCommand)
|
||||||
|
addSubcommand(new LongnailMergeCommand)
|
||||||
addSubcommand(new LongnailSchedCommand)
|
addSubcommand(new LongnailSchedCommand)
|
||||||
|
|
||||||
|
banner("""This program offers several subcommands to execute different tasks.
|
||||||
|
|The main subcommand to create the hardware module of an ISAX is `isaxHLS`.
|
||||||
|
|For more information about the several subcommands use `tgc-hammer subcommand --help` with the name of the respective subcommand.
|
||||||
|
|
|
||||||
|
|Usage: tgc-hammer isaxHLS -c VexRiscv --useMinIISolution isax.core_desc
|
||||||
|
|""".stripMargin)
|
||||||
|
|
||||||
|
shortSubcommandsHelp(true)
|
||||||
|
|
||||||
verify()
|
verify()
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,22 @@
|
|||||||
package com.minres.tgc.hammer.cli
|
package com.minres.tgc.hammer.cli
|
||||||
|
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import com.minres.tgc.hammer.Global.*
|
import com.minres.tgc.hammer.Global.*
|
||||||
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
||||||
import com.minres.tgc.hammer.tasks.longnail.{LongnailHLSTask, LongnailMergeTask, LongnailScheduleTask, SchedulingParameters}
|
import com.minres.tgc.hammer.tasks.longnail.{LongnailHLSTask, LongnailMergeTask, LongnailScheduleTask, SchedulingParameters}
|
||||||
|
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
import os.Path
|
import os.Path
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class LongnailCommand extends MySubcommand("isaxHLS") with CoreSelection {
|
class LongnailCommand extends MySubcommand("isaxHLS") with CoreSelection with Logging[LongnailCommand] with ValidationUtils {
|
||||||
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 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 useMinIISolution: ScallopOption[Boolean] = toggle(name = "useMinIISolution", group = mainGroup, default = Some(false), descrYes = "Whether to automatically choose the scheduling solution with the lowest II. If not activated, a manual selection during execution will be required!")
|
val useMinIISolution: ScallopOption[Boolean] = toggle(name = "useMinIISolution", group = mainGroup, default = Some(false), descrYes = "Whether to automatically choose the scheduling solution with the lowest II. If not activated, a manual selection during execution will be required!")
|
||||||
val schedParams: SchedulingParameters = addConfigElement(new SchedulingParameters)
|
val schedParams: SchedulingParameters = addConfigElement(new SchedulingParameters)
|
||||||
|
|
||||||
|
check(inputFiles)(checkPathsIsFile)
|
||||||
|
|
||||||
banner(
|
banner(
|
||||||
"""Run the complete longnail flow from CoreDSL/MLIR to receive a SystemVerilog representation of the ISAXes
|
"""Run the complete longnail flow from CoreDSL/MLIR to receive a SystemVerilog representation of the ISAXes
|
||||||
|Usage: tgc-hammer isaxHLS -c VexRiscv --useMinIISolution isax.core_desc
|
|Usage: tgc-hammer isaxHLS -c VexRiscv --useMinIISolution isax.core_desc
|
||||||
@@ -34,11 +37,17 @@ class LongnailCommand extends MySubcommand("isaxHLS") with CoreSelection {
|
|||||||
tasks += LongnailMergeTask(allMlirFiles, concatInput, mergedInput)
|
tasks += LongnailMergeTask(allMlirFiles, concatInput, mergedInput)
|
||||||
tasks += LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams)
|
tasks += LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams)
|
||||||
}
|
}
|
||||||
|
val verilogOutput = OUT_DIR / "verilog"
|
||||||
|
os.makeDir.all(verilogOutput)
|
||||||
if (useMinIISolution()) {
|
if (useMinIISolution()) {
|
||||||
tasks += LongnailHLSTask(schedParams.schedulingSolutionFile(), None, OUT_DIR)
|
tasks += LongnailHLSTask(schedParams.schedulingSolutionFile(), None, verilogOutput)
|
||||||
} else {
|
} else {
|
||||||
???
|
???
|
||||||
}
|
}
|
||||||
tasks.toSeq
|
tasks.toSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def cleanup(): Unit = {
|
||||||
|
log.info(s"Finished, verilog output in ${OUT_DIR / "verilog"}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,29 +3,41 @@ package com.minres.tgc.hammer.cli
|
|||||||
import com.minres.tgc.hammer.tasks.{CopyTask, Task, TreenailTask}
|
import com.minres.tgc.hammer.tasks.{CopyTask, Task, TreenailTask}
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
import os.Path
|
import os.Path
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import com.minres.tgc.hammer.Global.*
|
import com.minres.tgc.hammer.Global.*
|
||||||
import com.minres.tgc.hammer.tasks.longnail.LongnailMergeTask
|
import com.minres.tgc.hammer.tasks.longnail.LongnailMergeTask
|
||||||
|
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||||
|
|
||||||
class LongnailMergeCommand extends MySubcommand("mergeISAX") {
|
class LongnailMergeCommand extends MySubcommand("mergeISAX") with Logging[LongnailMergeCommand] with ValidationUtils {
|
||||||
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 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 output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("merged.mlir".path()), descr = "The .mlir file containing the merged ISAXes")
|
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("merged.mlir".path()), descr = "The .mlir file containing the merged ISAXes")
|
||||||
|
val overwrite: ScallopOption[Boolean] = toggle()
|
||||||
|
|
||||||
|
check(inputFiles)(checkPathsIsFile)
|
||||||
|
checkNotIf(overwrite)(output)(checkPathDoesNotExist)
|
||||||
|
|
||||||
override def getRequiredTasks: Seq[Task] = {
|
override def getRequiredTasks: Seq[Task] = {
|
||||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||||
|
|
||||||
if (inputFiles().size == 1) {
|
if (inputFiles().size == 1) {
|
||||||
|
log.debug(s"Only one input file, no merge required...")
|
||||||
if (coreDSLFiles.size == 1) {
|
if (coreDSLFiles.size == 1) {
|
||||||
|
log.trace(s"CoreDSL input file, creating translation task to MLIR...")
|
||||||
Seq(TreenailTask(coreDSLFiles.head, output()))
|
Seq(TreenailTask(coreDSLFiles.head, output()))
|
||||||
} else {
|
} else {
|
||||||
|
log.trace(s"MLIR input file, creating copy task...")
|
||||||
Seq(CopyTask(mlirFiles.head, output()))
|
Seq(CopyTask(mlirFiles.head, output()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
log.debug(s"Multiple input files, creating translation tasks to MLIR and merge task...")
|
||||||
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
||||||
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
||||||
val concatInput = TMP_DIR / "concat.mlir"
|
val concatInput = TMP_DIR / "concat.mlir"
|
||||||
treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, output())
|
treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, output())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def cleanup(): Unit = {
|
||||||
|
log.info(s"Finished, merged MLIR output in ${output()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,19 @@
|
|||||||
package com.minres.tgc.hammer.cli
|
package com.minres.tgc.hammer.cli
|
||||||
|
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import com.minres.tgc.hammer.Global.*
|
import com.minres.tgc.hammer.Global.*
|
||||||
import com.minres.tgc.hammer.tasks.longnail.{LongnailMergeTask, LongnailScheduleTask}
|
import com.minres.tgc.hammer.tasks.longnail.{LongnailMergeTask, LongnailScheduleTask}
|
||||||
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
||||||
import com.minres.tgc.hammer.tasks.longnail.SchedulingParameters
|
import com.minres.tgc.hammer.tasks.longnail.SchedulingParameters
|
||||||
|
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
import os.Path
|
import os.Path
|
||||||
|
|
||||||
class LongnailSchedCommand extends MySubcommand("scheduleISAX") with CoreSelection {
|
class LongnailSchedCommand extends MySubcommand("scheduleISAX") with CoreSelection with Logging[LongnailSchedCommand] with ValidationUtils {
|
||||||
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 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)
|
val schedParams: SchedulingParameters = addConfigElement(new SchedulingParameters)
|
||||||
|
|
||||||
|
check(inputFiles)(checkPathsIsFile)
|
||||||
|
|
||||||
banner(
|
banner(
|
||||||
"""Generate Scheduling information for the provided ISAXes using Longnail
|
"""Generate Scheduling information for the provided ISAXes using Longnail
|
||||||
@@ -19,15 +21,23 @@ class LongnailSchedCommand extends MySubcommand("scheduleISAX") with CoreSelecti
|
|||||||
|""".stripMargin)
|
|""".stripMargin)
|
||||||
|
|
||||||
override def getRequiredTasks: Seq[Task] = {
|
override def getRequiredTasks: Seq[Task] = {
|
||||||
|
log.debug(s"Creating translation task to MLIR for CoreDSL inputs...")
|
||||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||||
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
||||||
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
||||||
if (allMlirFiles.size == 1) {
|
if (allMlirFiles.size == 1) {
|
||||||
|
log.debug(s"Single input file, only creating schedule task...")
|
||||||
treenailTasks :+ LongnailScheduleTask(allMlirFiles.head, getCoreDatasheet, schedParams)
|
treenailTasks :+ LongnailScheduleTask(allMlirFiles.head, getCoreDatasheet, schedParams)
|
||||||
} else {
|
} else {
|
||||||
val mergedInput = TMP_DIR / "merged.mlir"
|
val mergedInput = TMP_DIR / "merged.mlir"
|
||||||
val concatInput = TMP_DIR / "concat.mlir"
|
val concatInput = TMP_DIR / "concat.mlir"
|
||||||
|
log.debug(s"Multiple input files, creating merge and schedule task...")
|
||||||
treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, mergedInput) :+ LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams)
|
treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, mergedInput) :+ LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def cleanup(): Unit = {
|
||||||
|
log.info(s"Finished, scheduling solutions in ${schedParams.schedulingSolutionFile()}")
|
||||||
|
log.info(s"Scheduling selection file (KConf) in ${schedParams.schedule.schedulingSelectionFile()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,25 +3,28 @@ package com.minres.tgc.hammer.cli
|
|||||||
import com.minres.tgc.hammer.options.ConfigElement
|
import com.minres.tgc.hammer.options.ConfigElement
|
||||||
import com.minres.tgc.hammer.tasks.Task
|
import com.minres.tgc.hammer.tasks.Task
|
||||||
import org.rogach.scallop.{ScallopOption, ScallopOptionGroup, Subcommand, Util}
|
import org.rogach.scallop.{ScallopOption, ScallopOptionGroup, Subcommand, Util}
|
||||||
|
import com.minres.tgc.hammer.util.{Checker, ValidationBase}
|
||||||
|
|
||||||
import java.nio.file.Files
|
abstract class MySubcommand(val name: String) extends Subcommand(name) with ValidationBase[ScallopOption] {
|
||||||
|
|
||||||
abstract class MySubcommand(name: String) extends Subcommand(name) {
|
|
||||||
protected val mainGroup: ScallopOptionGroup = group()
|
protected val mainGroup: ScallopOptionGroup = group()
|
||||||
|
|
||||||
def getRequiredTasks: Seq[Task]
|
def getRequiredTasks: Seq[Task]
|
||||||
|
def cleanup(): Unit
|
||||||
|
|
||||||
def addConfigElement[T <: ConfigElement](elem: T): T = {
|
def addConfigElement[T <: ConfigElement](elem: T): T = {
|
||||||
elem.init(this, null)
|
elem.init(this, null)
|
||||||
elem
|
elem
|
||||||
}
|
}
|
||||||
|
|
||||||
def validateOSPathIsDirectory(pathOption: ScallopOption[os.Path]): Unit = addValidation {
|
|
||||||
pathOption.toOption
|
def check[T](option: ScallopOption[T])(check: Checker[T]): Unit = {
|
||||||
.map {
|
addValidation(check(option))
|
||||||
case path if Files.isDirectory(path.toNIO) => Right(())
|
}
|
||||||
case path => Left(Util.format("File '%s' is not a directory", path))
|
|
||||||
}
|
def checkPred[T, U](condOpt: ScallopOption[U], cond: U => Boolean)(option: ScallopOption[T])(check: Checker[T]): Unit = addValidation {
|
||||||
.getOrElse(Right(()))
|
condOpt.toOption match {
|
||||||
|
case Some(value) if cond(value) => check(option)
|
||||||
|
case _ => Right(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,19 @@
|
|||||||
package com.minres.tgc.hammer.cli
|
package com.minres.tgc.hammer.cli
|
||||||
|
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
||||||
|
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
import os.Path
|
import os.Path
|
||||||
|
|
||||||
class TreenailCommand extends MySubcommand("parseCoreDSL") {
|
class TreenailCommand extends MySubcommand("parseCoreDSL") with Logging[TreenailCommand] with ValidationUtils {
|
||||||
val coreDSL: ScallopOption[Path] = trailArg[Path]("coreDSL", descr = "The .core_desc input file to be converted")
|
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")
|
val output: ScallopOption[Path] = opt[Path](short = 'o', default = Some("isax.mlir".path()), descr = "The .mlir file containing the converted ISAX")
|
||||||
|
val overwrite: ScallopOption[Boolean] = toggle()
|
||||||
|
|
||||||
|
check(coreDSL)(checkPathIsFile)
|
||||||
|
check(coreDSL)(checkPathIsCoreDSL)
|
||||||
|
checkNotIf(overwrite)(output)(checkPathDoesNotExist)
|
||||||
|
|
||||||
banner(
|
banner(
|
||||||
"""Parse a CoreDSL input using Treenail into the MLIR representation
|
"""Parse a CoreDSL input using Treenail into the MLIR representation
|
||||||
@@ -19,4 +25,8 @@ class TreenailCommand extends MySubcommand("parseCoreDSL") {
|
|||||||
TreenailTask(coreDSL(), output())
|
TreenailTask(coreDSL(), output())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def cleanup(): Unit = {
|
||||||
|
log.info(s"Finished, MLIR output in ${output()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,16 +7,20 @@ import scala.compiletime.uninitialized
|
|||||||
|
|
||||||
trait BaseOption[T](using conv: ValueConverter[T]) extends ConfigElement {
|
trait BaseOption[T](using conv: ValueConverter[T]) extends ConfigElement {
|
||||||
protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T]
|
protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T]
|
||||||
private var scallop: ScallopOption[T] = uninitialized
|
|
||||||
|
protected[options] var scallop: ScallopOption[T] = uninitialized
|
||||||
|
|
||||||
def init(scallopConf: ScallopConf, group: ScallopOptionGroup): Unit = {
|
def init(scallopConf: ScallopConf, group: ScallopOptionGroup): Unit = {
|
||||||
scallop = createScallop(scallopConf, group)
|
scallop = createScallop(scallopConf, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
def get: T = scallop()
|
def default: () => Option[T]
|
||||||
def apply(): T = get
|
|
||||||
|
|
||||||
def getToolParameters: Seq[Shellable] = if (scallop.isDefined) Seq(s"$toolName", getToolArg) else Seq()
|
def get: Option[T] = scallop.toOption.orElse(default())
|
||||||
|
|
||||||
|
def apply(): T = get.get
|
||||||
|
|
||||||
|
def getToolParameters: Seq[Shellable] = if (get.isDefined) Seq(s"$toolName", get.get.toString) else Seq()
|
||||||
|
|
||||||
def toolName: String
|
def toolName: String
|
||||||
def getToolArg: String = get.toString
|
}
|
||||||
}
|
|
@@ -5,8 +5,8 @@ import org.rogach.scallop.*
|
|||||||
enum Color:
|
enum Color:
|
||||||
case Red, Green, Blue
|
case Red, Green, Blue
|
||||||
|
|
||||||
class ChoiceOption(choices: Seq[String], cliName: String, val toolName: String, descr: String, default: => Option[String], required: Boolean, cliShort: Char) extends BaseOption[String] {
|
class ChoiceOption(choices: Seq[String], cliName: String, val toolName: String, descr: String, val default: () => Option[String], required: Boolean, cliShort: Char) extends BaseOption[String] {
|
||||||
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[String] = {
|
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[String] = {
|
||||||
conf.choice(choices, name = cliName, short = cliShort, descr = descr, default = default, required = required, group = group)
|
conf.choice(choices, name = cliName, short = cliShort, descr = descr, required = required, group = group)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,5 +11,6 @@ class CommandGroup(name: String) extends BaseGroup {
|
|||||||
|
|
||||||
override def init(scallopConf: ScallopConf, group: ScallopOptionGroup): Unit = {
|
override def init(scallopConf: ScallopConf, group: ScallopOptionGroup): Unit = {
|
||||||
options.foreach(_.init(scallopConf, group))
|
options.foreach(_.init(scallopConf, group))
|
||||||
|
initValidation(scallopConf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,31 +1,52 @@
|
|||||||
package com.minres.tgc.hammer.options
|
package com.minres.tgc.hammer.options
|
||||||
|
|
||||||
|
|
||||||
|
import com.minres.tgc.hammer.util.{Checker, ValidationBase, ValidationUtils}
|
||||||
import org.rogach.scallop.{ScallopConf, ScallopOptionGroup, ValueConverter}
|
import org.rogach.scallop.{ScallopConf, ScallopOptionGroup, ValueConverter}
|
||||||
import os.Shellable
|
import os.Shellable
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
trait BaseGroup extends ConfigElement {
|
trait BaseGroup extends ConfigElement with ValidationBase[BaseOption] with ValidationUtils {
|
||||||
protected val options = mutable.ListBuffer[ConfigElement]()
|
protected val options = mutable.ListBuffer[ConfigElement]()
|
||||||
protected def add[T <: ConfigElement](option: T): T = {
|
protected def add[T <: ConfigElement](option: T): T = {
|
||||||
options += option
|
options += option
|
||||||
option
|
option
|
||||||
}
|
}
|
||||||
|
|
||||||
def value[T](cliName: String, toolName: String, descr: String = "", default: => Option[T] = None, required: Boolean = false, cliShort: Char = '\u0000')(using conv: ValueConverter[T]): ValueOption[T] = add(ValueOption(cliName, toolName, descr, default, required, cliShort))
|
def initValidation(scallopConf: ScallopConf): Unit = {
|
||||||
def valueS[T](name: String, descr: String = "", default: => Option[T] = None, required: Boolean = false, cliShort: Char = '\u0000')(using conv: ValueConverter[T]): ValueOption[T] = add(ValueOption(name, name, descr, default, required, cliShort))
|
validations.foreach(fn => scallopConf.addValidation(fn()))
|
||||||
|
}
|
||||||
|
|
||||||
def trail[T](toolName: String, descr: String = "", default: => Option[T] = None, required: Boolean = false)(using conv: ValueConverter[T]): TrailOption[T] = add(TrailOption(toolName, descr, default, required))
|
private var validations: List[() => Either[String, Unit]] = Nil
|
||||||
|
|
||||||
def choice(choices: Seq[String], cliName: String, toolName: String, descr: String = "", default: => Option[String] = None, required: Boolean = false, cliShort: Char = '\u0000'): ChoiceOption = add(ChoiceOption(choices, cliName, toolName, descr, default, required, cliShort))
|
private def addValidation(fn: () => Either[String, Unit]): Unit = {
|
||||||
def choiceS(choices: Seq[String], name: String, descr: String = "", default: => Option[String] = None, required: Boolean = false, cliShort: Char = '\u0000'): ChoiceOption = add(ChoiceOption(choices, name, name, descr, default, required, cliShort))
|
validations :+= fn
|
||||||
|
}
|
||||||
|
|
||||||
|
def check[T](option: BaseOption[T])(check: Checker[T]): Unit = {
|
||||||
|
addValidation(() => check(option.scallop))
|
||||||
|
}
|
||||||
|
def checkPred[T, U](condOpt: BaseOption[U], cond: U => Boolean)(option: BaseOption[T])(check: Checker[T]): Unit = addValidation { () =>
|
||||||
|
condOpt.scallop.toOption match {
|
||||||
|
case Some(value) if cond(value) => check(option.scallop)
|
||||||
|
case _ => Right(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def value[T](cliName: String, toolName: String, descr: String = "", default: () => Option[T] = () => None, required: Boolean = false, cliShort: Char = '\u0000')(using conv: ValueConverter[T]): ValueOption[T] = add(ValueOption(cliName, toolName, descr, default, required, cliShort))
|
||||||
|
def valueS[T](name: String, descr: String = "", default: () => Option[T] = () => None, required: Boolean = false, cliShort: Char = '\u0000')(using conv: ValueConverter[T]): ValueOption[T] = add(ValueOption(name, name, descr, default, required, cliShort))
|
||||||
|
|
||||||
|
def trail[T](toolName: String, descr: String = "", default: () => Option[T] = () => None, required: Boolean = false)(using conv: ValueConverter[T]): TrailOption[T] = add(TrailOption(toolName, descr, default, required))
|
||||||
|
|
||||||
|
def choice(choices: Seq[String], cliName: String, toolName: String, descr: String = "", default: () => Option[String] = () => None, required: Boolean = false, cliShort: Char = '\u0000'): ChoiceOption = add(ChoiceOption(choices, cliName, toolName, descr, default, required, cliShort))
|
||||||
|
def choiceS(choices: Seq[String], name: String, descr: String = "", default: () => Option[String] = () => None, required: Boolean = false, cliShort: Char = '\u0000'): ChoiceOption = add(ChoiceOption(choices, name, name, descr, default, required, cliShort))
|
||||||
|
|
||||||
def tally(cliName: String, toolName: String, descr: String = "", required: Boolean = false, cliShort: Char = '\u0000'): TallyOption = add(TallyOption(cliName, toolName, descr, required, cliShort))
|
def tally(cliName: String, toolName: String, descr: String = "", required: Boolean = false, cliShort: Char = '\u0000'): TallyOption = add(TallyOption(cliName, toolName, descr, required, cliShort))
|
||||||
def tallyS(name: String, descr: String = "", required: Boolean = false, cliShort: Char = '\u0000'): TallyOption = add(TallyOption(name, name, descr, required, cliShort))
|
def tallyS(name: String, descr: String = "", required: Boolean = false, cliShort: Char = '\u0000'): TallyOption = add(TallyOption(name, name, descr, required, cliShort))
|
||||||
|
|
||||||
def toggle(cliName: String, toolName: String, descr: String = "", default: => Option[Boolean] = None, required: Boolean = false, cliShort: Char = '\u0000'): ToggleOption = add(ToggleOption(cliName, toolName, descr, default, required, cliShort))
|
def toggle(cliName: String, toolName: String, descr: String = "", default: () => Option[Boolean] = () => None, required: Boolean = false, cliShort: Char = '\u0000'): ToggleOption = add(ToggleOption(cliName, toolName, descr, default, required, cliShort))
|
||||||
def toggleS(name: String, descr: String = "", default: => Option[Boolean] = None, required: Boolean = false, cliShort: Char = '\u0000'): ToggleOption = add(ToggleOption(name, name, descr, default, required, cliShort))
|
def toggleS(name: String, descr: String = "", default: () => Option[Boolean] = () => None, required: Boolean = false, cliShort: Char = '\u0000'): ToggleOption = add(ToggleOption(name, name, descr, default, required, cliShort))
|
||||||
}
|
}
|
||||||
|
|
||||||
trait OptionGroup extends BaseGroup {
|
trait OptionGroup extends BaseGroup {
|
||||||
@@ -36,5 +57,6 @@ trait OptionGroup extends BaseGroup {
|
|||||||
def init(scallopConf: ScallopConf, g: ScallopOptionGroup): Unit = {
|
def init(scallopConf: ScallopConf, g: ScallopOptionGroup): Unit = {
|
||||||
val group = scallopConf.group(name)
|
val group = scallopConf.group(name)
|
||||||
options.foreach(_.init(scallopConf, group))
|
options.foreach(_.init(scallopConf, group))
|
||||||
|
initValidation(scallopConf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,4 +6,6 @@ class TallyOption(cliName: String, val toolName: String, descr: String, required
|
|||||||
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[Int] = {
|
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[Int] = {
|
||||||
conf.tally(name = cliName, short = cliShort, descr = descr, group = group)
|
conf.tally(name = cliName, short = cliShort, descr = descr, group = group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def default: () => Option[Int] = () => None
|
||||||
}
|
}
|
@@ -2,9 +2,9 @@ package com.minres.tgc.hammer.options
|
|||||||
|
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
|
|
||||||
class ToggleOption(cliName: String, val toolName: String, descr: String, default: => Option[Boolean], required: Boolean, cliShort: Char) extends BaseOption[Boolean] {
|
class ToggleOption(cliName: String, val toolName: String, descr: String, val default: () => Option[Boolean], required: Boolean, cliShort: Char) extends BaseOption[Boolean] {
|
||||||
|
|
||||||
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[Boolean] = {
|
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[Boolean] = {
|
||||||
conf.toggle(name = cliName, short = cliShort, descrYes = descr, default = default, required = required, group = group)
|
conf.toggle(name = cliName, short = cliShort, descrYes = descr, required = required, group = group)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,8 +2,8 @@ package com.minres.tgc.hammer.options
|
|||||||
|
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
|
|
||||||
class TrailOption[T](val toolName: String, descr: String, default: => Option[T], required: Boolean)(using conv: ValueConverter[T]) extends BaseOption[T] {
|
class TrailOption[T](val toolName: String, descr: String, val default: () => Option[T], required: Boolean)(using conv: ValueConverter[T]) extends BaseOption[T] {
|
||||||
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T] = {
|
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T] = {
|
||||||
conf.trailArg[T](descr = descr, default = default, required = required, group = group)
|
conf.trailArg[T](descr = descr, required = required, group = group)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,8 +2,8 @@ package com.minres.tgc.hammer.options
|
|||||||
|
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
|
|
||||||
class ValueOption[T](cliName: String, val toolName: String, descr: String, default: => Option[T], required: Boolean, cliShort: Char)(using conv: ValueConverter[T]) extends BaseOption[T] {
|
class ValueOption[T](cliName: String, val toolName: String, descr: String, val default: () => Option[T], required: Boolean, cliShort: Char)(using conv: ValueConverter[T]) extends BaseOption[T] {
|
||||||
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T] = {
|
override protected def createScallop(conf: ScallopConf, group: ScallopOptionGroup): ScallopOption[T] = {
|
||||||
conf.opt[T](name = cliName, short = cliShort, descr = descr, default = default, required = required, group = group)
|
conf.opt[T](name = cliName, short = cliShort, descr = descr, required = required, group = group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,9 @@ package com.minres.tgc.hammer.tasks
|
|||||||
|
|
||||||
import os.*
|
import os.*
|
||||||
|
|
||||||
case class CopyTask(from: Path, to: Path) extends Task {
|
case class CopyTask(from: Path, to: Path) extends TaskImpl[CopyTask] {
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
|
assert(isFile(from), "Input file does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def execute(): Unit = {
|
override def execute(): Unit = {
|
||||||
|
@@ -1,13 +1,32 @@
|
|||||||
package com.minres.tgc.hammer.tasks
|
package com.minres.tgc.hammer.tasks
|
||||||
|
|
||||||
|
import com.minres.tgc.hammer.Global.TMP_DIR
|
||||||
|
import com.minres.tgc.hammer.Main
|
||||||
|
import com.minres.tgc.hammer.util.Logging
|
||||||
import os.{Path, Shellable}
|
import os.{Path, Shellable}
|
||||||
|
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
|
||||||
trait Task {
|
trait Task {
|
||||||
def validate(): Unit
|
def validate(): Unit
|
||||||
def execute(): Unit
|
def execute(): Unit
|
||||||
|
|
||||||
def runExecutable(execPath: Path, args: Shellable*): os.CommandResult = {
|
def run(): Unit = {
|
||||||
val command = s"$execPath ${args.flatMap(_.value).mkString(" ")}"
|
validate()
|
||||||
os.proc("bash", "-c", command).call(stdout = os.Inherit)
|
execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TaskImpl[T <: Task : ClassTag] extends Task with Logging[T] {
|
||||||
|
|
||||||
|
def runExecutable(execPath: Path, args: Shellable*)(logFile: os.Path): os.CommandResult = {
|
||||||
|
val command = s"$execPath ${args.flatMap(_.value).mkString(" ")}"
|
||||||
|
log.debug(s"Running external program: ")
|
||||||
|
log.debug(command)
|
||||||
|
val output: os.ProcessOutput = if (Main.conf.printToolOutput())
|
||||||
|
os.Inherit
|
||||||
|
else
|
||||||
|
logFile
|
||||||
|
os.proc("bash", "-c", command).call(cwd = TMP_DIR, stdout = output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,17 @@
|
|||||||
package com.minres.tgc.hammer.tasks
|
package com.minres.tgc.hammer.tasks
|
||||||
|
|
||||||
import com.minres.tgc.hammer.Global
|
import com.minres.tgc.hammer.Global.*
|
||||||
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import os.*
|
import os.*
|
||||||
|
|
||||||
case class TreenailTask(coreDSLInput: Path, output: Path) extends Task {
|
case class TreenailTask(coreDSLInput: Path, output: Path) extends TaskImpl[TreenailTask] {
|
||||||
private val EXECUTABLE = Global.TREENAIL / "app" / "build" / "install" / "app" / "bin" / "app"
|
private val EXECUTABLE = TREENAIL / "app" / "build" / "install" / "app" / "bin" / "app"
|
||||||
|
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
assert(isFile(EXECUTABLE), "Treenail Executable is missing, build Treenail")
|
assert(isFile(EXECUTABLE), "Treenail Executable is missing, build Treenail")
|
||||||
|
assert(isCoreDSLFile(coreDSLInput), "Input file does not exist")
|
||||||
}
|
}
|
||||||
override def execute(): Unit = {
|
override def execute(): Unit = {
|
||||||
runExecutable(EXECUTABLE, "-o", output, coreDSLInput)
|
runExecutable(EXECUTABLE, "-o", output, coreDSLInput)(LOG_DIR / "treenail.log")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,10 @@ package com.minres.tgc.hammer.tasks.longnail
|
|||||||
|
|
||||||
import com.minres.tgc.hammer.Global
|
import com.minres.tgc.hammer.Global
|
||||||
import com.minres.tgc.hammer.options.*
|
import com.minres.tgc.hammer.options.*
|
||||||
import com.minres.tgc.hammer.tasks.Task
|
import com.minres.tgc.hammer.tasks.{Task, TaskImpl}
|
||||||
import os.{Path, isFile}
|
import os.{Path, isFile}
|
||||||
|
|
||||||
trait LongnailBaseTask extends Task {
|
trait LongnailBaseTask[T <: LongnailBaseTask[T]] extends TaskImpl[T] {
|
||||||
protected val EXECUTABLE: os.Path = Global.LONGNAIL / "build" / "bin" / "longnail-opt"
|
protected val EXECUTABLE: os.Path = Global.LONGNAIL / "build" / "bin" / "longnail-opt"
|
||||||
|
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
|
@@ -1,10 +1,15 @@
|
|||||||
package com.minres.tgc.hammer.tasks.longnail
|
package com.minres.tgc.hammer.tasks.longnail
|
||||||
|
|
||||||
import os.Path
|
import com.minres.tgc.hammer.Global.LOG_DIR
|
||||||
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
|
import os.*
|
||||||
|
|
||||||
class LongnailHLSTask(schedulingSolutionFile: Path, schedulingSelectionFile: Option[Path], outDirectory: Path) extends LongnailBaseTask {
|
class LongnailHLSTask(schedulingSolutionFile: Path, schedulingSelectionFile: Option[Path], outDirectory: Path) extends LongnailBaseTask[LongnailHLSTask] {
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
super.validate()
|
super.validate()
|
||||||
|
assert(isMLIRFile(schedulingSolutionFile), "Scheduling solution file does not exist")
|
||||||
|
schedulingSelectionFile.foreach(f => assert(isFile(f), "Scheduling selection file does not exist"))
|
||||||
|
assert(isDir(outDirectory), "Output directory does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def execute(): Unit = {
|
override def execute(): Unit = {
|
||||||
@@ -23,6 +28,6 @@ class LongnailHLSTask(schedulingSolutionFile: Path, schedulingSelectionFile: Opt
|
|||||||
"--hw-legalize-modules",
|
"--hw-legalize-modules",
|
||||||
s"--export-split-verilog=dir-name=$outDirectory",
|
s"--export-split-verilog=dir-name=$outDirectory",
|
||||||
schedulingSolutionFile
|
schedulingSolutionFile
|
||||||
)
|
)(LOG_DIR / "longnail_hls.log")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
package com.minres.tgc.hammer.tasks.longnail
|
package com.minres.tgc.hammer.tasks.longnail
|
||||||
|
|
||||||
import os.Path
|
import com.minres.tgc.hammer.Global.LOG_DIR
|
||||||
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
|
import os.*
|
||||||
|
|
||||||
class LongnailMergeTask(mlirFiles: Seq[Path], concatMLIR: Path, mergedMLIR: Path) extends LongnailBaseTask {
|
class LongnailMergeTask(mlirFiles: Seq[Path], concatMLIR: Path, mergedMLIR: Path) extends LongnailBaseTask[LongnailMergeTask] {
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
super.validate()
|
super.validate()
|
||||||
|
mlirFiles.foreach(f => assert(f.isMLIRFile, s"Input file $f does not exist or is not an MLIR file"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def execute(): Unit = {
|
override def execute(): Unit = {
|
||||||
@@ -15,6 +18,6 @@ class LongnailMergeTask(mlirFiles: Seq[Path], concatMLIR: Path, mergedMLIR: Path
|
|||||||
runExecutable(EXECUTABLE,
|
runExecutable(EXECUTABLE,
|
||||||
"--merge-multiple-isaxes", concatMLIR,
|
"--merge-multiple-isaxes", concatMLIR,
|
||||||
"-o", mergedMLIR
|
"-o", mergedMLIR
|
||||||
)
|
)(LOG_DIR / "longnail_merge.log")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,38 +1,24 @@
|
|||||||
package com.minres.tgc.hammer.tasks.longnail
|
package com.minres.tgc.hammer.tasks.longnail
|
||||||
|
|
||||||
import com.minres.tgc.hammer.options.*
|
import com.minres.tgc.hammer.Global.LOG_DIR
|
||||||
import com.minres.tgc.hammer.tasks.longnail.LongnailBaseTask
|
import com.minres.tgc.hammer.tasks.longnail.LongnailBaseTask
|
||||||
import os.Path
|
import com.minres.tgc.hammer.util.FileUtils.isMLIRFile
|
||||||
|
import os.*
|
||||||
|
|
||||||
class LongnailScheduleTask(isaxMLIR: Path, coreDatasheet: Path, params: SchedulingParameters) extends LongnailBaseTask {
|
class LongnailScheduleTask(isaxMLIR: Path, coreDatasheet: Path, params: SchedulingParameters) extends LongnailBaseTask[LongnailScheduleTask] {
|
||||||
|
|
||||||
override def validate(): Unit = {
|
override def validate(): Unit = {
|
||||||
super.validate()
|
super.validate()
|
||||||
|
assert(isMLIRFile(isaxMLIR), "Input file does not exist")
|
||||||
|
assert(isFile(coreDatasheet), "Core datasheet does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def execute(): Unit = {
|
override def execute(): Unit = {
|
||||||
/*runExecutable(EXECUTABLE,
|
|
||||||
"--lower-coredsl-to-lil",
|
|
||||||
"--max-unroll-factor", params.maxLoopUnrollFactor,
|
|
||||||
"--schedule-lil",
|
|
||||||
"--datasheet", params.base.coreDatasheet,
|
|
||||||
"--library", params.base.cellLibrary,
|
|
||||||
"--opTyLibrary", params.base.opTyLibrary,
|
|
||||||
"--clockTime", params.base.clockPeriod,
|
|
||||||
"--schedulingAlgo", params.base.schedulingAlgo,
|
|
||||||
"--solver", params.base.ilpSolver,
|
|
||||||
"--schedulingTimeout", params.schedulingTimeout,
|
|
||||||
"--schedRefineTimeout", params.schedulingRefineTimeout,
|
|
||||||
"--solSelKconfPath", params.schedulingKconf,
|
|
||||||
"--verbose", params.base.verbose.toString,
|
|
||||||
"-o", params.schedulingMLIR,
|
|
||||||
isaxMLIR
|
|
||||||
)*/
|
|
||||||
runExecutable(EXECUTABLE,
|
runExecutable(EXECUTABLE,
|
||||||
"--lower-coredsl-to-lil",
|
"--lower-coredsl-to-lil",
|
||||||
params.getToolParameters,
|
params.getToolParameters,
|
||||||
isaxMLIR
|
isaxMLIR
|
||||||
)
|
)(LOG_DIR / "longnail_schedule.log")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package com.minres.tgc.hammer.tasks.longnail
|
package com.minres.tgc.hammer.tasks.longnail
|
||||||
|
|
||||||
import com.minres.tgc.hammer.FileUtils.*
|
import com.minres.tgc.hammer.util.FileUtils.*
|
||||||
import com.minres.tgc.hammer.Global.OUT_DIR
|
import com.minres.tgc.hammer.Global.OUT_DIR
|
||||||
import com.minres.tgc.hammer.options.*
|
import com.minres.tgc.hammer.options.*
|
||||||
import org.rogach.scallop.*
|
import org.rogach.scallop.*
|
||||||
@@ -9,22 +9,26 @@ import os.Path
|
|||||||
class SchedulingParameters extends OptionGroup {
|
class SchedulingParameters extends OptionGroup {
|
||||||
override def name: String = "Longnail Scheduling Args"
|
override def name: String = "Longnail Scheduling Args"
|
||||||
|
|
||||||
add(new CommandGroup("--prepare-schedule-lil") {
|
class PrepareOptions extends CommandGroup("--prepare-schedule-lil") {
|
||||||
choiceS(Seq("LEGACY", "MS", "PAMS", "PARAMS", "MI_MS", "MI_PAMS", "MI_PARAMS"), name = "schedulingAlgo", default = Some("LEGACY"), descr =
|
val schedulingAlgo = 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")
|
"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")
|
val cellLibrary = 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)")
|
val opTyLibrary = valueS[Path](name = "opTyLibrary", descr = "The operator type model used for detailed data (e.g. from OL SKY130 in longnail/opTyLibraries/OL2.yaml)")
|
||||||
})
|
check(cellLibrary)(checkPathIsFile)
|
||||||
|
check(opTyLibrary)(checkPathIsFile)
|
||||||
|
}
|
||||||
|
val prepare = add(new PrepareOptions)
|
||||||
|
|
||||||
add(new CommandGroup("--schedule-lil") {
|
class ScheduleOptions extends CommandGroup("--schedule-lil") {
|
||||||
valueS[Int](name = "schedulingTimeout", default = Some(10), descr = "Longnail scheduling timeout in seconds")
|
val schedulingTimeout = 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")
|
val schedulingRefineTimeout = 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")
|
val schedulingSelectionFile = 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")
|
val ilpSolver = 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")
|
val verboseSched = 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")
|
val clockPeriod = value[Int](cliName = "clockPeriod", toolName = "clockTime", descr = "The target clock period; uses same time unit as delays in opTyLibrary", default = () => Some(10))
|
||||||
})
|
}
|
||||||
|
val schedule = add(new ScheduleOptions)
|
||||||
|
|
||||||
value[Int](cliName = "--maxLoopUnrollFactor", toolName = "max-unroll-factor", default = Some(16), descr = "Longnail max loop unroll factor")
|
val maxLoopUnrollFactor = value[Int](cliName = "maxLoopUnrollFactor", toolName = "--max-unroll-factor", default = () => Some(16), descr = "Longnail max loop unroll factor")
|
||||||
val schedulingSolutionFile: ValueOption[Path] = value[Path](cliName = "--schedulingMLIR", toolName = "o", default = Some(OUT_DIR / "scheduling_solutions.mlir"), descr = "Output file with different scheduling solutions")
|
val schedulingSolutionFile = value[Path](cliName = "schedulingMLIR", toolName = "--o", default = () => Some(OUT_DIR / "scheduling_solutions.mlir"), descr = "Output file with different scheduling solutions")
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
package com.minres.tgc.hammer.util
|
||||||
|
|
||||||
|
case class AssertException() extends Exception
|
@@ -1,8 +1,8 @@
|
|||||||
package com.minres.tgc.hammer
|
package com.minres.tgc.hammer.util
|
||||||
|
|
||||||
import org.rogach.scallop.{ValueConverter, listArgConverter, singleArgConverter}
|
import com.minres.tgc.hammer.Global.BASE_DIR
|
||||||
|
import org.rogach.scallop.{ScallopOption, Util, ValueConverter, listArgConverter, singleArgConverter}
|
||||||
import os.*
|
import os.*
|
||||||
import Global.*
|
|
||||||
|
|
||||||
import scala.collection.IterableOps
|
import scala.collection.IterableOps
|
||||||
|
|
||||||
@@ -13,6 +13,10 @@ object FileUtils {
|
|||||||
path / os.up / newName
|
path / os.up / newName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension (x: os.Path)
|
||||||
|
def isMLIRFile: Boolean = isFile(x) && x.ext == "mlir"
|
||||||
|
def isCoreDSLFile: Boolean = isFile(x) && x.ext == "core_desc"
|
||||||
|
|
||||||
extension (x: String)
|
extension (x: String)
|
||||||
def asPath(relative: Path): Path = {
|
def asPath(relative: Path): Path = {
|
||||||
Path(x, relative)
|
Path(x, relative)
|
||||||
@@ -31,4 +35,5 @@ object FileUtils {
|
|||||||
implicit val osPathRelBaseListConverter: ValueConverter[List[Path]] = {
|
implicit val osPathRelBaseListConverter: ValueConverter[List[Path]] = {
|
||||||
listArgConverter[Path](_.asPath(BASE_DIR))
|
listArgConverter[Path](_.asPath(BASE_DIR))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
package com.minres.tgc.hammer.util
|
||||||
|
|
||||||
|
import com.typesafe.scalalogging.Logger
|
||||||
|
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
|
||||||
|
trait Logging[T: ClassTag] {
|
||||||
|
protected val log: Logger = Logger[T]
|
||||||
|
|
||||||
|
protected def assert(boolean: Boolean, msg: String): Unit = {
|
||||||
|
if (!boolean) {
|
||||||
|
log.error(msg)
|
||||||
|
throw AssertException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
package com.minres.tgc.hammer.util
|
||||||
|
|
||||||
|
trait ValidationBase[O[_]] {
|
||||||
|
def check[T](option: O[T])(check: Checker[T]): Unit
|
||||||
|
def checkPred[T, U](condOpt: O[U], cond: U => Boolean)(option: O[T])(check: Checker[T]): Unit
|
||||||
|
def checkIf[T](condOpt: O[Boolean])(option: O[T])(check: Checker[T]): Unit = checkPred(condOpt, identity)(option)(check)
|
||||||
|
def checkNotIf[T](condOpt: O[Boolean])(option: O[T])(check: Checker[T]): Unit = checkPred(condOpt, !_)(option)(check)
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
package com.minres.tgc.hammer.util
|
||||||
|
|
||||||
|
import org.rogach.scallop.{ScallopOption, Util}
|
||||||
|
|
||||||
|
|
||||||
|
type Checker[T] = ScallopOption[T] => Either[String,Unit]
|
||||||
|
|
||||||
|
trait ValidationUtils { this: ValidationBase[?] =>
|
||||||
|
|
||||||
|
|
||||||
|
private def checkPredicate[T](option: ScallopOption[T], predicate: T => Boolean, format: String): Either[String,Unit] = {
|
||||||
|
option.toOption.map {
|
||||||
|
case o if predicate(o) => Right(())
|
||||||
|
case o => Left(Util.format(format, o))
|
||||||
|
}.getOrElse(Right(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def checkPredicateIt[T, CC <: Iterable](option: ScallopOption[CC[T]], predicate: T => Boolean, format: String): Either[String,Unit] = {
|
||||||
|
option.toOption.map(options => {
|
||||||
|
val problems = options.filterNot(predicate)
|
||||||
|
problems match {
|
||||||
|
case Nil => Right(())
|
||||||
|
case problem :: Nil => Left(Util.format(format, problem))
|
||||||
|
case _ => Left(s"Multiple: ${Util.format(format, problems.mkString(", "))}")
|
||||||
|
}
|
||||||
|
}).getOrElse(Right(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkPathExists: Checker[os.Path] = path => checkPredicate(path, os.exists, "File '%s' does not exist")
|
||||||
|
def checkPathDoesNotExist: Checker[os.Path] = path => checkPredicate(path, !os.exists(_), "File '%s' already exists")
|
||||||
|
def checkPathIsFile: Checker[os.Path] = path => checkPredicate(path, os.isFile, "File '%s' is not a file")
|
||||||
|
def checkPathIsDir: Checker[os.Path] = path => checkPredicate(path, os.isDir, "File '%s' is not a directory")
|
||||||
|
|
||||||
|
|
||||||
|
def checkPathsExists: Checker[List[os.Path]] = path => checkPredicateIt(path, os.exists, "File(s) '%s' do not exist")
|
||||||
|
def checkPathsDoesNotExists: Checker[List[os.Path]] = path => checkPredicateIt(path, !os.exists(_), "File(s) '%s' already exist")
|
||||||
|
def checkPathsIsFile: Checker[List[os.Path]] = path => checkPredicateIt(path, os.isFile, "File(s) '%s' are not files")
|
||||||
|
def checkPathsIsDir: Checker[List[os.Path]] = path => checkPredicateIt(path, os.isDir, "File(s) '%s' are not directories")
|
||||||
|
|
||||||
|
def checkPathIsCoreDSL: Checker[os.Path] = path => checkPredicate(path, p => p.ext == "core_desc", "File '%s' is not a CoreDSL file")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
1
wsTemplate/.envrc
Normal file
1
wsTemplate/.envrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
source source.sh
|
32
wsTemplate/README.md
Normal file
32
wsTemplate/README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# TGC Hammer Workspace
|
||||||
|
|
||||||
|
This is a workspace for using the TGC Hammer toolchain for ISAX-HLS and integration into TGC cores.
|
||||||
|
The required tools and executables are all located in the base TGC-Hammer repo from which this workspace was created.
|
||||||
|
|
||||||
|
To use the toolchain just enter this directory, `direnv` will then automatically setup all required environment variables.
|
||||||
|
Alternatively you can execute `source source.sh`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The executable for the toolchain is called `tgc-hammer`, it features various subcommands for different tasks.
|
||||||
|
The two main ones `isaxHLS` and `isaxCore` are described in the sections below.
|
||||||
|
|
||||||
|
It also features additionally subcommands for individual steps (e.g. just translate CoreDSL to MLIR), for more information see `tgc-hammer --help`.
|
||||||
|
|
||||||
|
### isaxHLS
|
||||||
|
|
||||||
|
This subcommand takes one or multiple input files describing the ISAXES and runs the Longnail HLS tool to create SystemVerilog respresentations for them.
|
||||||
|
|
||||||
|
The base command looks like this: `tgc-hammer isaxHLS -c VexRiscv --useMinIISolution isax.core_desc`
|
||||||
|
|
||||||
|
The `-c` or `--core` option is required, it provides Longnail with the Core Datasheet detailing core-specific scheduling information.
|
||||||
|
|
||||||
|
Currently the `--useMinIISolution` option is also required, manually selecting scheduling solutions is WIP.
|
||||||
|
|
||||||
|
The command ends with the input files. If multiple ones are specified, they are merged using Longnail before the scheduling and HLS. Both CoreDSL and already translated MLIR files are supported (also mixed).
|
||||||
|
|
||||||
|
For additional options see `tgc-hammer isaxHLS --help`.
|
||||||
|
|
||||||
|
### isaxCore
|
||||||
|
|
||||||
|
WIP
|
257
wsTemplate/examples/Keccak.core_desc
Normal file
257
wsTemplate/examples/Keccak.core_desc
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
InstructionSet Zx_keccak {
|
||||||
|
architectural_state {
|
||||||
|
unsigned int XLEN=32;
|
||||||
|
register unsigned<XLEN> X[32] [[is_main_reg]];
|
||||||
|
extern unsigned<8> MEM[1 << XLEN] [[is_main_mem]];
|
||||||
|
|
||||||
|
const unsigned int RV_CAUSE_ILLEGAL_INSTRUCTION = 0x02;
|
||||||
|
|
||||||
|
register unsigned<64> K[32];
|
||||||
|
register unsigned<8> LFSR;
|
||||||
|
}
|
||||||
|
functions {
|
||||||
|
|
||||||
|
unsigned<64> ROL64(unsigned<64> val, unsigned<64> shift) {
|
||||||
|
return (val << shift) | (val >> (64 - shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned<64> readLane(unsigned int x, unsigned int y) {
|
||||||
|
return K[x + 5 * y];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned<64> XORLane(unsigned int x, unsigned int y, unsigned<64> value) {
|
||||||
|
K[x + 5 * y] = K[x + 5 * y] ^ value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned<64> writeLane(unsigned int x, unsigned int y, unsigned<64> value) {
|
||||||
|
K[x + 5 * y] = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned<1> LFSR86540() {
|
||||||
|
unsigned<1> result = (unsigned<1>)(LFSR & 0x01);
|
||||||
|
if ((LFSR & 0x80) != 0) {
|
||||||
|
// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
|
||||||
|
LFSR = (LFSR << 1) ^ 0x71;
|
||||||
|
} else {
|
||||||
|
LFSR = LFSR << 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instructions {
|
||||||
|
// Custom-0 Opcode
|
||||||
|
LK64 {
|
||||||
|
encoding: imm[11:0] :: rs1[4:0] :: 3'b000 :: rd[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rd)}, {imm}({name(rs1)})";
|
||||||
|
behavior: {
|
||||||
|
unsigned<XLEN> load_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
K[rd]= MEM[load_address+7:load_address];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LK128 {
|
||||||
|
encoding: imm[11:0] :: rs1[4:0] :: 3'b010 :: rd[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rd)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rd%2 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<2; i++){
|
||||||
|
unsigned<XLEN> load_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
K[rd+i]= MEM[load_address+7:load_address];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LK256 {
|
||||||
|
encoding: imm[11:0] :: rs1[4:0] :: 3'b100 :: rd[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rd)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rd%4 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<4; i++){
|
||||||
|
unsigned<XLEN> load_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
K[rd+i]= MEM[load_address+7:load_address];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LK512 {
|
||||||
|
encoding: imm[11:0] :: rs1[4:0] :: 3'b110 :: rd[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rd)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rd%8 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<8; i++){
|
||||||
|
unsigned<XLEN> load_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
K[rd+i]= MEM[load_address+7:load_address];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SK64 {
|
||||||
|
encoding: imm[11:5] :: rs2[4:0] :: rs1[4:0] :: 3'b001 :: imm[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rs2)}, {imm}({name(rs1)})";
|
||||||
|
behavior: {
|
||||||
|
unsigned<XLEN> store_address = (unsigned<XLEN>)(X[rs1] + (signed)imm);
|
||||||
|
MEM[store_address+7:store_address] = K[rs2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SK128 {
|
||||||
|
encoding: imm[11:5] :: rs2[4:0] :: rs1[4:0] :: 3'b011 :: imm[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rs2)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rs2%2 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<2; i++){
|
||||||
|
unsigned<XLEN> store_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
MEM[store_address+7:store_address] = K[rs2+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SK256 {
|
||||||
|
encoding: imm[11:5] :: rs2[4:0] :: rs1[4:0] :: 3'b101 :: imm[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rs2)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rs2%4 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<4; i++){
|
||||||
|
unsigned<XLEN> store_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
MEM[store_address+7:store_address] = K[rs2+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SK512 {
|
||||||
|
encoding: imm[11:5] :: rs2[4:0] :: rs1[4:0] :: 3'b111 :: imm[4:0] :: 7'b0001011;
|
||||||
|
assembly: "{name(rs2)}, {imm}({name(rs1)})";
|
||||||
|
behavior: if(rs2%8 == 1) ; else {
|
||||||
|
unsigned<XLEN> base_address = (unsigned<XLEN>)(X[rs1] + (signed<12>)imm);
|
||||||
|
for(unsigned int i = 0; i<8; i++){
|
||||||
|
unsigned<XLEN> store_address = (unsigned<XLEN>)(base_address + 8*i);
|
||||||
|
MEM[store_address+7:store_address] = K[rs2+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KECCAK_THETA {
|
||||||
|
encoding: 7'b0000000 :: 5'b00000 :: 5'b00000 :: 3'b000 :: 5'b00000 :: 7'b0001011;
|
||||||
|
assembly: "keccak.theta";
|
||||||
|
behavior: {
|
||||||
|
// Temporary storage for C array (5 columns)
|
||||||
|
unsigned<64> C0, C1, C2, C3, C4;
|
||||||
|
unsigned<64> D;
|
||||||
|
|
||||||
|
// Compute the parity of the columns
|
||||||
|
C0 = readLane(0, 0) ^ readLane(0, 1) ^ readLane(0, 2) ^ readLane(0, 3) ^ readLane(0, 4);
|
||||||
|
C1 = readLane(1, 0) ^ readLane(1, 1) ^ readLane(1, 2) ^ readLane(1, 3) ^ readLane(1, 4);
|
||||||
|
C2 = readLane(2, 0) ^ readLane(2, 1) ^ readLane(2, 2) ^ readLane(2, 3) ^ readLane(2, 4);
|
||||||
|
C3 = readLane(3, 0) ^ readLane(3, 1) ^ readLane(3, 2) ^ readLane(3, 3) ^ readLane(3, 4);
|
||||||
|
C4 = readLane(4, 0) ^ readLane(4, 1) ^ readLane(4, 2) ^ readLane(4, 3) ^ readLane(4, 4);
|
||||||
|
|
||||||
|
// Apply theta effect to column 0
|
||||||
|
D = C4 ^ ROL64(C1, 1);
|
||||||
|
XORLane(0, 0, D);
|
||||||
|
XORLane(0, 1, D);
|
||||||
|
XORLane(0, 2, D);
|
||||||
|
XORLane(0, 3, D);
|
||||||
|
XORLane(0, 4, D);
|
||||||
|
|
||||||
|
// Apply theta effect to column 1
|
||||||
|
D = C0 ^ ROL64(C2, 1);
|
||||||
|
XORLane(1, 0, D);
|
||||||
|
XORLane(1, 1, D);
|
||||||
|
XORLane(1, 2, D);
|
||||||
|
XORLane(1, 3, D);
|
||||||
|
XORLane(1, 4, D);
|
||||||
|
|
||||||
|
// Apply theta effect to column 2
|
||||||
|
D = C1 ^ ROL64(C3, 1);
|
||||||
|
XORLane(2, 0, D);
|
||||||
|
XORLane(2, 1, D);
|
||||||
|
XORLane(2, 2, D);
|
||||||
|
XORLane(2, 3, D);
|
||||||
|
XORLane(2, 4, D);
|
||||||
|
|
||||||
|
// Apply theta effect to column 3
|
||||||
|
D = C2 ^ ROL64(C4, 1);
|
||||||
|
XORLane(3, 0, D);
|
||||||
|
XORLane(3, 1, D);
|
||||||
|
XORLane(3, 2, D);
|
||||||
|
XORLane(3, 3, D);
|
||||||
|
XORLane(3, 4, D);
|
||||||
|
|
||||||
|
// Apply theta effect to column 4
|
||||||
|
D = C3 ^ ROL64(C0, 1);
|
||||||
|
XORLane(4, 0, D);
|
||||||
|
XORLane(4, 1, D);
|
||||||
|
XORLane(4, 2, D);
|
||||||
|
XORLane(4, 3, D);
|
||||||
|
XORLane(4, 4, D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KECCAK_RHO_PI {
|
||||||
|
encoding: 7'b0000000 :: 5'b00000 :: 5'b00000 :: 3'b001 :: 5'b00000 :: 7'b0001011;
|
||||||
|
assembly: "keccak.rhopi";
|
||||||
|
behavior: {
|
||||||
|
unsigned<64> current, temp;
|
||||||
|
unsigned int x, y;
|
||||||
|
unsigned int r;
|
||||||
|
unsigned int Y;
|
||||||
|
|
||||||
|
// Start at coordinates (1, 0)
|
||||||
|
x = 1;
|
||||||
|
y = 0;
|
||||||
|
current = readLane(x, y);
|
||||||
|
|
||||||
|
// Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23
|
||||||
|
for(unsigned int t = 0; t < 24; t++) {
|
||||||
|
// Compute the rotation constant r = (t+1)(t+2)/2
|
||||||
|
r = ((t + 1) * (t + 2) / 2) % 64;
|
||||||
|
|
||||||
|
// Compute ((0 1)(2 3)) * (x y)
|
||||||
|
Y = (2 * x + 3 * y) % 5;
|
||||||
|
x = y;
|
||||||
|
y = Y;
|
||||||
|
|
||||||
|
// Swap current and state(x,y), and rotate
|
||||||
|
temp = readLane(x, y);
|
||||||
|
writeLane(x, y, ROL64(current, r));
|
||||||
|
current = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KECCAK_CHI {
|
||||||
|
encoding: 7'b0000000 :: 5'b00000 :: 5'b00000 :: 3'b010 :: 5'b00000 :: 7'b0001011;
|
||||||
|
assembly: "keccak.chi";
|
||||||
|
behavior: {
|
||||||
|
unsigned<64> T0, T1, T2, T3, T4;
|
||||||
|
unsigned int y;
|
||||||
|
for(y = 0; y < 5; y++) {
|
||||||
|
/* Take a copy of the plane */
|
||||||
|
T0 = readLane(0, y);
|
||||||
|
T1 = readLane(1, y);
|
||||||
|
T2 = readLane(2, y);
|
||||||
|
T3 = readLane(3, y);
|
||||||
|
T4 = readLane(4, y);
|
||||||
|
/* Compute χ on the plane */
|
||||||
|
writeLane(0, y, T0 ^ (~T1 & T2));
|
||||||
|
writeLane(1, y, T1 ^ (~T2 & T3));
|
||||||
|
writeLane(2, y, T2 ^ (~T3 & T4));
|
||||||
|
writeLane(3, y, T3 ^ (~T4 & T0));
|
||||||
|
writeLane(4, y, T4 ^ (~T0 & T1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KECCAK_IOTA {
|
||||||
|
encoding: 7'b0000000 :: 5'b00000 :: 5'b00000 :: 3'b011 :: 5'b00000 :: 7'b0001011;
|
||||||
|
assembly: "keccak.iota";
|
||||||
|
behavior: {
|
||||||
|
unsigned int j;
|
||||||
|
for (j = 0; j < 7; j++) {
|
||||||
|
unsigned int bitPosition = (unsigned int)((1 << j) - 1);
|
||||||
|
if (LFSR86540()) {
|
||||||
|
XORLane(0, 0, (unsigned<64>)1 << bitPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KECCAK_LFSR_RESET {
|
||||||
|
encoding: 7'b0000000 :: 5'b00000 :: 5'b00000 :: 3'b100 :: 5'b00000 :: 7'b0001011;
|
||||||
|
assembly: "keccak.lfsr.reset";
|
||||||
|
behavior: {
|
||||||
|
LFSR = 0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
wsTemplate/examples/LWC.core_desc
Normal file
79
wsTemplate/examples/LWC.core_desc
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
InstructionSet Zxlwc_ascon {
|
||||||
|
architectural_state {
|
||||||
|
unsigned int XLEN=32;
|
||||||
|
register unsigned<XLEN> X[32] [[is_main_reg]];
|
||||||
|
}
|
||||||
|
|
||||||
|
functions {
|
||||||
|
|
||||||
|
unsigned<64> _ror64(unsigned<64> val, unsigned<64> shift_amount) {
|
||||||
|
return (val >> shift_amount) | (val << (64 - shift_amount));
|
||||||
|
}
|
||||||
|
// ROT_0 = { 19, 61, 1, 10, 7 }
|
||||||
|
unsigned<64> rot_0(unsigned<5> imm){
|
||||||
|
unsigned<64> ret;
|
||||||
|
if(imm == 0)
|
||||||
|
ret = 19;
|
||||||
|
else if(imm==1)
|
||||||
|
ret = 61;
|
||||||
|
else if(imm==2)
|
||||||
|
ret = 1;
|
||||||
|
else if(imm==3)
|
||||||
|
ret = 10;
|
||||||
|
else if(imm==4)
|
||||||
|
ret = 7;
|
||||||
|
else ret = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// ROT_1 = { 28, 39, 6, 17, 41 }
|
||||||
|
unsigned<64> rot_1(unsigned<5> imm){
|
||||||
|
unsigned<64> ret;
|
||||||
|
if(imm == 0)
|
||||||
|
ret = 28;
|
||||||
|
else if(imm==1)
|
||||||
|
ret = 39;
|
||||||
|
else if(imm==2)
|
||||||
|
ret = 6;
|
||||||
|
else if(imm==3)
|
||||||
|
ret = 17;
|
||||||
|
else if(imm==4)
|
||||||
|
ret = 41;
|
||||||
|
else ret = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions{
|
||||||
|
ASCON_SIGMA_LO [[enable=XLEN==32]] {
|
||||||
|
encoding: 2'b00 :: imm[4:0] :: rs2[4:0] :: rs1[4:0] :: 3'b111 :: rd[4:0] :: 7'b0101011;
|
||||||
|
behavior: {
|
||||||
|
unsigned<32> x_hi = (unsigned<32>)X[rs2];
|
||||||
|
unsigned<32> x_lo = (unsigned<32>)X[rs1];
|
||||||
|
unsigned<64> x = x_hi :: x_lo;
|
||||||
|
unsigned<64> r = x ^ _ror64(x, rot_0(imm)) ^ _ror64(x, rot_1(imm));
|
||||||
|
X[rd] = (unsigned<XLEN>)r[31:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ASCON_SIGMA_HI [[enable=XLEN==32]] {
|
||||||
|
encoding: 2'b01 :: imm[4:0] :: rs2[4:0] :: rs1[4:0] :: 3'b111 :: rd[4:0] :: 7'b0101011;
|
||||||
|
behavior: {
|
||||||
|
unsigned<32> x_hi = (unsigned<32>)X[rs2];
|
||||||
|
unsigned<32> x_lo = (unsigned<32>)X[rs1];
|
||||||
|
unsigned<64> x = x_hi :: x_lo;
|
||||||
|
unsigned<64> r = x ^ _ror64(x, rot_0(imm)) ^ _ror64(x, rot_1(imm));
|
||||||
|
X[rd] = (unsigned<XLEN>)r[63:32];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASCON_SIGMA [[enable=XLEN==64]] {
|
||||||
|
encoding: 2'b10 :: imm[4:0] :: 5'b00000 :: rs1[4:0] :: 3'b110 :: rd[4:0] :: 7'b0101011;
|
||||||
|
behavior: {
|
||||||
|
unsigned<64> x = X[rs1];
|
||||||
|
unsigned<64> r = x ^ _ror64(x, rot_0(imm)) ^ _ror64(x, rot_1(imm));
|
||||||
|
X[rd] = (unsigned<XLEN>)r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user