主体内容摘自:https://blog.csdn.net/qq_34291505/article/details/87880730
一、生成Verilog前面介绍Scala的内容里说过,Scala程序的入口是主函数。所以,生成Verilog的程序自然是在主函数里例化待编译的模块,然后运行这个主函数。
例化待编译模块需要特殊的方法调用。chisel3包里有一个单例对象Driver,它包含一个方法execute,该方法接收两个参数:
- 第一个参数是命令行传入的实参即字符串数组args,
- 第二个是返回待编译模块的对象的无参函数。
运行这个execute方法,就能得到Verilog代码。
假设在src/main/scala
文件夹下有一个全加器的Chisel设计代码,如下所示:
// fulladder.scala
package test
import chisel3._
class FullAdder extends Module {
val io = IO(new Bundle {
val a = Input(UInt(1.W))
val b = Input(UInt(1.W))
val cin = Input(UInt(1.W))
val s = Output(UInt(1.W))
val cout = Output(UInt(1.W))
})
io.s := io.a ^ io.b ^ io.cin
io.cout := (io.a & io.b) | ((io.a | io.b) & io.cin)
}
接着,读者需要在src/test/scala
文件夹下编写对应的主函数文件,如下所示:
// fullAdderGen.scala
package test
object FullAdderGen extends App {
chisel3.Driver.execute(args, () => new FullAdder)
}
注1:chisel3.Driver.execute()
函数的定义如下:
- 第一个参数是args,它是用来传参的,可以在命令行传,也可以直接提供一个数组,具体下面再说;
- 第二个参数dut用来传入一个用户编写的模块的,它是无参、返回类型是RawModule的函数字面量。因为Chisel的模块本质上还是Scala的class,所以只需用new构造一个对象作为返回结果即可。
- 主函数里可以包括多个execute函数,也可以包含其它代码。
注2:chisel3.stage.ChiselStage.execute()
函数说明:
上述函数已经不推荐使用了,若是想使用execute函数,现在推荐使用chisel3.stage.ChiselStage
的execute,其实你在class ChiselStage
里面找不到该函数的定义,那是因为这个函数继承自firrtl.Stage
,定义和使用方法如下:
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
(new chisel3.stage.ChiselStage).execute(args, Seq(ChiselGeneratorAnnotation(() => new FullAdder)))
注3:chisel3.stage.ChiselStage.emitVerilog()
函数说明:
其实还有一个函数更被推荐使用,就是chisel3.stage.ChiselStage.emitVerilog()
,该函数也可以用来生成verilog代码,定义如下,可以看出其实内部也是调用了chisel3.stage.ChiselStage.execute()
这个函数,只不过所需传入的参数更加简单,第一参数不再需要传入一个返回RawModule的无参函数,而是直接将RawModule类型的对象传入即可,这用到了scala的传名参数的语法!!!
(new chisel3.stage.ChiselStage).emitVerilog(new FullAdder,args)
注4: 关于如何运行主函数的说明
建议把设计文件和主函数放在一个包里,比如这里的“package test
”,这样省去了编写路径的麻烦。
这里需要注意的是,放在同一个包里并不是指的同一路径下,这和sbt的编译机制有关,为了简单起见,我们只需要按照sbt的要求存放文件即可,这样就可以省去编写路径的麻烦!!!
要运行这个主函数,需要在build.sbt
文件所在的路径下打开终端,然后执行命令:
sbt 'test:runMain test.FullAdderGen'
注意,sbt后面有空格,再后面的内容都是被单引号对或双引号对包起来。其中,test:runMain
是让sbt执行src/test/scala
路径下的主函数的命令,而test.FullAdderGen
就是要执行的那个主函数。其中test
对应的就是package test
,FullAdderGen
就是单例对象的名字。
其实主函数也可以直接和设计代码写在一起,也即写在 fulladder.scala
文件中,注意这个文件在src/main/scala
路径下,此时如果要运行该主函数,命令需要稍作改变:sbt 'runMain test.FullAdderGen'
。可以看到唯一的区别就是少了test:
,此时的含义是去执行src/main/scala
路径下的主函数。
如果设计文件没有错误,那么最后就会看到“[success] Total time: 6 s, completed Feb 22, 2019 4:45:31 PM
”这样的信息。此时,终端的路径下就会生成三个文件:FullAdder.anno.json、FullAdder.fir和FullAdder.v
。
第一个文件用于记录传递给Firrtl编译器的Scala注解,读者可以不用关心。第二个后缀为“.fir”的文件就是对应的Firrtl代码,第三个自然是对应的Verilog文件。
首先查看最关心的Verilog文件,内容如下:
// FullAdder.v
module FullAdder(
input clock,
input reset,
input io_a,
input io_b,
input io_cin,
output io_s,
output io_cout
);
wire _T; // @[fulladder.scala 14:16]
wire _T_2; // @[fulladder.scala 15:20]
wire _T_3; // @[fulladder.scala 15:37]
wire _T_4; // @[fulladder.scala 15:45]
assign _T = io_a ^ io_b; // @[fulladder.scala 14:16]
assign _T_2 = io_a & io_b; // @[fulladder.scala 15:20]
assign _T_3 = io_a | io_b; // @[fulladder.scala 15:37]
assign _T_4 = _T_3 & io_cin; // @[fulladder.scala 15:45]
assign io_s = _T ^ io_cin; // @[fulladder.scala 14:8]
assign io_cout = _T_2 | _T_4; // @[fulladder.scala 15:11]
endmodule
可以看到,代码逻辑与想要表达的意思完全一致,而且对应的代码都用注释标明了来自于Chisel源文件的哪里。但由于这是通过语法分析的脚本代码得到的,所以看上去显得很笨拙、僵硬,生成了大量无用的中间变量声明。对于下游的综合器而言是一个负担,可能会影响综合器的优化。而且在进行仿真时,要理解这些中间变量也很麻烦。对后端人员来说,这也是让人头疼的问题。
接着再看一看Firrtl代码,内容如下:
// FullAdder.fir
;buildInfoPackage: chisel3, version: 3.2-SNAPSHOT, scalaVersion: 2.12.6, sbtVersion: 1.1.1
circuit FullAdder :
module FullAdder :
input clock : Clock
input reset : UInt
output io : {flip a : UInt, flip b : UInt, flip cin : UInt, s : UInt, cout : UInt}
node _T = xor(io.a, io.b) @[fulladder.scala 14:16]
node _T_1 = xor(_T, io.cin) @[fulladder.scala 14:23]
io.s
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?