[SpinalHDL] 时钟辅助参数设置
在verilog中只需要规定一个input clk
就能当做输入时钟,最终给他添加一个约束即可。
但是在spinalHDL中,时钟的设计就复杂一些,主要是“时钟域”的概念,在设置时钟域的时候,就会带有一些辅助参数来帮助后续的设计。
典型的例子是,利用时钟频率辅助变量,来进行自动计时的效果。
检测固定时间段内输入信号上升沿个数,检测时长由参数配置,时钟频率提前未知。
Code
传统的Verilog编程需要确定好时钟频率大小和定时时间的长短,手动计算出一个timeout值,然后根据timeout设置一个计数器来实现该操作。
但是在spinal中,时钟域是可以为其设置频率大小的,之后利用SpinalHDL lib中的Timeout模块,就能完成超时操作。
case class example1_2(timeMs:Int,detectRise:Boolean) extends Component{
val io=new Bundle{
val sigIn=in Bool
val clear=in Bool
val cnt=out UInt (32 bits)
}
val counter=new Area{
val timeout=Timeout(timeMs ms)
val incEnable=if(detectRise) io.sigIn.rise(False) else io.sigIn.fall(False)
val cnt=Counter(32 bits,incEnable)
when(io.clear){
cnt.value.clearAll()
}
when(timeout){
timeout.clear()
cnt.value.clearAll()
}
io.cnt:=RegNextWhen(cnt.value,timeout,U(0,32 bits))
}
}
object example1App extends App{
SpinalConfig(
defaultClockDomainFrequency = FixedFrequency(100 MHz)
).generateVerilog(example1_2(1,false)).printPruned()
}
其中,在生成verilog之前指定时钟域频率。SpinalConfig
,就可以进行默认时钟域的频率设置。
Sim
仿真的时候同样要设置仿真时钟的频率
object exSim {
def main(args: Array[String]) {
// 建立仿真 其中RiseCounter 来创建代码
SimConfig.withWave.withConfig(SpinalConfig(defaultClockDomainFrequency = FixedFrequency(100 MHz)))
.doSim(new example1_2(1,false)) { dut =>
// 创建时钟
//Fork a process to generate the reset and the clock on the dut
dut.clockDomain.forkStimulus(20)
// 注意 io的电平赋值用 #=
dut.io.clear #= true
// 等待三个时钟周期,不知道是否有更好的写法
for(idx <- 0 to 3){
dut.clockDomain.waitRisingEdge()
}
dut.io.clear #= false
for(idx <- 0 to 99){
//Drive the dut inputs with random values
dut.io.sigIn #= Random.nextBoolean()
//Wait a rising edge on the clock
dut.clockDomain.waitRisingEdge()
}
}
}
}
在doSim之前,指定仿真时钟的频率,但是其中dut.clockDomain.forkStimulus(20)
就不太了解这个参数的作用了,调整了一下发现并不能改变时钟的频率,之后了解的再更新,先留个坑。