首先安装构建环境(我用的系统是LinuxMint):
安装scala: sudo apt install scala; chisel是scala语言编写的库,而scala语言编译出来的字节码运行于JVM;所以会一并安装java运行时环境。
安装sbt: sudo apt install sbt; 安装的版本是1.4.6; sbt是scala的构建工具,可以方便的管理工程和处理依赖包。
设置sbt仓库:~/.sbt/repositories
[repositories]
local
aliyun-maven-public: https://maven.aliyun.com/repository/public
aliyun-maven-central: https://maven.aliyun.com/repository/central
建立一个Hello World工程:
├── build.sbt
├── src
│ ├── main
│ │ └── scala
│ │ └── Hello.scala
│ └── test
│ └── scala
│ └── HelloSpec.scala
import chisel3._
import chisel3.Driver
/**
* 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 {
(new chisel3.stage.ChiselStage).emitVerilog(new Hello())
}
import chisel3.iotesters.PeekPokeTester
import org.scalatest._
class HelloSpec extends FlatSpec with Matchers {
"Hello" should "pass" in {
chisel3.iotesters.Driver(() => new Hello()) { c =>
new PeekPokeTester(c) {
var ledStatus = -1
println("Start the blinking LED")
for (i <- 0 until 100) {
step(10000)
val ledNow = peek(c.io.led).toInt
val s = if (ledNow == 0) "o" else "*"
if (ledStatus != ledNow) {
System.out.println(s)
ledStatus = ledNow
}
}
println("
End the blinking LED")
}
} should be (true)
}
}
build.sbt
scalaVersion := "2.11.12"
scalacOptions := Seq("-deprecation", "-Xsource:2.11")
resolvers ++= Seq(
Resolver.sonatypeRepo("snapshots"),
Resolver.sonatypeRepo("releases")
)
// Chisel 3.4
libraryDependencies += "edu.berkeley.cs" %% "chisel-iotesters" % "1.5.1"
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.3.1"
上述工程实现了LED闪烁的功能,如果有FPGA可以把生成的Hello.v集成一下测试。
在build.sbt所在目录执行sbt compile编译源代码;执行sbt "run Hello"即可生成HDL文件,执行sbt test运行单元测试。我们来看看生成的Verilog代码:
1 module Hello(
2 input clock,
3 input reset,
4 output io_led
5 );
6 `ifdef RANDOMIZE_REG_INIT
7 reg [31:0] _RAND_0;
8 reg [31:0] _RAND_1;
9 `endif // RANDOMIZE_REG_INIT
10 reg [31:0] cntReg; // @[Hello.scala 20:23]
11 reg blkReg; // @[Hello.scala 21:23]
12 wire [31:0] _T_1 = cntReg + 32'h1; // @[Hello.scala 23:20]
13 assign io_led = blkReg; // @[Hello.scala 28:10]
14 always @(posedge clock) begin
15 if (reset) begin // @[Hello.scala 20:23]
16 cntReg <= 32'h0; // @[Hello.scala 20:23]
17 end else if (cntReg == 32'h17d783f) begin // @[Hello.scala 24:28]
18 cntReg <= 32'h0; // @[Hello.scala 25:12]
19 end else begin
20 cntReg <= _T_1; // @[Hello.scala 23:10]
21 end
22 if (reset) begin // @[Hello.scala 21:23]
23 blkReg <= 1'h0; // @[Hello.scala 21:23]
24 end else if (cntReg == 32'h17d783f) begin // @[Hello.scala 24:28]
25 blkReg <= ~blkReg; // @[Hello.scala 26:12]
26 end
27 end
28 // Register and memory initialization
29 `ifdef RANDOMIZE_GARBAGE_ASSIGN
30 `define RANDOMIZE
31 `endif
32 `ifdef RANDOMIZE_INVALID_ASSIGN
33 `define RANDOMIZE
34 `endif
35 `ifdef RANDOMIZE_REG_INIT
36 `define RANDOMIZE
37 `endif
38 `ifdef RANDOMIZE_MEM_INIT
39 `define RANDOMIZE
40 `endif
41 `ifndef RANDOM
42 `define RANDOM $random
43 `endif
44 `ifdef RANDOMIZE_MEM_INIT
45 integer initvar;
46 `endif
47 `ifndef SYNTHESIS
48 `ifdef FIRRTL_BEFORE_INITIAL
49 `FIRRTL_BEFORE_INITIAL
50 `endif
51 initial begin
52 `ifdef RANDOMIZE
53 `ifdef INIT_RANDOM
54 `INIT_RANDOM
55 `endif
56 `ifndef VERILATOR
57 `ifdef RANDOMIZE_DELAY
58 #`RANDOMIZE_DELAY begin end
59 `else
60 #0.002 begin end
61 `endif
62 `endif
63 `ifdef RANDOMIZE_REG_INIT
64 _RAND_0 = {1{`RANDOM}};
65 cntReg = _RAND_0[31:0];
66 _RAND_1 = {1{`RANDOM}};
67 blkReg = _RAND_1[0:0];
68 `endif // RANDOMIZE_REG_INIT
69 `endif // RANDOMIZE
70 end // initial
71 `ifdef FIRRTL_AFTER_INITIAL
72 `FIRRTL_AFTER_INITIAL
73 `endif
74 `endif // SYNTHESIS
75 endmodule
如此ugly的代码,怎么保证scala和HDL的形式验证(formal)?如果后期bug做ECO,网表命名成这样子,可读性这么差怎么搞?生成的Verilog怎么投入验证?chisel版本的迭代兼容性怎么保证?bug修改后继承版本如何回归验证?AMS系统如何验证?在模拟为顶层包数字的电路如何带入scala验证?
我会选择SystemVerilog和Verilog-A,而不是Chisel。