Accessing signals of the simulation
Read and write signals
Each interface signal of the toplevel can be read and written from Scala:
Syntax |
Description |
---|---|
|
Read a hardware |
|
Read a hardware |
|
Read a hardware |
|
Read a hardware |
|
Read a hardware |
|
Assign a hardware |
|
Assign a hardware |
|
Assign a hardware |
|
Assign a hardware |
|
Assign a hardware |
|
Assign a random value to a SpinalHDL value. |
dut.io.a #= 42
dut.io.a #= 42l
dut.io.a #= BigInt("101010", 2)
dut.io.a #= BigInt("0123456789ABCDEF", 16)
println(dut.io.b.toInt)
Accessing signals inside the component’s hierarchy
To access signals which are inside the component’s hierarchy, you have first to set the given signal as simPublic
.
You can add this simPublic
tag directly in the hardware description:
object SimAccessSubSignal {
import spinal.core.sim._
class TopLevel extends Component {
val counter = Reg(UInt(8 bits)) init(0) simPublic() // Here we add the simPublic tag on the counter register to make it visible
counter := counter + 1
}
def main(args: Array[String]) {
SimConfig.compile(new TopLevel).doSim{dut =>
dut.clockDomain.forkStimulus(10)
for(i <- 0 to 3) {
dut.clockDomain.waitSampling()
println(dut.counter.toInt)
}
}
}
}
Or you can add it later, after having instantiated your toplevel for the simulation:
object SimAccessSubSignal {
import spinal.core.sim._
class TopLevel extends Component {
val counter = Reg(UInt(8 bits)) init(0)
counter := counter + 1
}
def main(args: Array[String]) {
SimConfig.compile {
val dut = new TopLevel
dut.counter.simPublic() // Call simPublic() here
dut
}.doSim{dut =>
dut.clockDomain.forkStimulus(10)
for(i <- 0 to 3) {
dut.clockDomain.waitSampling()
println(dut.counter.toInt)
}
}
}
}
Load and Store of Memory in Simulation
It is possible to modify the contents of Mem
hardware interface
components in simulation. The data argument should be a word-width
value with the address being the word-address within.
There is no API to convert address and/or individual data bits into units other than the natural word size.
There is no API to mark any memory location with simulation X (undefined) state.
Syntax |
Description |
---|---|
|
Read a word from simulator at the word-address. |
|
Write a word to simulator at the word-address. |
Using this simple example using a memory:
case class MemoryExample() extends Component {
val wordCount = 64
val io = new Bundle {
val address = in port UInt(log2Up(wordCount) bit)
val i = in port Bits(8 bit)
val o = out port Bits(8 bit)
val we = in port Bool()
}
val mem = Mem(Bits(8 bit), wordCount=wordCount)
io.o := mem(io.address)
when(io.we) {
mem(io.address) := io.i
}
}
Setting up the simulation we make the memory accessible:
SimConfig.withVcdWave.compile {
val d = MemoryExample()
// make memory accessible during simulation
d.mem.simPublic()
d
}.doSim("example") { dut =>
We can read data during simulation, but have to take care that the data is already available (might be a cycle late due to simulation event ordering):
// do a write
dut.io.we #= true
dut.io.address #= 10
dut.io.i #= 0xaf
dut.clockDomain.waitSampling(2)
// check written data is there
assert(dut.mem.getBigInt(10) == 0xaf)
And can write to memory like so:
// set some data in memory
dut.mem.setBigInt(15, 0xfe)
// do a read to check if it's there
dut.io.address #= 15
dut.clockDomain.waitSampling(1)
assert(dut.io.o.toBigInt == 0xfe)
Care has to be taken that due to event ordering in simulation e.g. the read depicted above has to be delayed to when the value is actually available in the memory.