0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SpinalHDL Simulation性能提升測試

Spinal FPGA ? 來源:Spinal FPGA ? 2023-08-06 17:10 ? 次閱讀

昨晚看SpinalHDL的Issues,其中有一個關(guān)于性能提升的case 吸引到了我,嘗試實驗到深夜,測試下在SpinalHDL以及cocotb下的性能優(yōu)化手段。

SpinalHDL Simulation性能提升測試


無論是SpinalHDL還是cocotb,其在仿真方面所采用的思路是一樣的。在SpinalHDL的那個Issue里,Dolu主要想做的是盡可能避免在信號的賦值和讀取上的冗余代碼。以toInt為例,其會調(diào)用getInt函數(shù):

private defgetInt(bt: BaseType):Int = {
if(bt.getBitsWidth == 0) return0
val manager = SimManagerContext.current.manager
val signal = btToSignal(manager, bt)
manager.getInt(signal)
}


而Dolu的思路則是沒有必要每次都重新尋找manager、signal這些信息,畢竟對于一個信號而言這兩個值是不變的。而是提前準備好對于這種頻繁使用的接口則能夠盡可能降低不必要的開銷。

這里做了個測試,testSimNormal采用普通的API調(diào)用形式訪問信號,

testSimSpeed則采用加速后的方式進行訪問一個512bit信號位寬。兩者測試訪問1億次信號值所消耗的時間,測試結(jié)果如下:

testSimNormal 26998ms
testSimSpeed 24462ms

可以看出,還是能夠加速仿真速度的。

考慮到在仿真過程中無非是信號的驅(qū)動和讀取,那么這里應(yīng)該是都適用的,遂以相同的DUT相同的Case嘗試做了如下測試:


testSim1:采用SpinalHDL原生API進行仿真測試

testSim2:將信號的讀取和賦值均改為優(yōu)化后的方式

testSim3:在testSim2的基礎(chǔ)上將時鐘,復(fù)位驅(qū)動也改為優(yōu)化后的方式

testSim4:在testSim2的基礎(chǔ)上將waitSampling修改為優(yōu)化后的方式

testSim5:在testSim3的基礎(chǔ)上將時鐘,將waitSampling修改為優(yōu)化后的方式

測試結(jié)果如下:

testSim1 6469.675 ms
testSim2 6196.007 ms
testSim3 6196.007 ms
testSim4 6066.035 ms
testSim5 6076.121 ms


每個測試里面都是跑了500000周期,可以看到,對于降低延遲還是有效果的。對于更大的case,也許會有更有效的效果。

附上完整的測試代碼(由于電腦較差,諸君可自行測試):

import spinal.core._
import spinal.lib._
import spinal.sim.{Signal, SimManager, SimManagerContext}

import scala.collection.mutable.ArrayBuffer

case class dut() extends Component {
val io = new Bundle {
val data_in = slave Flow (UInt(512 bits))
val data_out = master Flow (UInt(512 bits))
}
noIoPrefix()
io.data_out << io.data_in.translateWith(io.data_in.payload + 1).stage()
}
import spinal.core.sim._

object testSimNormal extends App {
??SimConfig.withFstWave.compile(dut()).doSim { dut =>
dut.io.data_in.valid #= false
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(10)
val startTime = System.currentTimeMillis()
for (index <- 0 until 100000000) {
??????dut.io.data_out.payload.toBigInt
????}
????val endTime = System.currentTimeMillis()
????val totalTime = endTime - startTime
??? println("代碼運行時間:" + totalTime + "毫秒")
??}
}

object testSimSpeed extends App {
??implicit class SimBitVectorPimper(bt: BaseType) {
????class SimProxy(bt: BaseType) {
??????val manager = SimManagerContext.current.manager
??????val signal = manager.raw.userData.asInstanceOf[ArrayBuffer[Signal]](bt.algoInt)
??????val alwaysZero = bt.getBitsWidth == 0

??????def getLong = manager.getLong(signal)

??????def getBoolean = manager.getLong(signal) != 0

??????def getBigInt = manager.getBigInt(signal)

??????def assignBoolean(value: Boolean) = manager.setLong(signal, value.toInt)

??????def setLong(value: Long) = manager.setLong(signal, value)

??????def assignBigInt(value: BigInt) = manager.setBigInt(signal, value)
????}

????def simProxy() = new SimProxy(bt)
??}

??SimConfig.withFstWave.compile(dut()).doSim { dut =>
dut.io.data_in.valid #= false
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(10)
val dataOutHdl = dut.io.data_out.payload.simProxy()
val startTime = System.currentTimeMillis()
for (index <- 0 until 100000000) {
??????dataOutHdl.getBigInt
????}
????val endTime = System.currentTimeMillis()
????val totalTime = endTime - startTime
??? println("代碼運行時間:" + totalTime + "毫秒")
??}
}

object SimExtend {
??implicit class SimBitVectorPimper(bt: BaseType) {
????class SimProxy(bt: BaseType) {
??????val manager = SimManagerContext.current.manager
??????val signal = manager.raw.userData.asInstanceOf[ArrayBuffer[Signal]](bt.algoInt)
??????val alwaysZero = bt.getBitsWidth == 0

??????def getLong = manager.getLong(signal)

??????def getBoolean = manager.getLong(signal) != 0

??????def getBigInt = manager.getBigInt(signal)

??????def assignBoolean(value: Boolean) = manager.setLong(signal, value.toInt)

??????def setLong(value: Long) = manager.setLong(signal, value)

??????def assignBigInt(value: BigInt) = manager.setBigInt(signal, value)
????}

????def simProxy() = new SimProxy(bt)
??}

??def getBool(manager: SimManager, who: Bool): Bool = {
????val component = who.component
????if ((who.isInput || who.isOutput) && component != null && component.parent == null) {
??????who
????} else {
??????manager.userData.asInstanceOf[Component].pulledDataCache.getOrElse(who, null).asInstanceOf[Bool]
????}
??}
}

object testSim extends App {
??val dutCompiled = SimConfig.withFstWave.compile(dut())

??/** *****************************************************************************************
???* testSim1
???* *****************************************************************************************?*/
??dutCompiled.doSim { dut =>
dut.io.data_in.valid #= false
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(10)
var sum = BigInt(0)
for (index <- 0 until 500000) {
??????dut.clockDomain.waitSampling()
??????if (dut.io.data_out.valid.toBoolean) {
????????sum = sum + dut.io.data_out.payload.toBigInt
??????}
??????dut.io.data_in.valid #= true
??????dut.io.data_in.payload #= BigInt(index)
????}
??}

??/** *****************************************************************************************
???* testSim2
???* *****************************************************************************************?*/
??dutCompiled.doSim { dut =>
import SimExtend._
val dataInValidHdl = dut.io.data_in.valid.simProxy()
val dataInDataHdl = dut.io.data_in.payload.simProxy()
val dataOutValidHdl = dut.io.data_out.valid.simProxy()
val dataOutDataHdl = dut.io.data_out.payload.simProxy()
dataInValidHdl.assignBoolean(false)
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(10)
var sum = BigInt(0)
for (index <- 0 until 500000) {
??????dut.clockDomain.waitSampling()
??????if (dataOutValidHdl.getBoolean) {
????????sum = sum + dataOutDataHdl.getBigInt
??????}
??????dataInValidHdl.assignBoolean(true)
??????dataInDataHdl.assignBigInt(index)
????}
??}

??/** *****************************************************************************************
???* testSim3
???* *****************************************************************************************?*/
??dutCompiled.doSim { dut =>
import SimExtend._
val dataInValidHdl = dut.io.data_in.valid.simProxy()
val dataInDataHdl = dut.io.data_in.payload.simProxy()
val dataOutValidHdl = dut.io.data_out.valid.simProxy()
val dataOutDataHdl = dut.io.data_out.payload.simProxy()
val clock = getBool(SimManagerContext.current.manager, dut.clockDomain.clock).simProxy()
val reset = getBool(SimManagerContext.current.manager, dut.clockDomain.reset).simProxy()
dataInValidHdl.assignBoolean(false)
//clock generation
clock.assignBoolean(false)
reset.assignBoolean(true)
sleep(10 * 16)
reset.assignBoolean(false)
fork {
var value = false

def t: Unit = {
value = !value
clock.assignBoolean(value)
delayed(5)(t)
}

t
}
dut.clockDomain.waitSampling(10)
var sum = BigInt(0)
for (index <- 0 until 500000) {
??????dut.clockDomain.waitSampling()
??????if (dataOutValidHdl.getBoolean) {
????????sum = sum + dataOutDataHdl.getBigInt
??????}
??????dataInValidHdl.assignBoolean(true)
??????dataInDataHdl.assignBigInt(index)
????}
??}

??/** *****************************************************************************************
???* testSim4
???* *****************************************************************************************?*/
??dutCompiled.doSim { dut =>
import SimExtend._
val dataInValidHdl = dut.io.data_in.valid.simProxy()
val dataInDataHdl = dut.io.data_in.payload.simProxy()
val dataOutValidHdl = dut.io.data_out.valid.simProxy()
val dataOutDataHdl = dut.io.data_out.payload.simProxy()
val clock = getBool(SimManagerContext.current.manager, dut.clockDomain.clock).simProxy()
val reset = getBool(SimManagerContext.current.manager, dut.clockDomain.reset).simProxy()
var rising = false
var last = false
dataInValidHdl.assignBoolean(false)
//clock generation
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(10)
var sum = BigInt(0)
for (index <- 0 until 500000) {
??????waitUntil {
????????rising = false
????????val current = clock.getBoolean
????????if ((!last) && current) {
??????????rising = true
????????}
????????last = current
????????rising
??????}
??????if (dataOutValidHdl.getBoolean) {
????????sum = sum + dataOutDataHdl.getBigInt
??????}
??????dataInValidHdl.assignBoolean(true)
??????dataInDataHdl.assignBigInt(index)
????}
??}

??/** *****************************************************************************************
???* testSim5
???* *****************************************************************************************?*/
??dutCompiled.doSim { dut =>
import SimExtend._
val dataInValidHdl = dut.io.data_in.valid.simProxy()
val dataInDataHdl = dut.io.data_in.payload.simProxy()
val dataOutValidHdl = dut.io.data_out.valid.simProxy()
val dataOutDataHdl = dut.io.data_out.payload.simProxy()
val clock = getBool(SimManagerContext.current.manager, dut.clockDomain.clock).simProxy()
val reset = getBool(SimManagerContext.current.manager, dut.clockDomain.reset).simProxy()
var rising = false
var last = false
dataInValidHdl.assignBoolean(false)
//clock generation
clock.assignBoolean(false)
reset.assignBoolean(true)
sleep(10 * 16)
reset.assignBoolean(false)
fork {
var value = false

def t: Unit = {
value = !value
clock.assignBoolean(value)
delayed(5)(t)
}

t
}
dut.clockDomain.waitSampling(10)
var sum = BigInt(0)
for (index <- 0 until 500000) {
??????waitUntil {
????????rising = false
????????val current = clock.getBoolean
????????if ((!last) && current) {
??????????rising = true
????????}
????????last = current
????????rising
??????}
??????if (dataOutValidHdl.getBoolean) {
????????sum = sum + dataOutDataHdl.getBigInt
??????}
??????dataInValidHdl.assignBoolean(true)
??????dataInDataHdl.assignBigInt(index)
????}
??}
}
cocotb性能優(yōu)化


cocotb的仿真速度一直我是持保留意見的。在SpinalHDL里面做完嘗試,最近工作里用到的cocotb較多,就嘗試看下能否應(yīng)用到cocotb中??戳讼耤ocotb中的信號讀寫封裝背后的調(diào)用,其做了太多的封裝和調(diào)用。遂采用了相同的DUT做了同樣的測試。首先是做優(yōu)化前后的一百萬次的方式測試(跑一億次真的太久了)

testSimNormal 3.58s
testSimSpeed 1.09s


可以看到,這里有明顯的性能提升。


再來構(gòu)建下面的六個case:


testCase0 :采用cocotb提供的API接口進行數(shù)據(jù)讀寫訪問


testCase1: 僅將信號讀更改為底層接口直接調(diào)用形式進行訪問


testCase2:將信號讀,信號寫均改為底層接口直接調(diào)用形式進行訪問


testCase3:在testCase2的基礎(chǔ)上將信號接口提前生成好而不是使用時例化


testCase4:在testCase4的基礎(chǔ)上將時鐘生成修改為底層接口直接調(diào)用形式


testCase5: 在testCase0基礎(chǔ)上,僅將時鐘生成修改為底層接口直接調(diào)用的形式



測試結(jié)果如下:

190dbb3a-340b-11ee-9e74-dac502259ad0.jpg


每個Case中均做100000次周期測試??梢钥吹?,與原生Case仿真相比,testCase5能提升1.7倍多,而testCase4則有4.8倍的性能提升。由此可見,cocotb中對于信號讀寫的封裝由于做了太多安全和邊界的處理導(dǎo)致這種在仿真中經(jīng)常使用的函數(shù)帶來挺大的開銷。
由于Verilator好像不支持時鐘下沉,如果將時鐘的驅(qū)動給放到Verilog里面,也許還會有進一步的性能提升。
本人對于底層的東西不甚了解,單純從仿真速度上,cocotb相較于SpinalHDL還是有較大的差距(《既生瑜何生亮——SpinalHDL VS Cocotb》),有一點有意思的額是在SpinalHDL里面修改時鐘生成的方式并未有太大的性能提升,而在cocotb里確有明顯改善,諸君有興趣可以自行研究。
附上源碼,感興趣的小伙伴可以自行測試:
DUT:

// Generator : SpinalHDL v1.8.0b git head : 761a30e521263983ddf14de3592f7a9f38bf0589
// Component : simSpeedUpTest

`timescale 1ns/1ps

module dut (
input data_in_valid,
output reg data_out_valid,
input [511:0] data_in,
output reg [511:0] data_out,
input clk,
input reset
);
always @(posedge clk ) begin
if(reset) begin
data_out <= 'd0;
??????data_out_valid<='d0;
????end else?begin
??????data_out <= data_in+1;
??????data_out_valid<= data_in_valid;
????end
??end
endmodule

TestBench:

import cocotb
fromcocotb_bus.drivers import BusDriver
fromcocotb.clock import Clock
fromcocotb.triggers import ClockCycles,RisingEdge,Timer,ReadOnly
fromcocotb.handle import *

@cocotb.test(skip=False)
asyncdef testCaseNormal(dut):
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
dataInvalidSignal=dut.data_in_valid._handle
dataInDataSignal=dut.data_in._handle
cocotb.start_soon(generateClk(dut.clk))
dataInDataSignal.set_signal_val_binstr(0,bin(0)[2:])
dataInvalidSignal.set_signal_val_int(0,0)
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
forindex inrange(1000000):
dut.data_out_valid.value
awaitClockCycles(dut.clk,10)

@cocotb.test(skip=False)
asyncdef testCaseSpeed(dut):
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
dataInvalidSignal=dut.data_in_valid._handle
dataInDataSignal=dut.data_in._handle
cocotb.start_soon(generateClk(dut.clk))
dataInDataSignal.set_signal_val_binstr(0,bin(0)[2:])
dataInvalidSignal.set_signal_val_int(0,0)
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
forindex inrange(1000000):
targetDataSignal.get_signal_val_binstr()
awaitClockCycles(dut.clk,10)

@cocotb.test(skip=False)
asyncdef testCase0(dut):
cocotb.start_soon(Clock(dut.clk,10,'ns').start())
dut.reset.value=1
dut.data_in.value= 0
dut.data_in_valid.value= 0
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
targetSignal=dut.data_out._handle
forindex inrange(100000):
awaitRisingEdge(dut.clk)
ifint(dut.data_out_valid.value) == 1:
sum+= dut.data_out.value
dut.data_in_valid.value= 1
dut.data_in.value= index
awaitClockCycles(dut.clk,100000)

@cocotb.test(skip=False)
asyncdef testCase1(dut):
cocotb.start_soon(Clock(dut.clk,10,'ns').start())
dut.data_in.value= 0
dut.data_in_valid.value= 0
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
forindex inrange(100000):
awaitRisingEdge(dut.clk)
iftargetValueSignal.get_signal_val_long()==1:
sum+= int(targetDataSignal.get_signal_val_binstr(),2)
dut.data_in_valid.value= 1
dut.data_in.value= index
awaitClockCycles(dut.clk,10)


@cocotb.test(skip=False)
asyncdef testCase2(dut):
cocotb.start_soon(Clock(dut.clk,10,'ns').start())
dut.data_in.value= 0
dut.data_in_valid.value= 0
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
forindex inrange(100000):
awaitRisingEdge(dut.clk)
iftargetValueSignal.get_signal_val_long()==1:
sum+= int(targetDataSignal.get_signal_val_binstr(),2)
dut.data_in._handle.set_signal_val_binstr(0,bin(index)[2:])
dut.data_in_valid._handle.set_signal_val_int(0,1)
awaitClockCycles(dut.clk,10)

@cocotb.test(skip=False)
asyncdef testCase3(dut):
cocotb.start_soon(Clock(dut.clk,10,'ns').start())
dut.data_in.value= 0
dut.data_in_valid.value= 0
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
dataInvalidSignal=dut.data_in_valid._handle
dataInDataSignal=dut.data_in._handle
forindex inrange(100000):
awaitRisingEdge(dut.clk)
iftargetValueSignal.get_signal_val_long()==1:
sum+= int(targetDataSignal.get_signal_val_binstr(),2)
dataInDataSignal.set_signal_val_binstr(0,bin(index)[2:])
dataInvalidSignal.set_signal_val_int(0,1)
awaitClockCycles(dut.clk,10)

asyncdef generateClk(clk):
clk._handle.set_signal_val_int(1,0)
whileTrue:
awaitTimer(5, units="ns")
clk._handle.set_signal_val_int(0,0)
awaitTimer(5, units="ns")
clk._handle.set_signal_val_int(0,1)

@cocotb.test(skip=False)
asyncdef testCase4(dut):
targetDataSignal=dut.data_out._handle
targetValueSignal=dut.data_out_valid._handle
dataInvalidSignal=dut.data_in_valid._handle
dataInDataSignal=dut.data_in._handle
cocotb.start_soon(generateClk(dut.clk))
dataInDataSignal.set_signal_val_binstr(0,bin(0)[2:])
dataInvalidSignal.set_signal_val_int(0,0)
dut.reset.value=1
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
forindex inrange(100000):
awaitRisingEdge(dut.clk)
iftargetValueSignal.get_signal_val_long()==1:
sum+= int(targetDataSignal.get_signal_val_binstr(),2)
dataInDataSignal.set_signal_val_binstr(0,bin(index)[2:])
dataInvalidSignal.set_signal_val_int(0,1)
awaitClockCycles(dut.clk,10)

@cocotb.test(skip=False)
asyncdef testCase5(dut):
cocotb.start_soon(generateClk(dut.clk))
dut.reset.value=1
dut.data_in.value= 0
dut.data_in_valid.value= 0
awaitClockCycles(dut.clk,10)
dut.reset.value=0
awaitClockCycles(dut.clk,10)
sum=0
targetSignal=dut.data_out._handle
forindex inrange(100000):
awaitRisingEdge(dut.clk)
ifint(dut.data_out_valid.value) == 1:
sum+= dut.data_out.value
dut.data_in_valid.value= 1
dut.data_in.value= index
awaitClockCycles(dut.clk,100000)
審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 仿真
    +關(guān)注

    關(guān)注

    50

    文章

    4082

    瀏覽量

    133613
  • 信號
    +關(guān)注

    關(guān)注

    11

    文章

    2791

    瀏覽量

    76771
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4788

    瀏覽量

    68616
  • Simulation
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    8170

原文標題:給仿真加點速

文章出處:【微信號:Spinal FPGA,微信公眾號:Spinal FPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    如何實現(xiàn)SpinalHDL 環(huán)境搭建

    據(jù)說SpinalHDL相比chisel更具優(yōu)勢,這讓我有了興趣,今天開始安裝搭建。平常用的linux系統(tǒng)的,但是Intel IDEA安裝在Ubuntu上的時候總是卡的不行,就放棄了,其實
    的頭像 發(fā)表于 08-24 14:43 ?8655次閱讀
    如何實現(xiàn)<b class='flag-5'>SpinalHDL</b> 環(huán)境搭建

    spinalhdl轉(zhuǎn)Verilog可讀性 SpinalHDL開發(fā)流程

    SpinalHDL是基于Scala全新的硬件描述語言,解決了不少Verilog等傳統(tǒng)HDL語言的痛點,可以快速的完成某些IP的開發(fā),和完美的融入現(xiàn)有的開發(fā)流程。 誠然SpinalHDL的學習路線
    的頭像 發(fā)表于 07-27 09:29 ?2293次閱讀
    <b class='flag-5'>spinalhdl</b>轉(zhuǎn)Verilog可讀性 <b class='flag-5'>SpinalHDL</b>開發(fā)流程

    如何提升EMC性能?

    在電源模塊應(yīng)用中,EMC 設(shè)計往往是重中之重,因為關(guān)乎整個用戶產(chǎn)品的 EMC 性能。那么如何提升 EMC 性能呢?本文從電源模塊的設(shè)計與應(yīng)用角度為您解讀。EMC 測試又叫做電磁兼容,描
    發(fā)表于 10-29 07:07

    關(guān)于SpinalHDL中的驗證覆蓋率收集簡單說明

    在做RTL仿真驗證時,覆蓋率收集往往是我們在驗證中需要注意的地方,本篇就SpinalHDL中的驗證覆蓋率收集做一個簡單說明。sbt配置在SpinalHDL里進行仿真驗證時,我們的待測試代碼會生
    發(fā)表于 06-24 15:56

    SpinalHDL測試平臺搭建進行說明

    對于RTL設(shè)計而言,仿真驗證是上板前必不可少的一環(huán)。當我們的代碼基于SpinalHDL進行設(shè)計時,自然也想通過基于scala來進行測試驗證。測試平臺該有的樣子對于仿真驗證而言,簡單的仿真對比驗證我們
    發(fā)表于 07-20 14:38

    SpinalHDL是如何讓仿真跑起來的

    時,SpinalHDL會將的邏輯設(shè)計轉(zhuǎn)換成Verilog代碼,然后將Verilog代碼交給仿真器去編譯生成可執(zhí)行二進制文件。而我們由Scala編寫的測試代碼則會調(diào)用仿真器的VPI接口與設(shè)計邏輯進行數(shù)據(jù)交互,其
    發(fā)表于 07-25 15:09

    如何在SpinalHDL里啟動一個仿真

    使用SpinalHDL已經(jīng)集成好的接口來搭建仿真環(huán)境。SimConfig用于配置仿真環(huán)境參數(shù)。doSim里構(gòu)建仿真環(huán)境及測試case。SimConfig里的參數(shù)配置可分為三類:仿真環(huán)境配置。DUT配置及編譯。仿真啟動
    發(fā)表于 07-26 16:59

    SpinalHDL設(shè)計錯誤總結(jié)相關(guān)資料分享

    1、SpinalHDL設(shè)計錯誤  SpinalHDL編譯器會做很多設(shè)計檢查,來確保生成的VHDL/Verilog是可仿真的可綜合的。基本上,SpinalHDL不會生成破損的VHDL/Verilog
    發(fā)表于 10-24 15:37

    基于Windows系統(tǒng)的SpinalHDL開發(fā)環(huán)境搭建步驟

    開發(fā)所需軟件SpinaHDL環(huán)境搭建所需的軟件安裝包,SpinalHDL是Scala語言的一個庫,開發(fā)Scala需要使用IDEA軟件;JDK17、SDK:Scala2.12.15,SBT1.5.5
    發(fā)表于 10-24 15:40

    SpinalHDL中的對應(yīng)關(guān)系及聲明形式

    針對SpinalHDL中的兩大類型Reg、Wire,來梳理下在SpinalHDL中的對應(yīng)關(guān)系及聲明形式。
    的頭像 發(fā)表于 07-03 11:02 ?1569次閱讀

    SpinalHDL里如何實現(xiàn)Sobel邊緣檢測

    書接上文,趁著今天休假,采用SpinalHDL做一個小的demo,看看在SpinalHDL里如何優(yōu)雅的實現(xiàn)Sobel邊緣檢測。
    的頭像 發(fā)表于 08-26 08:59 ?1290次閱讀

    SpinalHDL BlackBox時鐘與復(fù)位

    SpinalHDL中使用之前已有的Verilog等代碼的時候需要將這些代碼包在一個BlackBox里面,但是如果這些代碼里面有時鐘和復(fù)位,我們需要怎么將時鐘和復(fù)位端口和SpinalHDL中已有的時鐘域連接起來呢?
    的頭像 發(fā)表于 05-04 11:13 ?815次閱讀
    <b class='flag-5'>SpinalHDL</b> BlackBox時鐘與復(fù)位

    SpinalHDL語法之Bool類型

    作為SpinalHDL語法篇的第一節(jié),我們也從最簡單的開始。 Bool類型定義
    的頭像 發(fā)表于 05-05 16:01 ?614次閱讀

    SOLIDWORKS Simulation 2024的10大新功能

    SOLIDWORKS Simulation是一款強大的工程仿真軟件,它能夠幫助工程師們對產(chǎn)品進行詳盡的分析,以確保產(chǎn)品在實際使用中的性能和可靠性。SOLIDWORKS Simulation 2024作為新版本,帶來了一系列令人興
    的頭像 發(fā)表于 01-26 15:12 ?1126次閱讀
    SOLIDWORKS <b class='flag-5'>Simulation</b> 2024的10大新功能

    SOLIDWORKS教育版——SIMULATION

    借助快速、易用的CAD 嵌入式分析解決方案 SOLIDWORKS Simulation,工程師和設(shè)計人員可對設(shè)計性能進行模擬和分析。您可以快速、輕松地采用先進的仿真技術(shù)來在設(shè)計的同時測試性能
    的頭像 發(fā)表于 03-04 15:31 ?479次閱讀
    SOLIDWORKS教育版——<b class='flag-5'>SIMULATION</b>