十二 · 2021年11月05日

SpinalHDL—仿真中时钟域驱动

对于仿真而言,与DUT打交道的无非是接口信号的驱动,而我们的设计往往是同步的,这就与避免不了与时钟信号打交道。本文就SpianlHDL下执行仿真时时钟域信号的驱动进行梳理。

时钟域

在SpinalHDL中,时钟域的概念包含了时钟、复位、软复位、时钟使能等系列信号:

ClockDomain(
  clock: Bool
  [,reset: Bool]
  [,softReset: Bool]
  [,clockEnable: Bool]
  [,frequency: IClockDomainFrequency]
  [,config: ClockDomainConfig]
) 

想一想我们在Verilog仿真中做时钟与复位信号驱动的方式:

always #time clk=~clk;
initial
begin
  rstn=1;
  #n;
  rstn=0;
end

而在SpinalHDL里,对于时钟域的驱动其定义了许多的API接口,在SpinalHDL-Doc(参见原文阅读) 中给了详细的API接口描述,根据个人使用下来的经验,个人认为只需掌握下面几个API接口即可仿真使用。

forkStimulus(period)

forkStimulus(period)用于启动一个进程用于驱动时钟域信号,其中传入的period用于指明时钟周期。在SpinalHDL里,下面两种时钟域信号的驱动方式是等价的:

fork {
  dut.clockDomain.assertReset()
  dut.clockDomain.fallingEdge()
  sleep(10)
  while(true) {
    dut.clockDomain.clockToggle()
    sleep(5)
  }
}

dut.clockDomain.forkStimulus(period = 10)

在SpinalHDL里,时钟域定义的配置选项中是会指定时钟是上升沿有效还是下降沿有效,同时也可以指定复位的形式是同步复位还是异步复位,是高电平有效还是低电平有效等,因为通过forkStimulus驱动时钟域信号时在启动的进程里会根据时钟域的配置正确的驱动时钟与复位信号。

forkSimSpeedPrinter(printPeriod)

forkSimSpeedPrinter(printPeriod)可理解为一个辅助API,可以用于在仿真中指定周期打印仿真速度(printPeriod参数可以不填),在仿真起始调用该API后即可在仿真中查看仿真的速度。在仿真中我们可以这么调用该API:

dut.clockDomain.forkSimSpeedPrinter()

在仿真中会看到如下打印信息:
image.png

SimTimeout(time)

SimTimeout(time)用于指定仿真超时时间,当我们对待测试设计运行周期数有大概预期时可通过该API指定仿真周期数。当超过指定周期仿真仍没有正常推出时将会报错。调用形式可直接这么写:

SimTimeout(10000)

waitSampling([cyclesCount])

waitSampling用于等待指定个数的有效时钟采样沿,默认为1个。

这里的有效时钟采样沿是指复位信号已经释放并且时钟有效采样沿触发到来。此外,当我们使用这个API时其执行完成返回时在仿真的时隙上此时在我们的仿真环境里时钟沿“刚刚”过去。

在我们的仿真代码里,我们仿真的启动通常都是这么来写:

SimConfig
    .withWave
      .withConfig(SpinalConfig(
        defaultClockDomainFrequency = FixedFrequency(100 MHz),
        defaultConfigForClockDomains = ClockDomainConfig(resetKind = SYNC)))
    .compile(new addInstSim(8))
    .doSim{dut=>
      dut.init //接口信号初始化
      SimTimeout(10000)//
      dut.clockDomain.forkStimulus(10)
      dut.clockDomain.forkSimSpeedPrinter()
      dut.clockDomain.waitSampling(10)//等待复位信号释放并过十个时钟采样时刻
      testcase()//测试case
    }

waitSamplingWhere(condAnd: => Boolean)

waitSamplingWhere(condAnd: => Boolean)是在waitSampling基础上,在有效时钟沿到来时检测到condAnd条件成立时方返回退出。比方说我们要等待dut输出信号a为高电平然后继续执行下面的激励输入,那么可以这么来写:

dut.clockDomain.waitSamplingWhere(dut.a.toBoolean)

多时钟域

多时钟域的仿真参见文章《SpinalHDL—ClockDomain》

小结

掌握这上述几个API的使用,那么对于仿真激励的编写基本已掌握了一大半,后续将会对DUT接口信号和内部信号的驱动和访问进行总结。

END

作者:玉骐
原文链接:https://mp.weixin.qq.com/s/EJFL8d3qEwUJ9Lk1yECptw
微信公众号:
 title=

推荐阅读

更多SpinalHDL技术干货请关注Spinal FPGA专栏。
推荐阅读
关注数
1581
内容数
133
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息