Skip to content

How to debug Chisel codes

Jianfeng An edited this page May 10, 2017 · 20 revisions

1. 如何调试

1.1 第一步:运行./run-single.sh Top使用C模型检查代码错误

该命令会将Chisel编译为C文件,然后gcc会将C文件编译为可执行文件并仿真。
一般要从第一个错误开始调试,因为后面的错误可能是前面的错误引起的。
所以要控制台输出中找到第一个错误位置,仔细找到是哪个文件出现的错误,看错误在第几行。
注意有的时候所报错误的.scala文件名并不是我们工程中有的文件名,这些文件是Chisel提供的,不用管这些文件错误,我们找到第一个是自己工程中文件名的错误。
找到错误所在文件的第几行具体位置,是解决错误的前提!
常见错误是拼写错误,Chisel是区分大小写的,所以信号名经常写错。
另一种常见错误是语法错误,请大家对照Tutorial手册中给出的正确语法。 在消除所有语法错误之后,你会得到下面的错误信息:
[info] [0.001] SEED 1494290977687
[info] [0.121] EXPECT AT 113 io_test_dm_out got 0 expected 1 FAIL
[info] [0.122] EXPECT AT 114 io_test_dm_out got 0 expected 2004 FAIL
[info] [0.123] EXPECT AT 115 io_test_dm_out got 0 expected 2004 FAIL
test Top Success: 100 tests passed in 121 cycles taking 0.153492 seconds
[info] [0.124] RAN 116 CYCLES FAILED FIRST AT CYCLE 113
================================================================================
Errors: 1: in the following commands
ercesiMIPS Top: test error occurred
================================================================================

这是因为我们在执行完"inst.s"中所有MIPS指令之后,会用expect检查DMM中存储的数据是否正确。
当然如果你一次把单周期MIPS的功能写对了,上面的错误就不会出现,否则你就开始第二步。

1.2 第二步:运行./run-bak.v.sh Top使用Verilog模型调试功能错误

这个命令会将Chisel文件转换为Verilog文件,并仿真产生一个Top.vcd文件。
Top.vcd在子目录test_run_dir中,test_run_dir中会有一个SingleCycle.LauncherXXX的子目录,如果有多个SingleCycle.Launcher目录则选择日期最近的一个查看。
使用gtkWave打开Top.vcd,将想观察的信号拖动到右面窗口,你就可以像使用Modelsim调试一样通过波形分析哪个信号的值出现了错误。


2. 如何避免Chisel3语法变化导致的警告?

2.1 声明寄存器

原语法:val pc = Reg(init = 0.U(30.W))
现语法:val pc = RegInit(0.U(30.W))(复位为0) 或val pc = Reg(UInt(30.W))(不复位)
使用原语法会报一个警告:

DatPath.scala:40: method apply in object Reg is deprecated: Use Reg(t), RegNext(next, [init]) or RegInit([t], init) instead
[warn] val pc = Reg(init = 0.U(30.W))
[warn] ^
[warn] one warning found

2.2 端口方向翻转

原语法:val dat = new DatToCtlIo().flip()
现语法:val dat = Flipped(new DatToCtlIo)
使用原语法会报一个警告:

[info] [0.002] Elaborating design...
[warn] CtlPath.scala:44: Flipped(Data) should be used over Data.flip in class SingleCycle.CtlPath
[info] [0.195] Done elaborating.
[info] [0.000] Elaborating design... [warn] CtlPath.scala:44: Flipped(Data) should be used over Data.flip in class SingleCycle.CtlPath [info] [0.016] Done elaborating.

3. 常见问题

3.1 scala文件中语句的描述顺序有何要求?

回顾一下Verilog中的always语句,一个module内部的always全部是并行执行的,这是硬件的根部特征,所以在Verilog中所有always语句的前后顺序是没有关系的。
Chisel也是类似的思想,所以描述时不用考虑前后关系,Chisel会按照每行语句的信号赋值关系,正确产生符合数据流的电路。

3.2 设计文件与测试文件的区别?

一般工程中,设计文件放在main目录下,其语法必须使用Chisel语法格式撰写;
而测试文件放在test目录下,其语法使用Scala语法撰写。 所以两者的根本区别在于语法格式,因为设计文件是要生成电路的,所以必须用Chisel描述;而测试文件相当testbench,不用生成电路只是用来产生测试激励,所以用scala描述即可。Scala可以提供丰富的语句,让我们进行读写文件等复杂操作。
大家不用专门学习scala,因为我们的测试文件基本不用修改。

3.3 sbt启动下载时间过长怎么办?

由于下载网站在国外,大约下载200MB左右的内容,如果时间过长,可以换一个时间段尝试下载。 另外一种方法是从其他同学那里拷贝相关的文件,复制到自己的机器上。 主要是拷贝用户主目录下的两个隐藏文件夹.sbt和.ivy2。建议先压缩,拷贝后再解压缩。

3.4 明明修改了文件,但是还是显示以前的错误

这很可能是sbt运行目录错误,你修改了其他目录的代码。你可以用pwd命令查看当前目录是否正确,也在编辑器中确认编辑的文件目录是否正确。

3.5 "inst.s"文件放在哪个目录下?

应放在工程根目录,而不是src目录里面。 顺便说一下,"inst.s"可以用MARS汇编器导出,这样调试时应对比MARS单步执行结果看每条指令执行结果是否正确。

3.6 自己安装的Linux注意什么

用java -version检查一下java版本,我们的某些文件需要1.8的支持,如果是1.7版本,请用以下命令更新:
sudo apt-get install openjdk-8-jdk 另外可以把/etc/apt/sources.list文件修改为以下内容,以便加快更新速度:

deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security multiverse

3.7 运行./run-single.sh Top报错“Permission denied”怎么办?

该脚本可能失去了执行权限,可以运行chmod +x ./run-single.sh修复。 也有可能是项目有些文件所属用户发生了变化,可以运行sudo chown -R cs11007 ./ercesiMIPS修复。

3.8 何时使用:=和=

在测试文件中使用=,在设计文件中val声明变量时用=,在设计文件中其他位置全部用:=。

3.9 错误sink or source unavailable to current module.

错误信息:Errors: 1: in the following commands
ercesiMIPS Top: exception Connection between sink (chisel3.core.UInt@57) and source (chisel3.core.UInt@9e) failed @: Sink or source unavailable to current module.
错误定位:在Error上方,会输出一堆信息:

[info] [0.002] Elaborating design...
chisel3.internal.ChiselException: Connection between sink (chisel3.core.UInt@57) and source (chisel3.core.UInt@9e) failed @: Sink or source unavailable to current module.
	at chisel3.internal.throwException$.apply(Error.scala:13)
	at chisel3.core.Data.connect(Data.scala:206)
	at chisel3.core.Data.$colon$eq(Data.scala:272)
	at SingleCycle.Top.<init>(Top.scala:39)
	at SingleCycle.Launcher$$anonfun$2$$anonfun$apply$3.apply(Launcher.scala:26)
	at SingleCycle.Launcher$$anonfun$2$$anonfun$apply$3.apply(Launcher.scala:26)
	at chisel3.core.Module$.do_apply(Module.scala:42)
	at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:92)
	at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:92)
	at chisel3.internal.Builder$$anonfun$build$1.apply(Builder.scala:240)

我们仔细寻找自己的代码在哪里出错,可以看到是Top.scala:39出错。 对应的代码是:

val cpath	= Module(new CtlPath())  
val dpath 	= Module(new DatPath())  
dpath.io.dmem_addr:=dpath.alu9.io.ALUout  

错误原因: 这个错误是因为信号使用层次化引用时某个子模块内部的信号,这样的电路是无法实现的。该语句是在访问top子模块dpath的内部信号,所以无法访问。
解决方法:将该语句挪到datapath.scala中实现,改为:
io.dmem_addr:=alu9.io.ALUout
这样对datapath模块来说,就是将alu模块的一个输出信号连接到datapath模块的输出,这样的电路Verilog才能实现。

3.10 Error:Sink is unwriteable by current module.

错误信息:

ercesiMIPS Top: exception Connection between sink (chisel3.core.UInt@9e) and source (chisel3.core.UInt@5b) failed @: Sink is unwriteable by current module.

错误定位: 在该Error往上找出错信息:

[info] [0.002] Elaborating design...
chisel3.internal.ChiselException: Connection between sink (chisel3.core.UInt@9e) and source (chisel3.core.UInt@5b) failed @: Sink is unwriteable by current module.
	at chisel3.internal.throwException$.apply(Error.scala:13)
	at chisel3.core.Data.connect(Data.scala:206)
	at chisel3.core.Data.$colon$eq(Data.scala:272)
	at SingleCycle.DatPath.<init>(DatPath.scala:43)
	at SingleCycle.Top$$anonfun$7.apply(Top.scala:36)
	at SingleCycle.Top$$anonfun$7.apply(Top.scala:36)
	at chisel3.core.Module$.do_apply(Module.scala:42)
	at SingleCycle.Top.<init>(Top.scala:36)
	at SingleCycle.Launcher$$anonfun$2$$anonfun$apply$3.apply(Launcher.scala:26)
	at SingleCycle.Launcher$$anonfun$2$$anonfun$apply$3.apply(Launcher.scala:26)

可以看到最先报错的是Datapath.scala:43,对应的代码是:

alu9.io.ALUout := io.dmem_datOut

错误分析:这句话显然是错误的,因为ALUout是ALU模块的输出信号,在datapath应该是只读,不能写入。
错误修改:应当对子模块的输出信号全部只读。