Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 22 additions & 16 deletions examples/src/main/scala/spinaldoc/examples/advanced/Slots.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,38 @@ case class SlotsDemo(slotsCount : Int) extends Component {
// ...


// Create the hardware for each slot
// Note each slot is an Area, not a Bundle
// Create the hardware for each slot.
// Note each slot is an Area, not a Bundle.
val slots = for(i <- 0 until slotsCount) yield new Area {
// Because the slot is an Area, we can define mix signal, registers, logic definitions
// Here are the registers for each slots
// Because the slot is an Area, we can define mix signals, registers,
// logic definitions.
// Here are the registers for each slots:
val valid = RegInit(False)
val address = Reg(UInt(8 bits))
val age = Reg(UInt(16 bits)) // Will count since how many cycles the slot is valid

// Here is some hardware behavior for each slots
// Implement the age logic
// Here is some hardware behavior for each slots.
// Implement the age logic.
when(valid) {
age := age + 1
}

// removeIt will be used as a slot interface later on
// removeIt will be used as a slot interface later on.
val removeIt = False
when(removeIt) {
valid := False
}
}

// Logic to allocate a new slot
// Logic to allocate a new slot.
val insert = new Area {
val cmd = Stream(UInt(8 bits)) // interface to issue requests
val cmd = Stream(UInt(8 bits)) // Interface to issue requests.
val free = slots.map(!_.valid)
val freeOh = OHMasking.first(free) // Get the first free slot (on hot mask)
cmd.ready := free.orR // Only allow cmd when there is a free slot
val freeOh = OHMasking.first(free) // Get the first free slot (on hot mask).
cmd.ready := free.orR // Only allow cmd when there is a free slot.
when(cmd.fire) {
// slots.onMask(freeOh)(code) will execute the code for each slot where the corresponding freeOh bit is set
// slots.onMask(freeOh)(code) will execute the code for each slot where
// the corresponding freeOh bit is set
slots.onMask(freeOh){slot =>
slot.valid := True
slot.address := cmd.payload
Expand All @@ -46,17 +48,21 @@ case class SlotsDemo(slotsCount : Int) extends Component {
}
}

// Logic to remove the slots which match a given address (assuming there is not more than one match)
// Logic to remove the slots which match a given address (assuming
// there is not more than one match).
val remove = new Area {
val cmd = Flow(UInt(8 bits)) // interface to issue requests
val oh = slots.map(s => s.valid && s.address === cmd.payload) // oh meaning "one hot"
val cmd = Flow(UInt(8 bits)) // Interface to issue requests.
// oh meaning "one hot"
val oh = slots.map(s => s.valid && s.address === cmd.payload)
when(cmd.fire) {
slots.onMask(oh){ slot =>
slot.removeIt := True
}
}

val reader = slots.reader(oh) // Create a facility to read the slots using "oh" as index
// Create a facility to read the slots using "oh" as index
val reader = slots.reader(oh)

val age = reader(_.age) // Age of the slot which is selected by "oh"
}

Expand Down
149 changes: 83 additions & 66 deletions source/SpinalHDL/Data types/Int.rst
Original file line number Diff line number Diff line change
Expand Up @@ -343,25 +343,25 @@ To cast a ``Bool``, a ``Bits``, or an ``SInt`` into a ``UInt``, you can use ``U(
val mySInt = S(myBits)

// UInt to SInt conversion
val UInt_30 = U(30, 8 bit)
val uInt_30 = U(30, 8 bit)

val SInt_30 = UInt_30.intoSInt
assert(SInt_30 === S(30, 9 bit))
val sInt_30 = uint_30.intoSInt
assert(sInt_30 === S(30, 9 bit))

mySInt := UInt_30.twoComplement(booleanDoInvert)
mySInt := uInt_30.twoComplement(booleanDoInvert)
// if booleanDoInvert is True then we get S(-30, 9 bit)
// otherwise we get S(30, 9 bit)

// absolute values
val SInt_n_4 = S(-3, 3 bit)
val abs_en = SInt_n_3.abs(booleanDoAbs)
val sInt_n_4 = S(-3, 3 bit)
val abs_en = sInt_n_3.abs(booleanDoAbs)
// if booleanDoAbs is True we get U(3, 3 bit)
// otherwise we get U"3'b101" or U(5, 3 bit) (raw bit pattern of -3)

val SInt_n_128 = S(-128, 8 bit)
val abs = SInt_n_128.abs
val sInt_n_128 = S(-128, 8 bit)
val abs = sInt_n_128.abs
assert(abs === U(128, 8 bit))
val sym_abs = SInt_n_128.absWithSym
val sym_abs = sInt_n_128.absWithSym
assert(sym_abs === U(127, 7 bit))

Bit extraction
Expand Down Expand Up @@ -558,58 +558,75 @@ Lower bit operations

About Rounding: https://en.wikipedia.org/wiki/Rounding

================ ================= ============= ======================== ====================== ===========
SpinalHDL-Name Wikipedia-Name API Mathematic Algorithm return(align=false) Supported
================ ================= ============= ======================== ====================== ===========
FLOOR RoundDown floor floor(x) w(x)-n bits Yes
FLOORTOZERO RoundToZero floorToZero sign*floor(abs(x)) w(x)-n bits Yes
CEIL RoundUp ceil ceil(x) w(x)-n+1 bits Yes
CEILTOINF RoundToInf ceilToInf sign*ceil(abs(x)) w(x)-n+1 bits Yes
ROUNDUP RoundHalfUp roundUp floor(x+0.5) w(x)-n+1 bits Yes
ROUNDDOWN RoundHalfDown roundDown ceil(x-0.5) w(x)-n+1 bits Yes
ROUNDTOZERO RoundHalfToZero roundToZero sign*ceil(abs(x)-0.5) w(x)-n+1 bits Yes
ROUNDTOINF RoundHalfToInf roundToInf sign*floor(abs(x)+0.5) w(x)-n+1 bits Yes
ROUNDTOEVEN RoundHalfToEven roundToEven No
ROUNDTOODD RoundHalfToOdd roundToOdd No
================ ================= ============= ======================== ====================== ===========
+-------------+-----------------+-------------+------------------------+----------------+----------+
|| Spinal HDL || Wikipedia || API || Mathematic || return || Sup- |
|| name || name || || Algorithm || (align=false) || port |
+=============+=================+=============+========================+================+==========+
| FLOOR | RoundDown | floor | floor(x) | w(x)-n bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| FLOORTOZERO | RoundToZero | floorToZero | sign*floor(abs(x)) | w(x)-n bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| CEIL | RoundUp | ceil | ceil(x) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| CEILTOINF | RoundToInf | ceilToInf | sign*ceil(abs(x)) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDUP | RoundHalfUp | roundUp | floor(x+0.5) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDDOWN | RoundHalfDown | roundDown | ceil(x-0.5) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDTOZERO | RoundHalfToZero | roundToZero | sign*ceil(abs(x)-0.5) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDTOINF | RoundHalfToInf | roundToInf | sign*floor(abs(x)+0.5) | w(x)-n+1 bits | Yes |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDTOEVEN | RoundHalfToEven | roundToEven | | | No |
+-------------+-----------------+-------------+------------------------+----------------+----------+
| ROUNDTOODD | RoundHalfToOdd | roundToOdd | | | No |
+-------------+-----------------+-------------+------------------------+----------------+----------+

.. note::
The **RoundToEven** and **RoundToOdd** modes are very special, and are used in some big data statistical fields with high accuracy concerns, SpinalHDL doesn't support them yet.

You will find `ROUNDUP`, `ROUNDDOWN`, `ROUNDTOZERO`, `ROUNDTOINF`, `ROUNDTOEVEN`, `ROUNTOODD` are very close in behavior, `ROUNDTOINF` is the most common. The behavior of rounding in different programming languages may be different.

====================== =================== ========================================================= ====================
Programming language default-RoundType Example comments
====================== =================== ========================================================= ====================
Matlab ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity
python2 ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity
python3 ROUNDTOEVEN round(1.5)=round(2.5)=2; round(-1.5)=round(-2.5)=-2 close to Even
Scala.math ROUNDTOUP round(1.5)=2,round(2.5)=3;round(-1.5)=-1,round(-2.5)=-2 always to +Infinity
SpinalHDL ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity
====================== =================== ========================================================= ====================
The **RoundToEven** and **RoundToOdd** modes are very special, and are used in some big data statistical fields
with high accuracy concerns, SpinalHDL doesn't support them yet.

You will find ``ROUNDUP``, ``ROUNDDOWN``, ``ROUNDTOZERO``, ``ROUNDTOINF``, ``ROUNDTOEVEN``, ``ROUNTOODD`` are very close in behavior,
``ROUNDTOINF`` is the most common. The behavior of rounding in different programming languages may be different.

============= =================== ================================================= ====================
language default-RoundType example comments
============= =================== ================================================= ====================
Matlab ROUNDTOINF | ``round(1.5) == 2``, ``round(2.5) == 3`` round to ±Infinity
| ``round(-1.5) == -2``, ``round(-2.5) == -3``
python2 ROUNDTOINF | ``round(1.5) == 2``, ``round(2.5) == 3`` round to ±Infinity
| ``round(-1.5) == -2``, ``round(-2.5) == -3``
python3 ROUNDTOEVEN | ``round(1.5) == round(2.5) == 2`` close to Even
| ``round(-1.5) == round(-2.5) == -2``
Scala.math ROUNDTOUP | ``round(1.5) == 2``, ``round(2.5) == 3`` always to +Infinity
| ``round(-1.5) == -1``, ``round(-2.5) == -2``
SpinalHDL ROUNDTOINF | ``round(1.5) == 2``, ``round(2.5) == 3`` round to ±Infinity
| ``round(-1.5) == -2``, ``round(-2.5) == -3``
============= =================== ================================================= ====================

.. note::
In SpinalHDL `ROUNDTOINF` is the default RoundType (``round = roundToInf``)

.. code-block:: scala

val A = SInt(16 bits)
val B = A.roundToInf(6 bits) // default 'align = false' with carry, got 11 bit
val B = A.roundToInf(6 bits, align = true) // sat 1 carry bit, got 10 bit
val B = A.floor(6 bits) // return 10 bit
val B = A.floorToZero(6 bits) // return 10 bit
val B = A.ceil(6 bits) // ceil with carry so return 11 bit
val B = A.ceil(6 bits, align = true) // ceil with carry then sat 1 bit return 10 bit
val B = A.ceilToInf(6 bits)
val B = A.roundUp(6 bits)
val B = A.roundDown(6 bits)
val B = A.roundToInf(6 bits)
val B = A.roundToZero(6 bits)
val B = A.round(6 bits) // SpinalHDL uses roundToInf as the default rounding mode

val B0 = A.roundToInf(6 bits, align = true) // ---+
val a = SInt(16 bits)
val b = a.roundToInf(6 bits) // default 'align = false' with carry, got 11 bit
val b = a.roundToInf(6 bits, align = true) // sat 1 carry bit, got 10 bit
val b = a.floor(6 bits) // return 10 bit
val b = a.floorToZero(6 bits) // return 10 bit
val b = a.ceil(6 bits) // ceil with carry so return 11 bit
val b = a.ceil(6 bits, align = true) // ceil with carry then sat 1 bit return 10 bit
val b = a.ceilToInf(6 bits)
val b = a.roundUp(6 bits)
val b = a.roundDown(6 bits)
val b = a.roundToInf(6 bits)
val b = a.roundToZero(6 bits)
val b = a.round(6 bits) // SpinalHDL uses roundToInf as the default rounding mode

val b0 = a.roundToInf(6 bits, align = true) // ---+
// |--> equal
val B1 = A.roundToInf(6 bits, align = false).sat(1) // ---+
val b1 = a.roundToInf(6 bits, align = false).sat(1) // ---+

.. note::
Only ``floor`` and ``floorToZero`` work without the ``align`` option; they do not need a carry bit. Other rounding operations default to using a carry bit.
Expand Down Expand Up @@ -651,13 +668,13 @@ Symmetric is only valid for ``SInt``.

.. code-block:: scala

val A = SInt(8 bits)
val B = A.sat(3 bits) // return 5 bits with saturated highest 3 bits
val B = A.sat(3) // equal to sat(3 bits)
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val C = A.symmetry // return 8 bits and symmetry as (-128~127 to -127~127)
val C = A.sat(3).symmetry // return 5 bits and symmetry as (-16~15 to -15~15)
val a = SInt(8 bits)
val b = a.sat(3 bits) // return 5 bits with saturated highest 3 bits
val b = a.sat(3) // equal to sat(3 bits)
val b = a.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val b = a.trim(3 bits) // return 5 bits with the highest 3 bits discarded
val c = a.symmetry // return 8 bits and symmetry as (-128~127 to -127~127)
val c = a.sat(3).symmetry // return 5 bits and symmetry as (-16~15 to -15~15)

fixTo function
^^^^^^^^^^^^^^
Expand All @@ -678,13 +695,13 @@ Factory Fix function with Auto Saturation:

.. code-block:: scala

val A = SInt(16 bits)
val B = A.fixTo(10 downto 3) // default RoundType.ROUNDTOINF, sym = false
val B = A.fixTo( 8 downto 0, RoundType.ROUNDUP)
val B = A.fixTo( 9 downto 3, RoundType.CEIL, sym = false)
val B = A.fixTo(16 downto 1, RoundType.ROUNDTOINF, sym = true )
val B = A.fixTo(10 downto 3, RoundType.FLOOR) // floor 3 bit, sat 5 bit @ highest
val B = A.fixTo(20 downto 3, RoundType.FLOOR) // floor 3 bit, expand 2 bit @ highest
val a = SInt(16 bits)
val b = a.fixTo(10 downto 3) // default RoundType.ROUNDTOINF, sym = false
val b = a.fixTo( 8 downto 0, RoundType.ROUNDUP)
val b = a.fixTo( 9 downto 3, RoundType.CEIL, sym = false)
val b = a.fixTo(16 downto 1, RoundType.ROUNDTOINF, sym = true )
val b = a.fixTo(10 downto 3, RoundType.FLOOR) // floor 3 bit, sat 5 bit @ highest
val b = a.fixTo(20 downto 3, RoundType.FLOOR) // floor 3 bit, expand 2 bit @ highest


.. _saturation: https://en.wikipedia.org/wiki/Saturation_arithmetic
23 changes: 14 additions & 9 deletions source/SpinalHDL/Examples/Advanced ones/slots.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,36 @@ Slots
Introduction
------------

Let's say you have some hardware which has to keep track of multiple similar ongoing activities, you may want to implement an array of "slots" to do so. This example show how to do it using Area, OHMasking.first, onMask and reader.
Let's say you have some hardware which has to keep track of multiple similar ongoing activities,
you may want to implement an array of "slots" to do so. This example show how to do it using
``Area``, ``OHMasking.first``, ``onMask`` and ``reader``.


Implementation
^^^^^^^^^^^^^^

This implementation avoid the use of Vec. Instead, it use Area which allow to mix signal, registers and logic definitions in each slot.
This implementation avoid the use of ``Vec``. Instead, it use Area which allow to mix signals,
registers and logic definitions in each slot.

Note that the `reader` API is for SpinalHDL version coming after 1.9.1
Note that the ``reader`` API is for SpinalHDL version coming after 1.9.1

.. literalinclude:: /../examples/src/main/scala/spinaldoc/examples/advanced/Slots.scala
:language: scala


In practice
^^^^^^^^^^^^^^
^^^^^^^^^^^

For instance, this kind of slot pattern is used in Tilelink coherency hub to keep track of all ongoing memory probes in flight:
For instance, this kind of slot pattern is used in Tilelink coherency hub to keep track of all
ongoing memory probes in flight `in SpinalHDL code <https://github.com/SpinalHDL/SpinalHDL/blob/008c73f1ce18e294f137efe7a1442bd3f8fa2ee0/lib/src/main/scala/spinal/lib/bus/tilelink/coherent/Hub.scala#L376>`_.

https://github.com/SpinalHDL/SpinalHDL/blob/008c73f1ce18e294f137efe7a1442bd3f8fa2ee0/lib/src/main/scala/spinal/lib/bus/tilelink/coherent/Hub.scala#L376

As well in the DRAM / SDR / DDR memory controller to implement the handling of multiple memory transactions at once (having multiple precharge / active / read / write running at the same time to improve performances) :

https://github.com/SpinalHDL/SpinalHDL/blob/1edba1890b5f629b28e5171b3c449155337d2548/lib/src/main/scala/spinal/lib/memory/sdram/xdr/Tasker.scala#L202
As well in the DRAM / SDR / DDR memory controller to implement the handling of multiple memory
transactions at once (having multiple precharge / active / read / write running at the same time to
improve performances) `here <https://github.com/SpinalHDL/SpinalHDL/blob/1edba1890b5f629b28e5171b3c449155337d2548/lib/src/main/scala/spinal/lib/memory/sdram/xdr/Tasker.scala#L202>`_.

As well in the NaxRiscv (out of order CPU) load-store-unit to handle the store-queue / load-queue hardware (a bit too scary to show here in the doc XD)
As well in the NaxRiscv (out of order CPU) load-store-unit to handle the store-queue / load-queue
hardware (a bit too scary to show here in the doc XD).


1 change: 1 addition & 0 deletions source/SpinalHDL/Introduction/Projects using SpinalHDL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Repositories
* `VexRiscv CPU and SoC <https://github.com/SpinalHDL/VexRiscv>`_
* `NaxRiscv CPU <https://github.com/SpinalHDL/NaxRiscv>`_
* `SaxonSoc <https://github.com/SpinalHDL/SaxonSoc/tree/dev-0.3/bsp/digilent/ArtyA7SmpLinux>`_
* `VexiiRiscv CPU <https://github.com/SpinalHDL/VexiiRiscv>`_
* `open-rdma <https://github.com/datenlord/open-rdma>`_
* `MicroRV32 SoC <https://github.com/agra-uni-bremen/microrv32>`_
* \.\.\.
Expand Down
Loading
Loading