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()
}
}
}
}
相关推荐
ThreeYear_s2 小时前
基于FPGA的超声波显示水位距离,通过蓝牙传输水位数据到手机,同时支持RAM存储水位数据,读取数据。
fpga开发
szxinmai主板定制专家3 小时前
【飞腾AI加固服务器】全国产化飞腾+昇腾310+PCIe Switch的AI大模型服务器解决方案
运维·服务器·arm开发·人工智能·fpga开发
GateWorld3 小时前
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (三)数据格式
fpga开发·mipi csi2
hahaha60167 小时前
FPGA静态功耗
fpga开发
碎碎思7 小时前
FPGA定点和浮点数学运算-实例对比
fpga开发
GateWorld18 小时前
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析LLP (二)
fpga开发·mipi csi2
hahaha60161 天前
Xilinx 325T FPGA 中的 GT(GTP 或 GTX)收发器和普通 LVDS 接口的差模和共模电压
fpga开发
hahaha60161 天前
FPGA没有使用的IO悬空对漏电流有没有影响
fpga开发
贝塔实验室2 天前
FPGA 动态重构配置流程
驱动开发·fpga开发·硬件架构·硬件工程·射频工程·fpga·基带工程
GateWorld2 天前
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
fpga开发·mipi csi2