本文作为SpinalHDL学习笔记第十四篇,记录使用SpinalHDL的一些实用性语法工具。
SpinalHDL学习笔记总纲链接如下:
6.存根(Stub)
7.Assertions
8.Report
9.ScopeProperty
可以将组件层次结构清空作为一个存根(stub):
- class SubSysModule extends Component {
- val io = new Bundle {
- val dx = slave(Stream(Bits(32 bits)))
- val dy = master(Stream(Bits(32 bits)))
- }
- io.dy <-< io.dx
- }
- class TopLevel extends Component {
- val dut = new SubSysModule().stub //instance an SubSysModule as empty stub
- }
例如,它将生成以下 Verilog 代码:
- module SubSysModule (
- input io_dx_valid,
- output io_dx_ready,
- input [31:0] io_dx_payload,
- output io_dy_valid,
- input io_dy_ready,
- output [31:0] io_dy_payload,
- input clk,
- input reset
- );
- assign io_dx_ready = 1'b0;
- assign io_dy_valid = 1'b0;
- assign io_dy_payload = 32'h0;
- endmodule
还可以清空顶部组件:
SpinalVerilog(new Pinsec(500 MHz).stub)
stub 有什么作用?
• 首先遍历所有组件并找出时钟,然后保留时钟
• 然后删除所有子组件
• 然后删除我们不需要的所有赋值和逻辑
• 给输出端口赋值 0
除了 Scala 运行时断言之外,还可以使用以下语法添加硬件断言:
assert(assertion : Bool, message : String = null, severity: AssertNodeSeverity = Error)
严重性等级是:
| 名称 | 描述 |
| NOTE | 用于报告提示性消息 |
| WARNING | 用于报告异常情况 |
| ERROR | 用于报告不应该发生的情况 |
| FAILURE | 用于报告致命情况并关闭仿真 |
一个实际的例子是检查当 ready 为低电平时,握手协议的 valid 信号不应该由高变低:
- class TopLevel extends Component {
- val valid = RegInit(False)
- val ready = in Bool()
- when(ready) {
- valid := False
- }
- // some logic
- assert(
- assertion = !(valid.fall && !ready),
- message = "Valid dropped when ready was low",
- severity = ERROR
- )
- }
可以使用以下语法在 RTL 中添加调试以进行仿真:
- object Enum extends SpinalEnum{
- val MIAOU, RAWRR = newElement()
- }
- class TopLevel extends Component {
- val a = Enum.RAWRR()
- val b = U(0x42)
- val c = out(Enum.RAWRR())
- val d = out (U(0x42))
- report(Seq("miaou ", a, b, c, d))
- }
例如,它将生成以下 Verilog 代码:
$display("NOTE miaou %s%x%s%x", a_string, b, c_string, d);
从 SpinalHDL 1.4.4 开始,还支持以下语法:
report(L"miaou $a $b $c $d")
可以使用 REPORT_TIME 对象显示当前仿真时间:
report(L"miaou $REPORT_TIME")
会导致:
$display("NOTE miaou %t", $time);
范围属性是可以在当前线程本地存储值的东西。它的 API 可用于设置/获取该值,还可以以堆栈方式对部分值进行修改。
换句话说,它是全局变量、 scala 隐式变量、线程本地变量(ThreadLocal)的替代品。
• 与全局变量相比,它允许运行多个线程独立运行相同的代码
• 与 scala 隐式变量相比,它与代码库的耦合较小
• 与线程本地变量(ThreadLocal)相比,它有一些 API 可以收集所有范围属性并稍后将它们恢复到相
同状态
- object Xlen extends ScopeProperty[Int]
- object ScopePropertyMiaou extends App {
- Xlen.set(1)
- println(Xlen.get) //1
- Xlen(2) {
- println(Xlen.get) //2
- Xlen(3) {
- println(Xlen.get) //3
- Xlen.set(4)
- println(Xlen.get) //4
- }
- println(Xlen.get) //2
- }
- }