SpinalHDL之仿真(八)

本文作为SpinalHDL学习笔记第三十六篇,介绍SpinalHDL仿真示例。

目录:

1.异步加法器

2.双时钟域 FIFO

3.单时钟域 FIFO

1.异步加法器

此示例使用组合逻辑创建一个 Component ,对 3 个操作数执行一些简单的算术运算。

测试平台执行 100 次以下步骤:
• 将 a, b, 和 c 初始化为 0..255 范围内的随机整数。
• 激励 DUT (Device Under Test) 匹配 a, b, c 的输入。
• 等待 1 个仿真步长(以允许输入传播)。
• 检查输出是否正确。

Scala 复制代码
import spinal.core._
import spinal.core.sim._
import scala.util.Random
object SimAsynchronousExample {
class Dut extends Component {
val io = new Bundle {
val a, b, c = in UInt (8 bits)
val result = out UInt (8 bits)
}
io.result := io.a + io.b - io.c
}
def main(args: Array[String]): Unit = {
SimConfig.withWave.compile(new Dut).doSim{ dut =>
var idx = 0
while(idx < 100){
val a, b, c = Random.nextInt(256)
dut.io.a #= a
dut.io.b #= b
dut.io.c #= c
sleep(1) // Sleep 1 simulation timestep
assert(dut.io.result.toInt == ((a + b - c) & 0xFF))
idx += 1
}
}
}
}

2.双时钟域 FIFO

此示例创建了一个专为跨时钟域而设计的 StreamFifoCC 以及 3 个仿真线程。

线程处理:
• 两个时钟域的管理
• 推入 FIFO
• 从 FIFO 弹出

FIFO 推送线程将输入随机化。

FIFO 弹出线程根据参考模型(普通的 scala.collection.mutable.Queue 实例)检查 DUT 的输出。

Scala 复制代码
import spinal.core._
import spinal.core.sim._
import scala.collection.mutable.Queue
object SimStreamFifoCCExample {
def main(args: Array[String]): Unit = {
// Compile the Component for the simulator.
val compiled = SimConfig.withWave.allOptimisation.compile(
rtl = new StreamFifoCC(
dataType = Bits(32 bits),
depth = 32,
pushClock = ClockDomain.external("clkA"),
popClock = ClockDomain.external("clkB",withReset = false)
)
)
// Run the simulation.
compiled.doSimUntilVoid{dut =>
val queueModel = mutable.Queue[Long]()
// Fork a thread to manage the clock domains signals
val clocksThread = fork {
// Clear the clock domains' signals, to be sure the simulation captures␣
,→their first edges.
dut.pushClock.fallingEdge()
dut.popClock.fallingEdge()
dut.pushClock.deassertReset()
sleep(0)
// Do the resets.
dut.pushClock.assertReset()
sleep(10)
dut.pushClock.deassertReset()
sleep(1)
// Forever, randomly toggle one of the clocks.
// This will create asynchronous clocks without fixed frequencies.
while(true) {
if(Random.nextBoolean()) {
dut.pushClock.clockToggle()
} else {
dut.popClock.clockToggle()
}
sleep(1)
}
}

// Push data randomly, and fill the queueModel with pushed transactions.
val pushThread = fork {
while(true) {
dut.io.push.valid.randomize()
dut.io.push.payload.randomize()
dut.pushClock.waitSampling()
if(dut.io.push.valid.toBoolean && dut.io.push.ready.toBoolean) {
queueModel.enqueue(dut.io.push.payload.toLong)
}
}
}
// Pop data randomly, and check that it match with the queueModel.
val popThread = fork {
for(i <- 0 until 100000) {
dut.io.pop.ready.randomize()
dut.popClock.waitSampling()
if(dut.io.pop.valid.toBoolean && dut.io.pop.ready.toBoolean) {
assert(dut.io.pop.payload.toLong == queueModel.dequeue())
}
}
simSuccess()
}
}
}
}

3.单时钟域 FIFO

此示例创建一个 StreamFifo,并生成 3 个仿真线程。与Dual clock ffo 示例不同,此 FIFO 不需要复杂的时钟管理。

3 个仿真线程处理:
• 管理时钟/复位
• 推入 FIFO
• 从 FIFO 弹出

FIFO 推送线程将输入随机化。

FIFO 弹出线程根据参考模型(普通的 scala.collection.mutable.Queue 实例)检查 DUT 的输出。

Scala 复制代码
import spinal.core._
import spinal.core.sim._
import scala.collection.mutable.Queue
object SimStreamFifoExample {
def main(args: Array[String]): Unit = {
// Compile the Component for the simulator.
val compiled = SimConfig.withWave.allOptimisation.compile(
rtl = new StreamFifo(
dataType = Bits(32 bits),
depth = 32
)
)

// Run the simulation.
compiled.doSimUntilVoid{dut =>
val queueModel = mutable.Queue[Long]()
dut.clockDomain.forkStimulus(period = 10)
SimTimeout(1000000*10)
// Push data randomly, and fill the queueModel with pushed transactions.
val pushThread = fork {
dut.io.push.valid #= false
while(true) {
dut.io.push.valid.randomize()
dut.io.push.payload.randomize()
dut.clockDomain.waitSampling()
if(dut.io.push.valid.toBoolean && dut.io.push.ready.toBoolean) {
queueModel.enqueue(dut.io.push.payload.toLong)
}
}
}
// Pop data randomly, and check that it match with the queueModel.
val popThread = fork {
dut.io.pop.ready #= true
for(i <- 0 until 100000) {
dut.io.pop.ready.randomize()
dut.clockDomain.waitSampling()
if(dut.io.pop.valid.toBoolean && dut.io.pop.ready.toBoolean) {
assert(dut.io.pop.payload.toLong == queueModel.dequeue())
}
}
simSuccess()
}
}
}
}
相关推荐
何事误红尘3 小时前
ZYNQ学习FPGA笔记(一):vivado安装、XC7Z045
fpga开发
zlinear数据采集卡21 小时前
D223的SRAM硬件记录仪:外部触发与瞬态波形捕获方案
arm开发·嵌入式硬件·fpga开发·开源
szxinmai主板定制专家1 天前
基于 RK3588 + Xilinx Kintex-7 FPGA 异构工业主控板设计方案
arm开发·人工智能·嵌入式硬件·fpga开发·zynq
Rambo.xia1 天前
RFSoC高速采集卡设计项目:一块板卡串联综合优化5大核心技术
单片机·嵌入式硬件·fpga开发
XMAIPC_Robot1 天前
RK3588+STM32:高性能机器人运动控制解决方案,兼顾实时性与AI算力
人工智能·stm32·嵌入式硬件·算法·fpga开发·机器人·arm+fpga
zlinear数据采集卡1 天前
D223的DDS信号发生器:10000点查找表与4通道16位DAC波形输出
arm开发·嵌入式硬件·fpga开发·开源
物质波波波2 天前
WS-RPE:面向边缘物理AI实时特征值计算的硬件工作窃取调度器与冗余PE激活架构
人工智能·fpga开发·架构·系统架构·硬件架构
我爱C编程2 天前
基于FPGA的DSB调制解调系统verilog开发
fpga开发·verilog·fpga·dsb
zlinear数据采集卡2 天前
USB HS 480M高速传输与SRAM记录仪:DABM-D223数据存储系统全解析
arm开发·嵌入式硬件·fpga开发·开源
逻辑诗篇2 天前
基于 XCVU13P 的 4 路 100G 光纤 PCIe 处理板 PCIE727 硬件规格全解析
fpga开发