Utils
General
Many tools and utilities are present in spinal.lib but some are already present in the SpinalHDL Core.
Syntax |
Return |
Description |
---|---|---|
|
Int |
Return the width of a Bits/UInt/SInt signal |
|
Int |
Return the number of bits needed to represent |
|
Boolean |
Return true if |
|
BigInt |
Return the first |
|
Bits |
Concatenate all arguments, the first in MSB, the last in LSB |
Cloning hardware datatypes
You can clone a given hardware data type by using the cloneOf(x)
function.
It will return a new instance of the same Scala type and parameters.
For example:
def plusOne(value : UInt) : UInt = {
// Will recreate a UInt with the same width than ``value``
val temp = cloneOf(value)
temp := value + 1
return temp
}
// treePlusOne will become a 8 bits value
val treePlusOne = plusOne(U(3, 8 bits))
You can get more information about how hardware data types are managed on the Hardware types page.
Note
If you use the cloneOf
function on a Bundle
, this Bundle
should be a case class
or should override the clone function internally.
Passing a datatype as construction parameter
Many pieces of reusable hardware need to be parameterized by some data type. For example if you want to define a FIFO or a shift register, you need a parameter to specify which kind of payload you want for the component.
There are two similar ways to do this.
The old way
A good example of the old way to do this is in this definition of a ShiftRegister
component:
case class ShiftRegister[T <: Data](dataType: T, depth: Int) extends Component {
val io = new Bundle {
val input = in (cloneOf(dataType))
val output = out(cloneOf(dataType))
}
// ...
}
And here is how you can instantiate the component:
val shiftReg = ShiftRegister(Bits(32 bits), depth = 8)
As you can see, the raw hardware type is directly passed as a construction parameter.
Then each time you want to create an new instance of that kind of hardware data type, you need to use the cloneOf(...)
function.
Doing things this way is not super safe as it’s easy to forget to use cloneOf
.
The safe way
An example of the safe way to pass a data type parameter is as follows:
case class ShiftRegister[T <: Data](dataType: HardType[T], depth: Int) extends Component {
val io = new Bundle {
val input = in (dataType())
val output = out(dataType())
}
// ...
}
And here is how you instantiate the component (exactly the same as before):
val shiftReg = ShiftRegister(Bits(32 bits), depth = 8)
Notice how the example above uses a HardType
wrapper around the raw data type T
, which is a “blueprint” definition of a hardware data type.
This way of doing things is easier to use than the “old way”, because to create a new instance of the hardware data type you only need to call the apply
function of that HardType
(or in other words, just add parentheses after the parameter).
Additionally, this mechanism is completely transparent from the point of view of the user, as a hardware data type can be implicitly converted into a HardType
.
Frequency and time
SpinalHDL has a dedicated syntax to define frequency and time values:
val frequency = 100 MHz
val timeoutLimit = 3 ms
val period = 100 us
val periodCycles = frequency * period
val timeoutCycles = frequency * timeoutLimit
TimeNumber
:fs
, ps
, ns
, us
, ms
, sec
, mn
, hr
HertzNumber
:Hz
, KHz
, MHz
, GHz
, THz
TimeNumber
and HertzNumber
are based on the PhysicalNumber
class which uses the Scala BigDecimal
type to store numbers.