-
-
Notifications
You must be signed in to change notification settings - Fork 336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
need support for using Bundle in simulation #392
Comments
Hi, Right, you can't use the bundle stuff as a whole. but you can access its elements. To workaround that issue, i have some "dirty" SimData classe which use Bundle introspection to copy all its values :
It isn't perfect, but can be usefull. So, i would say, either use that SimData class to capture things, else you may have usage into iterate on the elements of your bundle via the Bundle.elements function. Can you show me the Bundle in question ? |
Let's start with a simple case
If I want to test this unit, what should I do?
|
|
@Dolu1990
I tried to use the code below,but fail to compile
|
object Play1 {
class Rgb extends Bundle{
val r,g,b = UInt(8 bits)
}
class MyTopLevel extends Component {
val io = new Bundle {
val rgbin = in (new Rgb)
val rgbout = out(new Rgb)
}
io.rgbout.setAsReg()
io.rgbout := io.rgbin
}
def main(args: Array[String]): Unit = {
import spinal.core.sim._
SimConfig.compile(new MyTopLevel).doSim{dut =>
dut.clockDomain.forkStimulus(10)
for(i <- 0 until 100){
val ref = SimData.copy(dut.io.rgbin)
dut.io.rgbin.randomize()
dut.clockDomain.waitSampling()
if(i != 0) assert(ref.check(dut.io.rgbout))
}
}
}
}
object Play2 {
class Rgb extends Bundle{
val r,g,b = UInt(8 bits)
}
class MyTopLevel extends Component {
val io = new Bundle {
val rgbin = in (new Rgb)
val rgbout = out(new Rgb)
}
io.rgbout.setAsReg()
io.rgbout.r := io.rgbin.r
io.rgbout.g := io.rgbin.g
io.rgbout.b := io.rgbin.b + 1//Add one!
}
def main(args: Array[String]): Unit = {
import spinal.core.sim._
SimConfig.compile(new MyTopLevel).doSim{dut =>
dut.clockDomain.forkStimulus(10)
for(i <- 0 until 100){
val ref = SimData()
ref.r = dut.io.rgbin.r.toBigInt
ref.g = dut.io.rgbin.g.toBigInt
ref.b = dut.io.rgbin.b.toBigInt + 1
dut.io.rgbin.randomize()
dut.clockDomain.waitSampling()
if(i != 0) assert(ref.check(dut.io.rgbout))
}
}
}
} |
Basicaly, the Dynamic trait of the SimData class allow to use it a bit like a dynamicaly typed class. (bit like in python) |
val ref = SimData.copy(dut.io.rgbin)
ref.b = ref.b.asInstanceOf[BigInt] + 1 //Not the greated syntax in the world, that's not realy the intend of SimData I don't know, in practice with the testbench i had to do, i didn't falled in this kind of usages. Basicaly, what is done is that i model in scala my stimulus, that then i apply to both hardware and reference model. Then i check the dut against the reference model. And basicaly, the nature of the stimulus generation and the reference model being in a fondamental nature different from the hardware one, there wasn't realy a gain trying to reuse Bundle structure in my testbenches. |
@Dolu1990 I can only check that my model run funtionaly as my expect, rather than cycle by cycle (or is there a better way to do this? SimData is really helpful now , but I think native support for Bundle using in Simulation will be better.like when we using verilog,we use the same data type in sim as we use in design, so we won't need to deal with a lot of type conversion |
@ArcheyChen native supoort for Bundle Depending on how you define the drive method, spinal can't help you decide how to drive the bundle. object palyRGB extends App{
case class RGB() extends Bundle{
val r = UInt( 8 bit)
val g = UInt( 8 bit)
val b = UInt( 8 bit)
def #=(rgb: (Int, Int, Int)): Unit ={
import spinal.core.sim._
r #= rgb._1
g #= rgb._2
b #= rgb._3
}
def monitor() = (r.toLong, g.toLong, b.toLong)
}
class Top extends Component {
val io = new Bundle{
val din = slave Flow(RGB())
val dout = master Flow(RGB())
}
io.dout := RegNext(io.din)
private val outcollect = new ListBuffer[(Long, Long, Long)]()
def drive(rgbs: List[(Int, Int, Int)]): Unit = {
outcollect.clear()
fork{//drive
rgbs.foreach{rgb =>
io.din.valid #= true
io.din #= rgb
clockDomain.waitSampling()
}
io.din.valid #= false
clockDomain.waitSampling(10)
println(outcollect)
simSuccess()
}
}
def moniter = {
fork{
sleep(0)
while(true){
val res = io.dout.monitor()
if(io.dout.valid.toBoolean){
outcollect.append(res)
}
clockDomain.waitSampling()
}
}
}
}
val rand = new Random(0)
val data = List.fill(100)(rand.nextInt(128), rand.nextInt(128), rand.nextInt(128))
SpinalSimConfig().withFstWave.compile(new Top).doSimUntilVoid("test"){dut =>
dut.clockDomain.forkStimulus(2)
dut.drive(data)
dut.moniter
}
} another Apb3 Bundle write and read example implicit class APB3Extends(apb3: Apb3){
import spinal.core._
import spinal.core.sim._
def simWrite(addr: Long, data: BigInt)(cd: ClockDomain) = {
cd.waitSampling()
apb3.PSEL #= 0
apb3.PENABLE #= true
apb3.PADDR #= addr
apb3.PWRITE #= true
cd.waitSampling()
apb3.PWDATA #= data
while(!apb3.PREADY.toBoolean){cd.waitSampling()}
}
def simRead(addr: Long)(cd: ClockDomain): BigInt = {
cd.waitSampling()
apb3.PSEL #= 0
apb3.PENABLE #= true
apb3.PADDR #= addr
apb3.PWRITE #= false
cd.waitSampling()
while(!apb3.PREADY.toBoolean){cd.waitSampling()}
sleep(0)
apb3.PRDATA.toLong
} |
This should be addressed in the long term by #879 (like the last example above) |
https://github.com/SpinalHDL/SpinalHDL/issues/392#issuecomment-805624235 |
I think things could be emulated in a soft way, like having a hashmap[Data, BigInt] and having it populated automaticaly by providing a reference bundle. |
@Dolu1990
Hello,I'm using spinal to write a multi-core cache.
But when I try to simulate my code,I found that I can't use things like Bundle in my testbench,and that is really a trouble for me.
like I'm trying to test a out-of-order queue, the payload is a Bundle with dozens of wires.
I have to create a pure scala class ---- same as the Bundle,but use int instead of UInt(), to maintain the data I push to the queue. And it's not a good solution,since I also have to compare every element with [ x.toInt ]
Is there any good plan to deal with this kind of problem? If not,I think using verilog to write a testbench is a better idea
The text was updated successfully, but these errors were encountered: