在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)
就不太了解這個參數的作用了,調整了一下發現並不能改變時鍾的頻率,之后了解的再更新,先留個坑。