Skip to content

Commit

Permalink
Merge pull request #217 from andreasWallner/document_mem_sim_api
Browse files Browse the repository at this point in the history
Document mem sim api
  • Loading branch information
andreasWallner authored Oct 14, 2023
2 parents 3b2882a + e5c2c62 commit 86a7d48
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package spinaldoc.libraries.sequential_logic

import spinal.core._
import spinal.lib._
import spinal.core.sim._

import scala.language.postfixOps

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
}
}
// end case class MemoryExample

object MemorySim extends App {
SimConfig.withVcdWave.compile {
val d = MemoryExample()
// make memory accessible during simulation
d.mem.simPublic()
d
}.doSim("example") { dut =>
dut.io.we #= false
dut.clockDomain.forkStimulus(10)
dut.clockDomain.waitSampling(2)

// 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)

dut.io.we #= false
dut.clockDomain.waitSampling(1)

// 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)
}
}

4 changes: 2 additions & 2 deletions source/SpinalHDL/Sequential logic/memory.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
RAM/ROM
=======
RAM/ROM Memory
==============

To create a memory in SpinalHDL, the ``Mem`` class should be used.
It allows you to define a memory and add read and write ports to it.
Expand Down
86 changes: 58 additions & 28 deletions source/SpinalHDL/Simulation/signal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,6 @@ Each interface signal of the toplevel can be read and written from Scala:
dut.io.a #= BigInt("0123456789ABCDEF", 16)
println(dut.io.b.toInt)
.. _simulation_of_memory:

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.

.. list-table::
:header-rows: 1
:widths: 3 5

* - Syntax
- Description
* - ``Mem.getBigInt(address: Long): BigInt``
- Read a word from simulator at the word-address.
* - ``Mem.setBigInt(address: Long, data: BigInt)``
- Write a word to simulator at the word-address.


Accessing signals inside the component's hierarchy
--------------------------------------------------

Expand Down Expand Up @@ -129,3 +101,61 @@ Or you can add it later, after having instantiated your toplevel for the simulat
}
}
.. _simulation_of_memory:

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.

.. list-table::
:header-rows: 1
:widths: 1 1

* - Syntax
- Description
* - ``Mem.getBigInt(address: Long): BigInt``
- Read a word from simulator at the word-address.
* - ``Mem.setBigInt(address: Long, data: BigInt)``
- Write a word to simulator at the word-address.

Using this simple example using a memory:

.. literalinclude:: /../examples/src/main/scala/spinaldoc/sequential_logic/memory_sim.scala
:language: scala
:start-at: case class MemoryExample
:end-before: // end case class MemoryExample

Setting up the simulation we make the memory accessible:

.. literalinclude:: /../examples/src/main/scala/spinaldoc/sequential_logic/memory_sim.scala
:language: scala
:start-at: SimConfig
:end-at: doSim

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):

.. literalinclude:: /../examples/src/main/scala/spinaldoc/sequential_logic/memory_sim.scala
:language: scala
:start-at: // do a write
:end-at: assert(dut.mem

And can write to memory like so:

.. literalinclude:: /../examples/src/main/scala/spinaldoc/sequential_logic/memory_sim.scala
:language: scala
:start-at: // set some data in memory
:end-at: assert(dut.io

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.
33 changes: 0 additions & 33 deletions source/SpinalHDL/miscelenea/core/core_components.rst
Original file line number Diff line number Diff line change
Expand Up @@ -444,39 +444,6 @@ There is a small component and a ``main`` that generate the corresponding VHDL.
}
}
Memory
------

.. list-table::
:header-rows: 1
:widths: 2 1

* - Syntax
- Description
* - Mem(type : Data,size : Int)
- Create a RAM
* - Mem(type : Data,initialContent : Array[Data])
- Create a ROM


.. list-table::
:header-rows: 1
:widths: 3 2 1

* - Syntax
- Description
- Return
* - mem(x)
- Asynchronous read
- T
* - mem(x) := y
- Synchronous write
-
* - mem.readSync(address,enable)
- Synchronous read
- T


Instantiate VHDL and Verilog IP
-------------------------------

Expand Down

0 comments on commit 86a7d48

Please sign in to comment.