diff --git a/build.sc b/build.sc index 2c64d604685..ab49842c3a1 100644 --- a/build.sc +++ b/build.sc @@ -288,3 +288,32 @@ trait CIRCTPanamaBinderModuleTest Seq(PathRef(millSourcePath / "src" / "test")) } } + +object filecheckutility extends Cross[FileCheckUtility](v.scalaCrossVersions) + +trait FileCheckUtility + extends tests.FileCheckUtilityModule + with CrossModuleBase + with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up / "filecheck" / "utility" + def circtPanamaBinderModule = circtpanamabinder(crossScalaVersion) +} + +val checkTuples = v.scalaCrossVersions.flatMap(sv => + os.walk( + os.pwd / "filecheck" / "tests", + // avoid issue when including chisel/build.sc + includeTarget = true + ) + .filter(os.isFile) + .filter(f => f.ext == "scala" || f.ext == "sc" ) + .map(_.last).map(test => + (sv, test) + ) +) +object filecheck extends Cross[FileCheckTestModule](checkTuples) + +trait FileCheckTestModule + extends tests.FileCheckTestModule { + def fileCheckUtilityModule = filecheckutility("2.13.12") +} \ No newline at end of file diff --git a/filecheck/tests/ChiselCIRCTBinding.sc b/filecheck/tests/ChiselCIRCTBinding.sc new file mode 100644 index 00000000000..b318144d0bf --- /dev/null +++ b/filecheck/tests/ChiselCIRCTBinding.sc @@ -0,0 +1,15 @@ +//> RUN: scala-cli $THIS +//> using options -Xplugin:$PLUGINJAR +//> using javaHome $JAVAHOME +//> using javaOpt --enable-native-access=ALL-UNNAMED --enable-preview $JAVACNATIVELIBPATH +import chisel3._ +import utility.binding._ + +class FooBundle extends Bundle { + val foo = Input(UInt(3.W)) +} +class FooModule extends Module { + val io = IO(new FooBundle) +} +firrtlString(new FooModule) +verilogString(new FooModule) \ No newline at end of file diff --git a/filecheck/tests/EmptyModule.sc b/filecheck/tests/EmptyModule.sc new file mode 100644 index 00000000000..4fb7822d164 --- /dev/null +++ b/filecheck/tests/EmptyModule.sc @@ -0,0 +1,5 @@ +//> RUN: scala-cli $THIS | firtool -format=fir +import chisel3._ +import circt.stage.ChiselStage +class EmptyModule extends Module +println(ChiselStage.emitCHIRRTL(new EmptyModule)) \ No newline at end of file diff --git a/filecheck/tests/WithCompilerPlugin.sc b/filecheck/tests/WithCompilerPlugin.sc new file mode 100644 index 00000000000..70b4ccde7cc --- /dev/null +++ b/filecheck/tests/WithCompilerPlugin.sc @@ -0,0 +1,11 @@ +//> RUN: scala-cli $THIS +//> using options -Xplugin:$PLUGINJAR +import chisel3._ +import circt.stage.ChiselStage +class FooBundle extends Bundle { + val foo = Input(UInt(3.W)) +} +class FooModule extends Module { + val io = IO(new FooBundle) +} +println(ChiselStage.emitCHIRRTL(new FooModule)) diff --git a/filecheck/tests/WithoutCompilerPlugin.sc b/filecheck/tests/WithoutCompilerPlugin.sc new file mode 100644 index 00000000000..171e4341716 --- /dev/null +++ b/filecheck/tests/WithoutCompilerPlugin.sc @@ -0,0 +1,10 @@ +//> RUN: scala-cli $THIS +import chisel3._ +import circt.stage.ChiselStage +class FooBundle extends Bundle { + val foo = Input(UInt(3.W)) +} +class FooModule extends Module { + val io = IO(new FooBundle) +} +println(ChiselStage.emitCHIRRTL(new FooModule)) diff --git a/filecheck/utility/src/package.scala b/filecheck/utility/src/package.scala new file mode 100644 index 00000000000..03e63ea52bb --- /dev/null +++ b/filecheck/utility/src/package.scala @@ -0,0 +1,23 @@ +import chisel3._ + +package object utility { + object binding { + def streamString(module: => RawModule, stream: chisel3.internal.CIRCTConverter => geny.Writable): String = Seq( + new chisel3.stage.phases.Elaborate, + chisel3.internal.panama.Convert + ).foldLeft( + firrtl.AnnotationSeq(Seq(chisel3.stage.ChiselGeneratorAnnotation(() => module))) + ) { case (annos, phase) => phase.transform(annos) } + .collectFirst { + case chisel3.internal.panama.circt.PanamaCIRCTConverterAnnotation(converter) => + val string = new java.io.ByteArrayOutputStream + stream(converter).writeBytesTo(string) + new String(string.toByteArray) + } + .get + + def firrtlString(module: => RawModule): String = streamString(module, _.firrtlStream) + + def verilogString(module: => RawModule): String = streamString(module, _.verilogStream) + } +} \ No newline at end of file diff --git a/tests.sc b/tests.sc index 915c312d02f..1cf74fd2b1e 100644 --- a/tests.sc +++ b/tests.sc @@ -1,6 +1,11 @@ import mill._ +import mill.api.Result import mill.scalalib._ -import $file.common +import mill.scalalib.api.CompilationResult +import mill.util.Jvm + +import java.util +import scala.jdk.StreamConverters.StreamHasToScala trait SvsimUnitTestModule extends TestModule @@ -77,3 +82,49 @@ trait CIRCTPanamaBinderModuleTestModule scalacheckIvy ) } + +trait FileCheckUtilityModule + extends ScalaModule + with common.HasCIRCTPanamaBinderModule + with common.HasMacroAnnotations + +trait FileCheckTestModule + extends Cross.Module2[String, String] + with TaskModule { + def crossScalaVersion = crossValue + def dutPath = crossValue2 + def fileCheckUtilityModule: FileCheckUtilityModule + + def file = T.input(PathRef(millSourcePath / "tests" / dutPath)) + def source = T(os.read(file().path)) + def testLines = T(source().lines().toScala(LazyList).filter(s => s.matches("^//>\\s+RUN:.*"))) + def tests = T(testLines().map(_ + .replaceAll("^//>\\s+RUN:\\s+", "") + .replaceAll("\\$THIS", processedFile().path.toString) + )) + def processedFilePath = T(T.dest/dutPath) + def processed = T( + s"""//> using scala "$crossScalaVersion" + |//> using jars ${fileCheckUtilityModule.runClasspath().map(_.path).mkString(" ")} + |""".stripMargin + + source() + .replaceAll("^//>\\s+RUN:.*", "") + .replaceAll("\\$THIS", processedFilePath().toString) + .replaceAll("\\$PLUGINJAR", fileCheckUtilityModule.pluginModule.jar().path.toString) + .replaceAll("\\$JAVAHOME", sys.props("java.home")) + .replaceAll("\\$JAVACNATIVELIBPATH", fileCheckUtilityModule.circtPanamaBinderModule.libraryPaths().map(p => s"-Djava.library.path=${p.path}").mkString(" ")) + ) + def processedFile = T { + os.write.over(processedFilePath(), processed()) + PathRef(processedFilePath()) + } + def run = T { + processedFile() + tests().map{c => + T.log.info(s"run $c") + os.proc("bash", "-c", c).call() + } + } + + override def defaultCommandName(): String = "test" +} \ No newline at end of file