吃透Chisel语言.09.Chisel项目构建、运行和测试(一)——用sbt构建Chisel项目并运行

Chisel项目构建、运行和测试(一)——用sbt构建Chisel项目并运行

上一大部分介绍了Chisel的基础语法,但除了教程开始的Demo以外,我们还没有开始写Chisel代码,这对于学习编程语言来说是大忌。不过好在Chisel基础语法部分内容并不算多,眼睛过一遍可能也掌握个大差不差了。但不能总这样,所以这一部分就来讲讲如何开始我们的Chisel项目。

如何开始Chisel项目

那么构建Chisel项目我们需要了解哪些东西呢?

首先,我们得知道怎么编译Chisel程序吧?其次,我们得知道怎么用Chisel代码生成Verilog代码来在FPGA上执行吧?再者我们还得知道怎么写测试来调试和验证我们的代码是否正确吧?

Chisel是用Scala写的,所以支持构建Scala项目的过程应该在Chisel项目上也适用。而Scala上一个流行的构建工具就是sbt,它是Scala interactive Build Tool的缩写。这个sbt不仅能够驱动编译和测试过程,还能够给Scala和Chisel下载正确版本的库,也就是有包管理的功能。

目前Chisel流行的项目构建工具就是sbt和mill,我们这里用sbt构建我们的项目。

关于sbt和build.sbt配置文件

Scala库中与Chisel和Chisel tester相关的部分是在构建过程从一个Maven仓库中下载下来的,而这些库是通过build.sbt文件引用的。Chisel项目中一个典型的build.sbt文件内容如下:

// See README.md for license details.

ThisBuild / scalaVersion     := "2.13.8"
ThisBuild / version          := "0.1.0"
ThisBuild / organization     := "com.github.github3rr0r"

val chiselVersion = "3.5.1"

lazy val root = (project in file("."))
  .settings(
    name := "OhMyChisel",
    libraryDependencies ++= Seq(
      "edu.berkeley.cs" %% "chisel3" % chiselVersion,
      "edu.berkeley.cs" %% "chiseltest" % "0.5.1" % "test"
    ),
    scalacOptions ++= Seq(
      "-language:reflectiveCalls",
      "-deprecation",
      "-feature",
      "-Xcheckinit",
      "-P:chiselplugin:genBundleElements",
    ),
    addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full),
  )


我们可以在build.sbt文件中配置latest.release来指定使用最新的Chisel版本,但是这样做的缺点就是每次都会从在线的Maven仓库中再搜索,如果没有联网的话就会构建失败。所以最好的做法还是在build.sbt中指定特定的Chisel版本,其他的Scala库也一样。

比如上面给出的典型build.sbt文件中,Scala版本指定为"2.13.8",Chisel版本指定为"3.5.1"chiseltest版本指定为"0.5.1"。指定版本不仅仅避免了没网时的尴尬,同时也保持了较好项目稳定性,比如由于Chisel发展较快,所以API不兼容的情况就在Chisel上时有发生。

Chisel项目源代码组织结构

sbt继承了Maven构建自动化工具的源代码组织结构约定,同时Maven也是开源Java库的仓库的管理者,Chisel在Maven仓库中的仓库在这里:Maven Repository: edu.berkeley.cs » chisel3 (mvnrepository.com)。

下面这张图展现了典型的Chisel项目源代码组织结构:

吃透Chisel语言.09.Chisel项目构建、运行和测试(一)——用sbt构建Chisel项目并运行_第1张图片

project文件夹就是项目根目录,你也可以起其它名字,这个根目录就包含了build.sbt,也有可能会包含一个用于构建过程的Makefile文件,还有可能会有README文件和LICENSE文件。

项目根目录中的src文件夹包含了全部的源代码,其中划分了main文件夹和test文件夹,前者包含了所有的硬件源码,后者包含了所有的测试器代码。Chisel是从Scala继承的,Scala又是从Java继承了源码软件包的组织结构。包(Package)可以把我们的Chisel代码组织为命名空间,包也可以包含子包。

项目根目录下的target文件夹包含了类字节码文件和其他生成的文件,通常我们不在这个文件夹放我们生成的Verilog文件,而是在根目录下的generated文件夹下生成Verilog文件。

为了在Chisel中利用命名空间的便利性,我们需要声明我们在某个包下定义了一个类,比如下面的例子就是在mypack包中定义了一个Abc类:

package mypack

import chisel3._

class Abc extends Module {
    val io = IO(new Bundle{})
}

需要注意的是,这里我们导入了chisel3这个包来使用Chisel中的类。

那现在我们想在其他上下文中(即不同的包命名空间)使用模块Abc,那么我们就需要导入mypack包中的组件:

import mypack._

class AbcUser extends Module {
    val io = IO(new Bundle{})
    val abc = new Abc()
}

上面两段代码中的下划线_表示通配符,意思是包里面所有的类都会导入。

也可以不从mypack导入所有的类型,而是使用完整名称mypack.Abc来指示mypack包中的Abc

class AbcUser2 extends Module {
    val io = IO(new Bundle{})
    val abc = new mypack.Abc()
}

还可以只导入Abc这一个类来创建实例:

import mypack.Abc

class AbcUser extends Module {
    val io = IO(new Bundle{})
    val abc = new Abc()
}

用sbt运行Chisel项目

简简单单一条指令就可以用sbt编译并运行Chisel项目:

sbt run

这条指令会从源代码树编译所有的Chisel代码,并类中搜索包含main方法的对象的类,或者更简单地直接搜索从App拓展的对象。如果找到了多个对象,那就会列举出所有符合条件的对象,我们可以选择一个来执行。我们也可以直接指定执行某个对象,将它作为参数传递给sbt即可:

sbt "runMain mypacket.MyObject"

sbt默认值搜索源码树中的main部分,而不会搜索test部分,这个约定也是从Java和Scala来的。如果要执行基于ChiselTestScalaTest的测试,直接运行这条代码就行:

sbt test

如果我们写一个测试,没有遵循ChiselTest的约定且包含了一个main函数,但是又把它放在了源代码树的test文件夹下,我们可以这么执行:

sbt "test:runMain mypacket.MyMainTest"

结语

这一篇介绍了sbt和怎么用sbt构建、运行Chisel项目,还介绍了Chisel项目的源代码组织结构,差不多就可以实践了。但在开始实践之前我们还有两个问题没有解决,一个是怎么生成Verilog代码,另一个是怎么写测试、运行测试。虽然这篇文章还提到了用sbt运行测试,但是怎么写完全不知道。接下来,我们还会有几篇文章,前一篇介绍Chisel怎么生成Verilog代码以及Chisel的工具流,后面几篇介绍怎么写Chisel测试和调试的四种姿势。

你可能感兴趣的:(吃透Chisel语言!!!,Chisel,计算机体系结构,risc-v,CPU设计实现,sbt)