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()
}
}
}
}
相关推荐
博览鸿蒙5 小时前
FPGA 工程中常见的基础硬件问题
fpga开发
GateWorld9 小时前
FPGA 实现无毛刺时钟切换
fpga开发·实战·无毛刺时钟
Seraphina_Lily11 小时前
从接口选型到体系结构认知——谈 CPU–FPGA–DSP 异构处理系统与同构冗余设计
fpga开发
Seraphina_Lily13 小时前
CPU–FPGA–DSP 异构系统中的总线接口选型——为什么 CPU 用 eLBC,而 DSP 用 XINTF?
fpga开发
GateWorld13 小时前
FPGA开发十年心路
fpga开发
ALINX技术博客1 天前
【ALINX 教程】FPGA Multiboot 功能实现——基于 ALINX Artix US+ AXAU25 开发板
fpga开发·fpga
Genevieve_xiao1 天前
【verilog】如何一小时成为verilog高手(并非
fpga开发
从此不归路1 天前
FPGA 结构与 CAD 设计(第3章)上
ide·fpga开发
Aaron15881 天前
基于VU13P在人工智能高速接口传输上的应用浅析
人工智能·算法·fpga开发·硬件架构·信息与通信·信号处理·基带工程
碎碎思1 天前
在 FPGA 上实现并行脉冲神经网络(Spiking Neural Net)
人工智能·深度学习·神经网络·机器学习·fpga开发