本文写于 2024年10月4日,此时 chisel 最新版本为 6.5.0 。
Overview
Chisel (Constructing Hardware In a Scala Embedded Language) 是新兴的硬件描述语言,是采用Scala作为基础、利用chisel第三方库的Domain Specific Language。本文记录了一次从github上的模板工程开始跑通一个最小Chisel工程以获得Verilog的过程。
获取 Github repo
首先通过这个链接获取 Github 项目模板并跟随指引部署到自己的 Github 仓库:Chisel Project Template
我把基于这个模板新建的repo命名为: chisel_helloworld
。这个仓库包含很多东西,其中我们需要关注的内容有:
chisel_helloworld
├── ...
├── README.md
├── src
│ ├── main
│ │ └── scala
│ │ ├── gcd
│ │ │ ├── DecoupledGCD.scala
│ │ │ └── GCD.scala
│ │ └── misc
│ │ └── Hello.scala
│ └── test
│ └── scala
│ └── gcd
│ └── GCDSpec.scala
├── build.sbt
└── build.sc
其中 src/main/scala/misc/Hello.scala
是我添加的文件,其内容为:
package misc
/*
* This code is a minimal hardware described in Chisel.
*
* Blinking LED: the FPGA version of Hello World
*/
import chisel3._
/**
* The blinking LED component.
*/
class Hello extends Module {
val io = IO(new Bundle {
val led = Output(UInt(1.W))
})
val CNT_MAX = (50000000 / 2 - 1).U
val cntReg = RegInit(0.U(32.W))
val blkReg = RegInit(0.U(1.W))
cntReg := cntReg + 1.U
when(cntReg === CNT_MAX) {
cntReg := 0.U
blkReg := ~blkReg
}
io.led := blkReg
}
/**
* An object extending App to generate the Verilog code.
*/
object Hello extends App {
emitVerilog(new Hello())
}
这份代码来自 chisel-example 。我修改了两处:
- 第一行的
package misc
:在同一个package
里面可以有很多份代码,会在后面再讨论这件事情 - 倒数第二行的
emitVerilog(new Hello())
:顾名思义,这里是构建产生.v
的 verilog 文件的语句,其完整API路径是chisel3.emitVerilog
,由于我们有一个import chisel3._
因此这里可以直接使用
构建项目得到 verilog 文件
Scala的构建工具有两个,一个是 SBT ,另一个是 mill 。从上面的文件目录树里可以看到有 build.sbt
和 build.sc
两个文件,前者是 SBT 的配置文件,后者是 mill 的配置文件。只要有 build.sbt
就可以使用 SBT 进行构建;使用 mill 的项目则常常同时具有 build.sbt
和 build.sc
。这两个文件是项目配置文件,打开 build.sbt
就能看到所用 Scala 以及 Chisel 的版本信息。
上面这个项目中的 build.sbt
文件长这样:
// See README.md for license details.
ThisBuild / scalaVersion := "2.13.12"
ThisBuild / version := "0.1.0"
ThisBuild / organization := "com.github.playasmegumin"
val chiselVersion = "6.2.0"
lazy val root = (project in file("."))
.settings(
name := "chisel_helloworld",
libraryDependencies ++= Seq(
"org.chipsalliance" %% "chisel" % chiselVersion,
"org.scalatest" %% "scalatest" % "3.2.16" % "test",
),
scalacOptions ++= Seq(
"-language:reflectiveCalls",
"-deprecation",
"-feature",
"-Xcheckinit",
"-Ymacro-annotations",
),
addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full),
)
可以看到这里的 Chisel 版本是 6.2.0 。Chisel 的版本迭代非常快,在跑网络上的 demo 时如果出现编译问题请查看对应版本的 Chisel API ,链接在这: Docs - chisel-lang
因为没搞明白 mill 怎么使,这里我用的是 SBT ,直接在项目根目录运行 sbt run
即可。
$ sbt run
[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 17.0.12)
[info] loading settings for project chisel_helloworld-build from plugins.sbt ...
[info] loading project definition from /home/duzelong/ysyx/chisel/chisel_helloworld/project
[info] loading settings for project root from build.sbt ...
[info] set current project to chisel_helloworld (in build file:/home/duzelong/ysyx/chisel/chisel_helloworld/)
[info] compiling 1 Scala source to /home/duzelong/ysyx/chisel/chisel_helloworld/target/scala-2.13/classes ...
Multiple main classes detected. Select one to run:
[1] gcd.GCD
[2] misc.Hello
Enter number:
因为在 src/main/scala
下面有两个 “包” :
└── src
└── main
└── scala
├── gcd
│ ├── DecoupledGCD.scala
│ └── GCD.scala
└── misc
└── Hello.scala
所以这里 SBT 给了我们两个选项,一个是 gcd
包的 GCD
,另一个是 misc
包的 Hello
。这里需要辨析一下,包的归属和目录结构没有什么关系,主要是在 GCD.scala
和 Hello.scala
分别用 package gcd
和 package misc
定义了各自所属的包名。文件夹结构可以随你喜欢的设置,不会有很大的影响。一开始我还尝试了这样的放置方法:
└── src
└── main
└── scala
├── gcd
│ ├── DecoupledGCD.scala
│ └── GCD.scala
└── Hello.scala
也并不影响文件和 package
的从属关系,这个 package
事实上很像命名空间。如果采用下面的目录结构,同时删除 src/main/scala/Hello.scala
的 package misc
:
└── src
└── main
└── scala
├── gcd
│ ├── DecoupledGCD.scala
│ └── GCD.scala
├── misc
│ └── Hello.scala
└── Hello.scala
则运行 sbt run
后会显示:
$ sbt run
[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 17.0.12)
[info] loading settings for project chisel_helloworld-build from plugins.sbt ...
[info] loading project definition from /home/duzelong/ysyx/chisel/chisel_helloworld/project
[info] loading settings for project root from build.sbt ...
[info] set current project to chisel_helloworld (in build file:/home/duzelong/ysyx/chisel/chisel_helloworld/)
[info] compiling 1 Scala source to /home/duzelong/ysyx/chisel/chisel_helloworld/target/scala-2.13/classes ...
Multiple main classes detected. Select one to run:
[1] Hello
[2] gcd.GCD
[3] misc.Hello
Enter number:
可见,在不同包里的 Hello
模块不会互相冲突,但是如果两个 Hello.scala
中都有 package misc
,则会下面的结果:
$ sbt run
[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 17.0.12)
[info] loading settings for project chisel_helloworld-build from plugins.sbt ...
[info] loading project definition from /home/duzelong/ysyx/chisel/chisel_helloworld/project
[info] loading settings for project root from build.sbt ...
[info] set current project to chisel_helloworld (in build file:/home/duzelong/ysyx/chisel/chisel_helloworld/)
[info] compiling 1 Scala source to /home/duzelong/ysyx/chisel/chisel_helloworld/target/scala-2.13/classes ...
[info] compiling 2 Scala sources to /home/duzelong/ysyx/chisel/chisel_helloworld/target/scala-2.13/classes ...
[error] /home/duzelong/ysyx/chisel/chisel_helloworld/src/main/scala/misc/Hello.scala:14:7: Hello is already defined as class Hello
[error] class Hello extends Module {
[error] ^
[error] /home/duzelong/ysyx/chisel/chisel_helloworld/src/main/scala/misc/Hello.scala:34:8: Hello is already defined as object Hello
[error] object Hello extends App {
[error] ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 2 s, completed 2024年10月4日 下午7:29:02
就是很经典的符号冲突错误。
接上面的步骤,我们运行 sbt run
后选择 misc.Hello
,则有:
$ sbt run
[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 17.0.12)
[info] loading settings for project chisel_helloworld-build from plugins.sbt ...
[info] loading project definition from /home/duzelong/ysyx/chisel/chisel_helloworld/project
[info] loading settings for project root from build.sbt ...
[info] set current project to chisel_helloworld (in build file:/home/duzelong/ysyx/chisel/chisel_helloworld/)
[info] compiling 2 Scala sources to /home/duzelong/ysyx/chisel/chisel_helloworld/target/scala-2.13/classes ...
Multiple main classes detected. Select one to run:
[1] Hello
[2] gcd.GCD
[3] misc.Hello
Enter number: 3
[info] running misc.Hello
[success] Total time: 10 s, completed 2024年10月4日 下午7:31:03
然后会在根目录里发现多了一个 Hello.sv
,里面就是我们需要的 Verilog 代码,至此本文的目的就达成了。
Others
当然这里还有其他几个值得细究的点。
在哪里都能运行 sbt run
吗?
目前看来是不行,如果在 src/
目录下运行 sbt run
就会有这样的后果:
src$ sbt run
[warn] No sbt.version set in project/build.properties, base directory: /home/duzelong/ysyx/chisel/chisel_helloworld/src
[info] welcome to sbt 1.10.2 (Eclipse Adoptium Java 17.0.12)
[info] set current project to src (in build file:/home/duzelong/ysyx/chisel/chisel_helloworld/src/)
[error] java.lang.RuntimeException: No main class detected.
[error] at scala.sys.package$.error(package.scala:30)
[error] stack trace is suppressed; run last Compile / bgRun for the full output
[error] (Compile / bgRun) No main class detected.
[error] Total time: 1 s, completed 2024年10月4日 下午7:32:24
看来在哪里运行 sbt run
, SBT 就会把哪里当作项目的根目录。
生成 Hello.sv
的位置可以改吗?
在项目根目录运行 sbt run
的时候就会在根目录生成 Hello.sv
。我猜测是直接把输出文件生成在了运行 sbt run
的目录。但是实际上只能在项目根目录运行 sbt run
,因此我的猜测没什么意义。
如果要修改生成 verilog 文件的路径,可能需要深入 SBT 的构建脚本,那就之后再看。
生成 verilog 文件的项目组件是什么?
似乎是用 FIRRTL 生成的,可以再看看。这块应该是 Chisel 自身的特性。
标签:info,sbt,scala,chisel,项目,Chisel,helloworld,Hello From: https://www.cnblogs.com/Chorolop/p/18447183