Compare commits
26 Commits
4fd033ee82
...
main
Author | SHA1 | Date | |
---|---|---|---|
25c93b8a73 | |||
4dcb6efcef | |||
420e50f23a | |||
6c7e7f496b | |||
44ab3f4622 | |||
2738df3bff | |||
80c9d458b4 | |||
1b450758d3 | |||
7954a9dbe3 | |||
3824dd4d29 | |||
32e626a5a1 | |||
e6f3474fd9 | |||
5218ed37b1 | |||
3d981d16ed | |||
9d0c71dedd | |||
3858761e66 | |||
be691c96be | |||
22a1f31683 | |||
47614ad47f | |||
69b63d93da | |||
9f5c9b4fc3 | |||
66fb0e24c8 | |||
39f0e052c1 | |||
67ff78c8bc | |||
78a96932d7 | |||
8a5262d117 |
@@ -1,3 +1,5 @@
|
||||
# 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,5 +29,7 @@ else
|
||||
echo "export TGC_HAMMER_WORKDIR=\"$PWD\"" >> source.sh
|
||||
echo "export PATH=\"${TGC_HAMMER_HOME}/toolflow/target/universal/stage/bin:$PATH\"" >> source.sh
|
||||
|
||||
cp -r ${TGC_HAMMER_HOME}/wsTemplate/. $PWD
|
||||
|
||||
mkdir -p output
|
||||
fi
|
@@ -11,5 +11,7 @@ lazy val root = project
|
||||
|
||||
libraryDependencies += "org.rogach" %% "scallop" % "5.2.0",
|
||||
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
|
||||
)
|
||||
|
@@ -1,11 +0,0 @@
|
||||
package com.minres.tgc.hammer
|
||||
|
||||
import os.*
|
||||
|
||||
object FileUtils {
|
||||
def changeExtension(path: os.Path, newExt: String): os.Path = {
|
||||
val baseName = path.baseName
|
||||
val newName = s"$baseName.$newExt"
|
||||
path / os.up / newName
|
||||
}
|
||||
}
|
@@ -9,5 +9,8 @@ object Global {
|
||||
lazy val TREENAIL: Path = HAMMER / "deps" / "treenail"
|
||||
lazy val LONGNAIL: Path = HAMMER / "deps" / "longnail"
|
||||
lazy val BASE_DIR: Path = os.pwd
|
||||
def OUT_DIR: Path = Main.conf.outputDirectory()
|
||||
def TMP_DIR: Path = OUT_DIR / "tmp"
|
||||
def LOG_DIR: Path = OUT_DIR / "logs"
|
||||
lazy val CORE_DATASHEETS: Path = HAMMER / "coreDatasheets"
|
||||
}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
package com.minres.tgc.hammer
|
||||
|
||||
import ch.qos.logback.classic.Level
|
||||
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
|
||||
|
||||
@@ -8,14 +12,41 @@ object Main {
|
||||
var conf: HammerConf = uninitialized
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val logger = Logger("TGCHammer")
|
||||
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 {
|
||||
case Some(c: MySubcommand) =>
|
||||
logger.info(s"Executing subcommand ${c.name}")
|
||||
val tasks = c.getRequiredTasks
|
||||
tasks.foreach(_.validate())
|
||||
tasks.foreach(_.execute())
|
||||
logger.debug(s"Subcommand requires ${tasks.size} tasks")
|
||||
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 _ =>
|
||||
logger.error(s"Found no subcommand, see help below")
|
||||
conf.printHelp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,14 @@ 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"
|
||||
|
||||
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,22 +1,28 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
import com.minres.tgc.hammer.Global
|
||||
import org.rogach.scallop.{ScallopConf, ScallopOption, ValueConverter, fileConverter, listArgConverter, singleArgConverter}
|
||||
import com.minres.tgc.hammer.Global.LOG_DIR
|
||||
import org.rogach.scallop.*
|
||||
import os.Path
|
||||
|
||||
import java.io.File
|
||||
import com.minres.tgc.hammer.util.FileUtils.*
|
||||
|
||||
class HammerConf(arguments: Seq[String]) extends ScallopConf(arguments) {
|
||||
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 TreenailCommand)
|
||||
addSubcommand(new LongnailMergeCommand)
|
||||
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()
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
import com.minres.tgc.hammer.util.FileUtils.*
|
||||
import com.minres.tgc.hammer.Global.*
|
||||
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
||||
import com.minres.tgc.hammer.tasks.longnail.{LongnailHLSTask, LongnailMergeTask, LongnailScheduleTask, SchedulingParameters}
|
||||
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||
import org.rogach.scallop.*
|
||||
import os.Path
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
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 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)
|
||||
|
||||
check(inputFiles)(checkPathsIsFile)
|
||||
|
||||
banner(
|
||||
"""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
|
||||
|""".stripMargin)
|
||||
|
||||
override def getRequiredTasks: Seq[Task] = {
|
||||
val tasks = mutable.ListBuffer[Task]()
|
||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
||||
tasks ++= treenailTasks
|
||||
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
||||
if (allMlirFiles.size == 1) {
|
||||
tasks += LongnailScheduleTask(allMlirFiles.head, getCoreDatasheet, schedParams)
|
||||
|
||||
} else {
|
||||
val mergedInput = TMP_DIR / "merged.mlir"
|
||||
val concatInput = TMP_DIR / "concat.mlir"
|
||||
tasks += LongnailMergeTask(allMlirFiles, concatInput, mergedInput)
|
||||
tasks += LongnailScheduleTask(mergedInput, getCoreDatasheet, schedParams)
|
||||
}
|
||||
val verilogOutput = OUT_DIR / "verilog"
|
||||
os.makeDir.all(verilogOutput)
|
||||
if (useMinIISolution()) {
|
||||
tasks += LongnailHLSTask(schedParams.schedulingSolutionFile(), None, verilogOutput)
|
||||
} else {
|
||||
???
|
||||
}
|
||||
tasks.toSeq
|
||||
}
|
||||
|
||||
override def cleanup(): Unit = {
|
||||
log.info(s"Finished, verilog output in ${OUT_DIR / "verilog"}")
|
||||
}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
class LongnailHLSCommand {
|
||||
|
||||
}
|
@@ -1,5 +1,43 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
class LongnailMergeCommand {
|
||||
import com.minres.tgc.hammer.tasks.{CopyTask, Task, TreenailTask}
|
||||
import org.rogach.scallop.*
|
||||
import os.Path
|
||||
import com.minres.tgc.hammer.util.FileUtils.*
|
||||
import com.minres.tgc.hammer.Global.*
|
||||
import com.minres.tgc.hammer.tasks.longnail.LongnailMergeTask
|
||||
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||
|
||||
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 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] = {
|
||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||
|
||||
if (inputFiles().size == 1) {
|
||||
log.debug(s"Only one input file, no merge required...")
|
||||
if (coreDSLFiles.size == 1) {
|
||||
log.trace(s"CoreDSL input file, creating translation task to MLIR...")
|
||||
Seq(TreenailTask(coreDSLFiles.head, output()))
|
||||
} else {
|
||||
log.trace(s"MLIR input file, creating copy task...")
|
||||
Seq(CopyTask(mlirFiles.head, output()))
|
||||
}
|
||||
} 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 allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
||||
val concatInput = TMP_DIR / "concat.mlir"
|
||||
treenailTasks :+ LongnailMergeTask(allMlirFiles, concatInput, output())
|
||||
}
|
||||
}
|
||||
|
||||
override def cleanup(): Unit = {
|
||||
log.info(s"Finished, merged MLIR output in ${output()}")
|
||||
}
|
||||
}
|
||||
|
@@ -1,29 +1,43 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
import com.minres.tgc.hammer.FileUtils.changeExtension
|
||||
import com.minres.tgc.hammer.util.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 com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||
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)
|
||||
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 schedParams: SchedulingParameters = addConfigElement(new SchedulingParameters)
|
||||
|
||||
validateOSPathIsDirectory(outputDirectory)
|
||||
check(inputFiles)(checkPathsIsFile)
|
||||
|
||||
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] = {
|
||||
log.debug(s"Creating translation task to MLIR for CoreDSL inputs...")
|
||||
val (coreDSLFiles, mlirFiles) = inputFiles().partition(_.ext == "core_desc")
|
||||
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, changeExtension(i, "mlir")))
|
||||
val treenailTasks = coreDSLFiles.map(i => TreenailTask(i, TMP_DIR / s"${i.baseName}.mlir"))
|
||||
val allMlirFiles = mlirFiles ++ treenailTasks.map(_.output)
|
||||
if (allMlirFiles.size == 1) {
|
||||
log.debug(s"Single input file, only creating schedule task...")
|
||||
treenailTasks :+ LongnailScheduleTask(allMlirFiles.head, getCoreDatasheet, schedParams)
|
||||
} else {
|
||||
val mergedInput = outputDirectory() / "merged.mlir"
|
||||
val concatInput = outputDirectory() / "concat.mlir"
|
||||
val mergedInput = TMP_DIR / "merged.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)
|
||||
}
|
||||
}
|
||||
|
||||
override def cleanup(): Unit = {
|
||||
log.info(s"Finished, scheduling solutions in ${schedParams.schedulingSolutionFile()}")
|
||||
log.info(s"Scheduling selection file (KConf) in ${schedParams.schedule.schedulingSelectionFile()}")
|
||||
}
|
||||
}
|
||||
|
@@ -1,27 +1,30 @@
|
||||
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 com.minres.tgc.hammer.util.{Checker, ValidationBase}
|
||||
|
||||
import java.nio.file.{Files, Path}
|
||||
|
||||
abstract class MySubcommand(name: String) extends Subcommand(name) {
|
||||
abstract class MySubcommand(val name: String) extends Subcommand(name) with ValidationBase[ScallopOption] {
|
||||
protected val mainGroup: ScallopOptionGroup = group()
|
||||
|
||||
def getRequiredTasks: Seq[Task]
|
||||
def cleanup(): Unit
|
||||
|
||||
def addConfigElement[T <: ConfigElement](elem: T): T = {
|
||||
elem.init(this, null)
|
||||
elem
|
||||
}
|
||||
|
||||
def validateOSPathIsDirectory(pathOption: ScallopOption[os.Path]): Unit = addValidation {
|
||||
pathOption.toOption
|
||||
.map {
|
||||
case path if Files.isDirectory(path.toNIO) => Right(())
|
||||
case path => Left(Util.format("File '%s' is not a directory", path))
|
||||
|
||||
def check[T](option: ScallopOption[T])(check: Checker[T]): Unit = {
|
||||
addValidation(check(option))
|
||||
}
|
||||
|
||||
def checkPred[T, U](condOpt: ScallopOption[U], cond: U => Boolean)(option: ScallopOption[T])(check: Checker[T]): Unit = addValidation {
|
||||
condOpt.toOption match {
|
||||
case Some(value) if cond(value) => check(option)
|
||||
case _ => Right(())
|
||||
}
|
||||
.getOrElse(Right(()))
|
||||
}
|
||||
}
|
||||
|
@@ -1,21 +1,32 @@
|
||||
package com.minres.tgc.hammer.cli
|
||||
|
||||
import com.minres.tgc.hammer.Global
|
||||
import com.minres.tgc.hammer.util.FileUtils.*
|
||||
import com.minres.tgc.hammer.tasks.{Task, TreenailTask}
|
||||
import com.minres.tgc.hammer.util.{Logging, ValidationUtils}
|
||||
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)))
|
||||
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 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()
|
||||
|
||||
validateFileIsFile(coreDSL)
|
||||
check(coreDSL)(checkPathIsFile)
|
||||
check(coreDSL)(checkPathIsCoreDSL)
|
||||
checkNotIf(overwrite)(output)(checkPathDoesNotExist)
|
||||
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
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 = {
|
||||
scallop = createScallop(scallopConf, group)
|
||||
}
|
||||
|
||||
def get: T = scallop()
|
||||
def apply: T = get
|
||||
def default: () => Option[T]
|
||||
|
||||
def getToolParameters: Seq[Shellable] = Seq(s"--$toolName", getToolArg)
|
||||
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 getToolArg: String = get.toString
|
||||
}
|
@@ -5,8 +5,8 @@ import org.rogach.scallop.*
|
||||
enum Color:
|
||||
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] = {
|
||||
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)
|
||||
}
|
||||
}
|
@@ -5,11 +5,12 @@ import os.Shellable
|
||||
|
||||
class CommandGroup(name: String) extends BaseGroup {
|
||||
override def getToolParameters: Seq[Shellable] = {
|
||||
val sub = options.toSeq.flatMap(_.getToolParameters)
|
||||
Seq(s"""$name="${sub.mkString(" ")}"""")
|
||||
val sub = options.toSeq.map(_.getToolParameters.flatMap(_.value).mkString("=")).filter(_.nonEmpty)
|
||||
Seq(s"$name=\'${sub.mkString(" ")}\'")
|
||||
}
|
||||
|
||||
override def init(scallopConf: ScallopConf, group: ScallopOptionGroup): Unit = {
|
||||
options.foreach(_.init(scallopConf, group))
|
||||
initValidation(scallopConf)
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +1,52 @@
|
||||
package com.minres.tgc.hammer.options
|
||||
|
||||
|
||||
import com.minres.tgc.hammer.util.{Checker, ValidationBase, ValidationUtils}
|
||||
import org.rogach.scallop.{ScallopConf, ScallopOptionGroup, ValueConverter}
|
||||
import os.Shellable
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
export com.minres.tgc.hammer.cli.osPathConverter
|
||||
|
||||
trait BaseGroup extends ConfigElement {
|
||||
trait BaseGroup extends ConfigElement with ValidationBase[BaseOption] with ValidationUtils {
|
||||
protected val options = mutable.ListBuffer[ConfigElement]()
|
||||
protected def add[T <: ConfigElement](option: T): T = {
|
||||
options += 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 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 initValidation(scallopConf: ScallopConf): Unit = {
|
||||
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))
|
||||
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))
|
||||
private def addValidation(fn: () => Either[String, Unit]): Unit = {
|
||||
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 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 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 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))
|
||||
}
|
||||
|
||||
trait OptionGroup extends BaseGroup {
|
||||
@@ -38,5 +57,6 @@ trait OptionGroup extends BaseGroup {
|
||||
def init(scallopConf: ScallopConf, g: ScallopOptionGroup): Unit = {
|
||||
val group = scallopConf.group(name)
|
||||
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] = {
|
||||
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.*
|
||||
|
||||
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] = {
|
||||
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.*
|
||||
|
||||
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] = {
|
||||
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.*
|
||||
|
||||
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] = {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package com.minres.tgc.hammer.tasks
|
||||
|
||||
import os.*
|
||||
|
||||
case class CopyTask(from: Path, to: Path) extends TaskImpl[CopyTask] {
|
||||
override def validate(): Unit = {
|
||||
assert(isFile(from), "Input file does not exist")
|
||||
}
|
||||
|
||||
override def execute(): Unit = {
|
||||
copy(from, to)
|
||||
}
|
||||
}
|
@@ -1,12 +1,32 @@
|
||||
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 scala.reflect.ClassTag
|
||||
|
||||
trait Task {
|
||||
def validate(): Unit
|
||||
def execute(): Unit
|
||||
|
||||
def runExecutable(execPath: Path, args: Shellable*): os.CommandResult = {
|
||||
os.proc(execPath, args).call()
|
||||
def run(): Unit = {
|
||||
validate()
|
||||
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
|
||||
|
||||
import com.minres.tgc.hammer.Global
|
||||
|
||||
import com.minres.tgc.hammer.Global.*
|
||||
import com.minres.tgc.hammer.util.FileUtils.*
|
||||
import os.*
|
||||
|
||||
case class TreenailTask(coreDSLInput: Path, output: Path) extends Task {
|
||||
private val EXECUTABLE = Global.TREENAIL / "app" / "build" / "install" / "app" / "bin" / "app"
|
||||
case class TreenailTask(coreDSLInput: Path, output: Path) extends TaskImpl[TreenailTask] {
|
||||
private val EXECUTABLE = TREENAIL / "app" / "build" / "install" / "app" / "bin" / "app"
|
||||
|
||||
override def validate(): Unit = {
|
||||
assert(isFile(EXECUTABLE), "Treenail Executable is missing, build Treenail")
|
||||
assert(isCoreDSLFile(coreDSLInput), "Input file does not exist")
|
||||
}
|
||||
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.options.*
|
||||
import com.minres.tgc.hammer.tasks.Task
|
||||
import com.minres.tgc.hammer.tasks.{Task, TaskImpl}
|
||||
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"
|
||||
|
||||
override def validate(): Unit = {
|
||||
|
@@ -1,18 +1,22 @@
|
||||
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(schedulingFile: Option[Path], outDirectory: Path) extends LongnailBaseTask {
|
||||
class LongnailHLSTask(schedulingSolutionFile: Path, schedulingSelectionFile: Option[Path], outDirectory: Path) extends LongnailBaseTask[LongnailHLSTask] {
|
||||
override def validate(): Unit = {
|
||||
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 = {
|
||||
runExecutable(EXECUTABLE,
|
||||
"--lower-lil-to-hw",
|
||||
schedulingFile match {
|
||||
case Some(value) => s"--solutionSelection $value"
|
||||
case None => "--forceUseMinIISolution=true"
|
||||
schedulingSelectionFile match {
|
||||
case Some(value) => s"--lower-lil-to-hw=solutionSelection=$value"
|
||||
case None => "--lower-lil-to-hw=forceUseMinIISolution=true"
|
||||
},
|
||||
"--simplify-structure",
|
||||
"--cse",
|
||||
@@ -22,8 +26,8 @@ class LongnailHLSTask(schedulingFile: Option[Path], outDirectory: Path) extends
|
||||
"--hw-cleanup",
|
||||
"--prettify-verilog",
|
||||
"--hw-legalize-modules",
|
||||
"--export-split-verilog",
|
||||
"--dir-name", outDirectory
|
||||
)
|
||||
s"--export-split-verilog=dir-name=$outDirectory",
|
||||
schedulingSolutionFile
|
||||
)(LOG_DIR / "longnail_hls.log")
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,13 @@
|
||||
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 = {
|
||||
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 = {
|
||||
@@ -15,6 +18,6 @@ class LongnailMergeTask(mlirFiles: Seq[Path], concatMLIR: Path, mergedMLIR: Path
|
||||
runExecutable(EXECUTABLE,
|
||||
"--merge-multiple-isaxes", concatMLIR,
|
||||
"-o", mergedMLIR
|
||||
)
|
||||
)(LOG_DIR / "longnail_merge.log")
|
||||
}
|
||||
}
|
||||
|
@@ -1,40 +1,24 @@
|
||||
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 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 = {
|
||||
super.validate()
|
||||
assert(isMLIRFile(isaxMLIR), "Input file does not exist")
|
||||
assert(isFile(coreDatasheet), "Core datasheet does not exist")
|
||||
}
|
||||
|
||||
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,
|
||||
"--lower-coredsl-to-lil",
|
||||
"--schedule-lil",
|
||||
"--datasheet", coreDatasheet,
|
||||
params.getToolParameters,
|
||||
isaxMLIR
|
||||
)
|
||||
)(LOG_DIR / "longnail_schedule.log")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,24 +1,34 @@
|
||||
package com.minres.tgc.hammer.tasks.longnail
|
||||
|
||||
import com.minres.tgc.hammer.util.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("schedule-lil") {
|
||||
valueS[Int](name = "schedulingTimeout")
|
||||
value[Int](cliName = "schedulingRefineTimeout", toolName = "schedRefineTimeout")
|
||||
value[Path](cliName = "schedulingKconf", toolName = "solSelKconfPath")
|
||||
choiceS(Seq("LEGACY", "MS", "PAMS", "PARAMS", "MI_MS", "MI_PAMS", "MI_PARAMS"), name = "schedulingAlgo", default = Some("LEGACY"))
|
||||
choice(Seq("CBC", "GLPK", "SCIP", "HIGHS", "GUROBI", "CPLEX", "XPRESS", "COPT"), cliName = "ilpSolver", toolName = "solver", default = Some("CBC"))
|
||||
toggle(cliName = "verboseSched", toolName = "verbose")
|
||||
valueS[Path](name = "opTyLibrary")
|
||||
value[Int](cliName = "clockPeriod", toolName = "clockTime")
|
||||
value[Path](cliName = "cellLibrary", toolName = "library")
|
||||
})
|
||||
class PrepareOptions extends CommandGroup("--prepare-schedule-lil") {
|
||||
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")
|
||||
val cellLibrary = value[Path](cliName = "cellLibrary", toolName = "library", descr = "The cell library used by Longnail (example: longnail/test/LILToHW/longnail*.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)
|
||||
|
||||
value[Int](cliName = "maxLoopUnrollFactor", toolName = "max-unroll-factor")
|
||||
value[Path](cliName = "schedulingMLIR", toolName = "o")
|
||||
class ScheduleOptions extends CommandGroup("--schedule-lil") {
|
||||
val schedulingTimeout = valueS[Int](name = "schedulingTimeout", default = () => Some(10), descr = "Longnail scheduling timeout in seconds")
|
||||
val schedulingRefineTimeout = value[Int](cliName = "schedulingRefineTimeout", toolName = "schedRefineTimeout", default = () => Some(10), descr = "Longnail schedule refinement timeout in seconds")
|
||||
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")
|
||||
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")
|
||||
val verboseSched = toggle(cliName = "verboseSched", toolName = "verbose", descr = "Enable verbose ILP solver messages")
|
||||
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)
|
||||
|
||||
val maxLoopUnrollFactor = value[Int](cliName = "maxLoopUnrollFactor", toolName = "--max-unroll-factor", default = () => Some(16), descr = "Longnail max loop unroll factor")
|
||||
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
|
@@ -0,0 +1,39 @@
|
||||
package com.minres.tgc.hammer.util
|
||||
|
||||
import com.minres.tgc.hammer.Global.BASE_DIR
|
||||
import org.rogach.scallop.{ScallopOption, Util, ValueConverter, listArgConverter, singleArgConverter}
|
||||
import os.*
|
||||
|
||||
import scala.collection.IterableOps
|
||||
|
||||
object FileUtils {
|
||||
def changeExtension(path: os.Path, newExt: String): os.Path = {
|
||||
val baseName = path.baseName
|
||||
val newName = s"$baseName.$newExt"
|
||||
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)
|
||||
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))
|
||||
}
|
||||
|
||||
}
|
@@ -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