索引置顶

SpinalHDL开发

Lambda演算python实现

函数式编程

Scala 笔记

RISCV 开发调试

Chisel 笔记

EDA工具

通信

想法

其他

SpinalHDL(九):不变应万变-MemWrap适配

对于IC开发工程师我们可能都有这样的痛苦经历,经常需要手动为不同工艺库替换Mem。有些团队的MemWrapper可能是有专门的脚本来生成,内部会用宏来区分不同工艺,相对来说还比较省事一点,即便这样MemWrpper的集成也是需要你手动连线。但是如果你是IP提供商,不同的团队或者公司的MemWrapper的信号命名也各不相同。同样替换Mem是一件极其无聊并且容易出错的事情。

1

另外我发现SpinalHDL自带的mem类型并不适合直接拿来做例化,所以需要为此创建一个新的解决方案来满足IC设计中这种常见的需求。spinal的mem模型我会放到Blackbox内部做为行为模型,这样在仿真的时候你可以clearBox来使用mem参考模型来仿真,不需要真正的去包含一个memwrap.v文件,这样在前期设计中非常方便。

因此对于设计者来讲,我本来只需要关心这地方例化的Mem类型(双口,真双口,单口),数据位宽,mem深度即可。除此之外工艺相关的事情对设计者应该是透明的。

可以总结为两点诉求

  • MemWrap替换不应修改HDL代码, 对开发者透明
  • 添加新的Vendor memWrap不应修改Spinal源码,保持前向兼容

2

因此,对于开发者来讲,只需要知道统一的RAM例化接口,为此为Spinal设计常见的3种MEM类型.

SpinalHDL(八):开发仿真测试一条龙

鉴于被chisel的peek poke test愚弄以后,我一度对Scala上的仿真环境不是特别有信心,当看到spinal.sim的时候觉得可能只是一个能work的demo而已,并没有足够重视。

我用Spinal开发的前几个模块依然走的传统的验证流程,先生成Verilog,然后再用scala生成激励,最后打包丢到Linux服务器上, 用Verilog/SV编写tesbech, 搭建测试比对环境,仿真工具不是VCS就是NcSim这些老牌商业软件。

直到一个偶然的机会,有一些很零碎的模块需要测试,不想再为此搭建一整套仿真环境,我想干脆用spinal.sim 简单做个测试,不测不知道,一测一发不可收拾。

SpinalHDL就是这样的汉子,一次又一次的轻视它,但它又不时的给你惊喜。

  • 不同于iotest的peak poke, 它的后台是verilator, verilator非常强大,性能比起商业软件VCS、NC毫不逊色。
  • spinal.sim 通过包装verilator提供的VPI,能够很方便灵活,实时的跟dut交互通信, 加上Scala本身语言的灵活性,它能做的不比UVM少。

今年chisel貌似后知后觉的回过神了,摒弃iotest,重新设计iotester2, iotester2和spinal.sim的思路很类似了, 后台是verilator, 有兴趣的可以自己试试

接下来我主要借助通信基带的两个模块来介绍一些如何使用SpinalHDL进行仿真测试,以及如何构建组织管理回归你的测试CASE。

对于spinal.sim的基础操作和使用请浏览官方文档Spinal-sim,这里不再赘述。

Maven Windows 配置

Maven 仓库timeOut 问题

Scala 工程打包发布依赖

repo1.maven.org\maven2\org\scalaz\scalaz-core_2.12\7.2.14

Scala 单例对象的三个应用

一 进度条

有时候我们在编写代码时希望能够查看运行时间,最简单的方法:

1
2
3
4
5
6
def main(args: Array[String]) {
val startTime: Long = System.currentTimeMillis
待测试的代码块
val endTime: Long = System.currentTimeMillis
System.out.println("程序运行时间: " + (endTime - startTime) + "ms")
}

但这个方法显然不是那么优雅。如果你在使用Scala的时候注意运行log,你会发下进度条更漂亮直观的。

1
2
3
4
5
6
7
[Runtime] SpinalHDL v1.3.9    git head : a4cb4aadf0820174c1b48023bfcd3e9981de1d4a
[Runtime] JVM max memory : 1820.5MiB
[Runtime] Current date : 2020.01.23 10:44:55
[Progress] at 0.000 : Elaborate components
[Progress] at 0.513 : Checks and transforms
[Progress] at 0.705 : Generate Verilog
[Done] at 0.806

实现非常简单,首先得创建一个单例对象,单例对象一旦被实例化以后,startTime就会确定,不管Driver后面被调用多少次只会用到第一次被实例化的对象,startTime也不会改变。

Spinal-sim Verilator install on Windows

Verilator install on Windows

Step1 : install MSYS32

到官网https://www.msys2.org/ 下载最近安装文件 msys2-x86_64-20190524.exe

运行安装到d:/msys64,安装完毕后打开 mingw64.exe

在命令行输入 pacman -Suyy

如果遇到以下异常

1
2
3
4
5
# pacman -Syuu
错误:无法初始化事务处理 (无法锁定数据库)
错误:无法锁定数据库:File exists
如果你确认软件包管理器没有在运行,
你可以删除 /var/lib/pacman/db.lck。

解决办法,删掉之前的文件: /var/lib/pacman/db.lck
出现错误的原因是,之前同步的时候,由于异常中断,导致之前进程锁文件未被释放。

Step2 Change mirrors for China user

如果更新库很慢导致失败

1
2
3
4
5
6
7
# pacman -Syuu
:: 正在同步软件包数据库...
错误:无法从 repo.msys2.org : Operation too slow. Less than 1 bytes/sec transferred the last 10 seconds 获取文件 'mingw32.db'] 49%
错误:无法从 sourceforge.net : Operation too slow. Less than 1 bytes/sec transferred the last 10 seconds 获取文件 'mingw32.db' 3%
错误:无法从 www2.futureware.at : Operation too slow. Less than 1 bytes/sec transferred the last 10 seconds 获取文件 'mingw32.db'7%
错误:无法从 mirror.yandex.ru : Operation too slow. Less than 1 bytes/sec transferred the last 10 seconds 获取文件 'mingw32.db' 10%
错误:无法升级 mingw32 (下载数据库出错)

请更新 清华镜像

编辑 /etc/pacman.d/mirrorlist.mingw32 ,在文件开头添加:

1
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686

编辑 /etc/pacman.d/mirrorlist.mingw64 ,在文件开头添加:

1
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/x86_64

编辑 /etc/pacman.d/mirrorlist.msys ,在文件开头添加:

1
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch

然后执行 pacman -Sy 刷新软件包数据即可。

Step3: Install Verilator

1
2
3
4
5
6
pacman -Syuu
#Close the MSYS2 shell once you're asked to
pacman -Syuu
pacman -S --needed base-devel mingw-w64-x86_64-toolchain \
git flex\
mingw-w64-x86_64-cmake
1
pacman -S mingw-w64-x86_64-verilator

Step4: Add to ENV

Add D:\msys64\usr\bin;D:\msys64\mingw64\bin to you windows PATH

Step4: Spinal simulation by verialtor

1
2
3
4
5
6
7
8
9
10
11
12
[Progress] Verilator compilation started
VDFT2Cell.mk:67: /mingw64/share/verilator/include/verilated.mk: No such file or directory
make: *** No rule to make target '/mingw64/share/verilator/include/verilated.mk'. Stop.
Exception in thread "main" java.lang.AssertionError: assertion failed: Verilator C++ model compilation failed
at scala.Predef$.assert(Predef.scala:170)
at spinal.sim.VerilatorBackend.compileVerilator(VerilatorBackend.scala:376)
at spinal.sim.VerilatorBackend.<init>(VerilatorBackend.scala:429)
at spinal.core.sim.SpinalVerilatorBackend$.apply(SimBootstraps.scala:120)
at spinal.core.sim.SpinalSimConfig.compile(SimBootstraps.scala:400)
at spinal.core.sim.SpinalSimConfig.compile(SimBootstraps.scala:364)
at FFT.DFT2CellTest$.main(FFTsim.scala:27)
at FFT.DFT2CellTest.main(FFTsim.scala)

显示verilated.mk路径找不到,我忍为应该是VERILATOR_ROOT目录设置有误, 查找verilated.mk的目录所在地,
然后在windows Env 中添加系统变量 VERILATOR_ROOT= /d/msys64/mingw64/share/verilator

任然遇到问题

1
2
3
4
5
6
7
8
9
x86_64-w64-mingw32-g++.exe: error: /d/msys64/mingw64/share/verilator/include/verilated.cpp: No such file or directory
x86_64-w64-mingw32-g++.exe: fatal error: no input files
compilation terminated.
make: *** [/d/msys64/mingw64/share/verilator/include/verilated.mk:192: verilated.o] Error 1
make: *** Waiting for unfinished jobs....
x86_64-w64-mingw32-g++.exe: error: /d/msys64/mingw64/share/verilator/include/verilated_vcd_c.cpp: No such file or directory
x86_64-w64-mingw32-g++.exe: fatal error: no input files
compilation terminated.
Exception in thread "main" java.lang.AssertionError: assertion failed: Verilator C++ model compilation failed

x86_64-w64-mingw32-g++.exe 不能访问/d/myss64/….,后来重新安装MSYS2到 C盘,并且将系统变量删除 VERILATOR_ROOT

任然遇到问题:
检查环境变量Paht的值为C:\Users\Administrator\.babun\cygwin\bin;D:\Program\emacs-26.2\bin;C:\Users\Administrator\.babun;C:\Users\Administrator\AppData\Roaming\npm;%IntelliJ IDEA Community Edition%;C:\Users\Administrator\AppData\Local\Pandoc\;c:\msys64\usr\bin\;c:\msys64\mingw64\bin\ 发现很乱 ,删除一些不用的
D:\Program\emacs-26.2\bin;C:\Users\Administrator\.babun;C:\Users\Administrator\AppData\Local\Pandoc\;c:\msys64\usr\bin\;c:\msys64\mingw64\bin\;
更新PATH

重新开启Project , 运行Spinal-sim ,Wow 居然成了, 非常痛苦, 饶了一大圈,居然是PATH变量的问题。总算是解决了

最后:

特别注意:

尽量把MSYS2安装到C盘 在环境变量Path末尾追加C:\msys64\usr\bin;C:\msys64\mingw64\bin

不要多此一举设置VERILATOR_ROOT, Spinal会默认识别到 /mingw64/share/verilator

如果运行不成功,请检查你的PATH,设置是不是非常杂乱,请删除不用的,尽量保持干净。

浮点避坑

浮点数相加

我们知道浮点数尽量避免不同量纲的数相加

1
2
> 1023 + 0.00000000000001
Double = 1023.0

浮点数除法

不同量纲之间的除法也会得到不一样的结果

1
2
3
4
> 1.023/2.047
Double = 0.49975574010747426
> 1023.0/2047.0
Double = 0.49975574010747437

因此对于有些应用可能引入意向不到的结果
比如

1
2
3
4
> 1023.0/2047.0*2.047 == 1.023
Boolean = false
> 1023.0/2047.0*2047 == 1023
Boolean = true

避免不同量纲的数做加减法,还要注意不同量纲的数做乘除法带来的意外结果

典型的例子

1
2
3
0.3 - 0.1
floor( 0.3*10 - 0.1 *10 ) //2.0
floor((0.3 - 0.1)*10 ) //1.0

Double Eps 精度

1
2
Float  (B=2 / p=24): Eps = 2^(-24) = 5.9604644775390625E-8
Double (B=2 / p=53): Eps = 2^(-53) = 1.1102230246251565E-16

也就是说计算机能表示的最小绝对值

1
2
0+1E-16 = E-16
1+1E-16 = 1.0

他的精度跟指数位有关,总共E-16次方的误差范围,指数位占n位,那么误差就等与E(-16+n)

1
2
3
4
1000+1e-16= 1000.0
1000+1e-15= 1000.0
1000+1e-14= 1000.0
1000+1e-13= 1000.0000000000001

只要指数位和分数位之和不要超过16,都可以表示

1
2
3
4
5
6
7
1E10+1E-6 = 1.0000000000000002E10   //能表示1E-6不能表示

1E10+1E-7 = 1.0E10 //误差1E-7不能表示
1E8+1E-7 = 1.000000000000001E8 //指数位8,误差1E-7可以表示
1000000 +1E-10 = 100000.0000000001 //可以表示1E-10
10000000 +1E-10 = 10000000.0 //不能表示1E-10误差,指数位占了7
1E18 + 13 = 1e18

所以你在用浮点计算的时候,要看数的量纲,量纲越大,Eps要设置的大一些, 否则就失去了意义

Scala EPS

所以在判断一个数是否为0是, 不能 a == 0 而是要 abs(a) <= Eps ,
同样在比较两个数是否相等时,不能 a == b 而是要 abs(a - b) <= Eps

BigDecimal

Double的问题是精度有限

1
2
3
val a = 0.02
val b = 0.03
val c = b - a

c的结果不是0.01,而是c: Double = 0.009999999999999998
因此有些系统设计中不能用double,不如金融银行金额计算
为什么会这样呢? 因为float和double都是浮点数, 都有取值范围, 都有精度范围. 浮点数与通常使用的小数不同, 使用中, 往往难以确定.
常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是!
double相减会转换成二进制,因double有效位数为 16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差,解决方法就是使用BigDecimal,它的有效长度足够长可存储小数位数。
因此可代替double来进行加减乘除, 金额必须是完全精确的计算, 故不能使用double或者float, 而应该采用java.math.BigDecimal.

1
2
3
val a = BigDecimal(0.02)
val b = BigDecimal(0.03)
val c = b - a

c的结果得到0.01

1
2
3
val a =  BigInt("1234567890123456").toLong
val b = 0.001
val c = a + b

c的值为1234567890123456,0.01丢失

1
2
3
val a =  BigDecimal("1234567890123456")
val b = BigDecimal(0.001)
val c = a + b

c的值为1234567890123456.001,精度并不会丢失

BigDecimal(value), value可以用数字初始化,太大的值只能用字符串初始化如“123456789012345678”

1
2
3
4
5
6
7
val a =  BigDecimal("1234567890123456001")
val b = BigDecimal(0.1231)
val c = a * b
c.precision
c.rounded
c.scale
c.pow(2)
1
2
3
val c= BigDecimal("1234.5000")
c.doubleValue
c.round(new java.math.MathContext(4, java.math.RoundingMode.HALF_UP))

Spinal-Bootcamp 在线新手教程

最近花了点时间基于Jupyter-notebook做了一个SpinalHDL教程.
方便立即运行查看一个Spinal用法和对应生成的verilog代码,大多数例子来源于SpinalHDL的官方文档,也新增了一些实例和Scala的高级用法,这些可以帮助你理解SpinalHDL如何工作。

目前可以直接点击Binder运行,国内访问Binder速度有点慢,也可以
clone到本地运行。

为什么做这个事情

  • 提供一个SpinalHDL的在线环境,方便测试功能用法,直接查看verilog,而不用新建工程
  • 提供一个Scala的在线环境,方便你测试一些Scala的用法

spinal-bootcamp

SpinalHDL(七):逢山开路-寄存器接口

目前大量存在手写寄存器接口的情况,对于几十个甚至几百个寄存器的IP,即便你有体力,也不能保证不犯错。
70

存在的问题

  • 纯体力活,工作量繁重
  • 容易引入错误,增加验证工作量
  • 文档和代码不同步,增加软件调试工作量

在这类问题上耗费测试debug时间非常不值当,只要你手写寄存器必然会遇到这了问题,软件调了好半天,最后发现文档跟代码不一致,
人是懒惰的,谁能完全保证代码更文档能同步更新,也肯定会犯错的,所以只能通过验证和测试来覆盖,如果问题能够越早发现,成本越低

这里分享二张图:

一张是某软件产品在各个阶段bug的成本
71

另外一张是IC开发各个阶段bug的成本
72

所以尽可能的在前期解决问题,第一次把事情做对,就是节约成本。

Scala3-Macro系统Tasty进展

Scala3 重新设计Macro系统,这是官网英文原文
翻译的很烂,全当学习笔记而已,仅供参考

Or: Scala in a (Tasty) Nutshell

如何迁移到 Scala 3这篇博文中提到最大的一个问题是关于宏的问题。
目前我们正在努力将Tasty和macros对齐,接下来谈一谈我们的想法.

What is Tasty?

Tasty是Scala3的高级交换格式。它基于类型化的抽象语法树
这些树在某种意义上包含了Scala程序中的所有信息。
它们表示程序的语法结构,还包含有关类型和位置的完整信息.
Tasty在语法检查之后(这样所有的类型都显式的知道了,并且隐式的东西都已经解释过了)给代码做一个快照,
但是在快照之前不会经过任何转换,因此所有的信息都不会丢失。
放语法树的文件为了紧凑会压缩优化(有点像javascript的压缩),这意味着我们可以在任何编译器运行期间
生成完整的Tasty语法树,即便是单独编译也不依赖任何其他东西。