
spinal.core.SInt.scala Maven / Gradle / Ivy
The newest version!
/* *\
** _____ ____ _____ _____ __ **
** / ___// __ \/ _/ | / / | / / HDL Core **
** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved **
** ___/ / ____// // /| / ___ |/ /___ **
** /____/_/ /___/_/ |_/_/ |_/_____/ **
** **
** This library is free software; you can redistribute it and/or **
** modify it under the terms of the GNU Lesser General Public **
** License as published by the Free Software Foundation; either **
** version 3.0 of the License, or (at your option) any later version. **
** **
** This library is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU **
** Lesser General Public License for more details. **
** **
** You should have received a copy of the GNU Lesser General Public **
** License along with this library. **
\* */
package spinal.core
import spinal.core.internals._
import spinal.idslplugin.Location
/**
* SInt factory used for instance by the IODirection to create a in/out SInt
*/
trait SIntFactory{
/** Create a new SInt */
def SInt(u: Unit = ()) = new SInt()
/** Create a new SInt of a given width */
def SInt(width: BitCount): SInt = SInt().setWidth(width.value)
}
/**
* The SInt type corresponds to a vector of bits that can be used for signed integer arithmetic.
*
* @example{{{
* val mySInt = SInt(8 bits)
* mySInt := S(4, 8 bits) + S"0000_1111"
* mySInt := S(4) - S"h1A"
* }}}
*
* @see [[http://spinalhdl.github.io/SpinalDoc/spinal/core/types/Int SInt Documentation]]
*/
class SInt extends BitVector with Num[SInt] with MinMaxProvider with DataPrimitives[SInt] with BaseTypePrimitives[SInt] with BitwiseOp[SInt] {
override def tag(q: QFormat): SInt = {
require(q.signed, "assign UQ to SInt")
require(q.width == this.getWidth, s"${q} width mismatch!")
Qtag = q
this
}
override def getTypeObject = TypeSInt
override private[core] def resizeFactory: Resize = new ResizeSInt
override def opName: String = "SInt"
override type T = SInt
private[spinal] override def _data: SInt = this
/**
* Concatenation between two SInt
* @example{{{ val mySInt = sInt1 @@ sInt2 }}}
* @param that an SInt to append
* @return a new SInt of width (width(this) + width(right))
*/
def @@(that: SInt): SInt = S(this ## that)
/** Concatenation between a SInt and UInt */
def @@(that: UInt): SInt = S(this ## that)
/** Concatenation between a SInt and a Bool */
def @@(that: Bool): SInt = S(this ## that)
/* Implement Num operators */
override def + (right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Add)
override def - (right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Sub)
override def * (right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Mul)
override def / (right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Div)
override def % (right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Mod)
override def < (right: SInt): Bool = wrapLogicalOperator(right, new Operator.SInt.Smaller)
override def > (right: SInt): Bool = right < this
override def <=(right: SInt): Bool = wrapLogicalOperator(right, new Operator.SInt.SmallerOrEqual)
override def >=(right: SInt): Bool = right <= this
override def >>(that: Int): SInt = wrapConstantOperator(new Operator.SInt.ShiftRightByInt(that))
override def <<(that: Int): SInt = wrapConstantOperator(new Operator.SInt.ShiftLeftByInt(that))
override def +^(right: SInt): SInt = this.expand + right.expand
override def -^(right: SInt): SInt = this.expand - right.expand
override def +|(right: SInt): SInt = (this +^ right).sat(1)
override def -|(right: SInt): SInt = (this -^ right).sat(1)
/* Implement BitwiseOp operators */
override def |(right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Or)
override def &(right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.And)
override def ^(right: SInt): SInt = wrapBinaryOperator(right, new Operator.SInt.Xor)
override def unary_~ : SInt = wrapUnaryOperator(new Operator.SInt.Not)
def valueRange: Range = {
assert(getWidth < 33)
(-(1l << getWidth-1) toInt) to (1 << getWidth-1)-1
}
/* Implement fixPoint operators */
def sign: Bool = this.msb
/**
* SInt symmetric
* @example{{{ val symmetrySInt = mySInt.symmetry }}}
* @return return a SInt which minValue equal -maxValue
*/
def symmetry: SInt = {
val ret = cloneOf(this)
ret := Mux(this === minValue, S(-maxValue), this)
ret
}
/**Saturation highest m bits*/
override def sat(m: Int): SInt = {
require(getWidth > m, s"Saturation bit width $m must be less than data bit width $getWidth")
m match {
case 0 => this << 0
case x if x > 0 => this._sat(m)
case _ => (Vec(this.sign,-m).asBits ## this).asSInt //sign bit expand
}
}
private def _sat(m: Int): SInt ={
val ret = SInt(getWidth-m bit)
when(this.sign){//negative process
when(!this(getWidth-1 downto getWidth-m-1).asBits.andR){
ret := ret.minValue
}.otherwise{
ret := this(getWidth-m-1 downto 0)
}
}.otherwise{//positive process
when(this(getWidth-2 downto getWidth-m-1).asBits.orR){
ret := ret.maxValue
}.otherwise {
ret := this(getWidth-m- 1 downto 0)
}
}
ret
}
def satWithSym(m: Int): SInt = sat(m).symmetry
/**highest m bits Discard */
override def trim(m: Int): SInt = this(getWidth-m-1 downto 0)
/**Round Api*/
/**return w(this)-n bits*/
override def floor(n: Int): SInt = {
require(getWidth > n, s"floor bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => this._floor(n)
case _ => this << -n
}
}
private def _floor(n: Int): SInt = this >> n
/**
* SInt ceil
* @example{{{ val mySInt = SInt(w bits).ceil }}}
* @param n : ceil lowerest n bit
* @return a new SInt of width (w - n + 1)
*/
override def ceil(n: Int, align: Boolean = true): SInt = {
require(getWidth > n, s"ceil bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _ceil(n).sat(1) else _ceil(n)
case _ => this << -n
}
}
/**return w(this)-n+1 bits*/
private def _ceil(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
when(sign){
ret := this._negativeCeil(n).expand
}.otherwise{
ret := this._positiveCeil(n)
}
ret
}
/**return w(this)-n bits*/
private def _negativeCeil(n: Int): SInt ={
val ret = SInt(getWidth-n bits)
when(this(n-1 downto 0).orR){
ret := this(getWidth - 1 downto n) + 1
}.otherwise{
ret := this(getWidth - 1 downto n)
}
ret
}
/**return w(this)-n+1 bits*/
private def _positiveCeil(n: Int): SInt ={
val ret = SInt(getWidth-n+1 bits)
ret := this(getWidth-2 downto 0).asUInt._ceil(n).intoSInt
ret
}
/** SInt roundUp lowest m bits, friendly for hardware timing and area
* sign * floor(abs(x))
* */
override def floorToZero(n: Int): SInt = {
require(getWidth > n, s"floorToZero bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => _floorToZero(n)
case _ => this << -n
}
}
/**return w(this)-n bits*/
private def _floorToZero(n: Int): SInt = {
val ret = SInt(getWidth-n bits)
when(sign){
ret := this._negativeCeil(n)
}.otherwise{
ret := this._floor(n)
}
ret
}
/** SInt roundUp lowest m bits, friendly for hardware timing and area
* sign * ceil(abs(x))
* */
override def ceilToInf(n: Int, align: Boolean = true): SInt = {
require(getWidth > n, s"ceilToInf bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _ceilToInf(n).sat(1) else _ceilToInf(n)
case _ => this << -n
}
}
/**return w(this)-n+1 bits*/
private def _ceilToInf(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
when(sign){
ret := this._floor(n).expand
}.otherwise{
ret := this._positiveCeil(n)
}
ret
}
/** SInt roundUp lowest m bits, friendly for hardware timing and area
* floor(x + 0.5)
* */
override def roundUp(n: Int, align: Boolean = true): SInt = {
require(getWidth > n, s"RoundUp bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x >0 => if(align) _roundUp(n).sat(1) else _roundUp(n)
case _ => this << -n
}
}
/**return w(this)-n bits*/
private def _roundUp(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
val positive0p5: SInt = (Bits(getWidth-n bits).clearAll ## True).asSInt
ret := (this(getWidth-1 downto n-1) +^ positive0p5)._floor(1) //(x + 0.5).floor
ret
}
/** SInt roundDown lowest m bits, complex for hardware , not recommended
* The algorithm represented by python code :
* ceil(x - 0.5)
* */
override def roundDown(n: Int, align: Boolean): SInt = {
require(getWidth > n, s"RoundDown bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _roundDown(n).sat(1) else _roundDown(n)
case _ => this << -n
}
}
private def _roundDown(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
val negative0p5: SInt = (Bits(getWidth-n+1 bits).setAll ## Bits(n-1 bits).clearAll).asSInt
val sub0p5: SInt = this(getWidth-1 downto 0) +^ negative0p5 //need carry
when(sub0p5.sign){
ret := sub0p5._negativeCeil(n)
}.otherwise{
ret := sub0p5(getWidth-1 downto 0)._positiveCeil(n)
}
ret
}
/** SInt roundToZero
* The algorithm represented by python code :
* sign * ceil(abs(x) - 0.5)
* */
override def roundToZero(n: Int, align: Boolean): SInt = {
require(getWidth > n, s"RoundToZero bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _roundToZero(n).sat(1) else _roundToZero(n)
case _ => this << -n
}
}
/**return w(this)-n bits*/
private def _roundToZero(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
val positive0p5: SInt = (Bits(getWidth-n bits).clearAll ## True ## Bits(n-1 bits).clearAll()).asSInt
val negative0p5: SInt = (Bits(getWidth-n+1 bits).setAll ## Bits(n-1 bits).clearAll).asSInt
val sub0p5ForPos: SInt = this(getWidth-1 downto 0) +^ negative0p5
val add0p5ForNeg: SInt = this(getWidth-1 downto 0) + positive0p5 //no carry needed
when(sub0p5ForPos.sign){
ret := add0p5ForNeg._floor(n).expand
}.otherwise{
ret := sub0p5ForPos(getWidth-1 downto 0)._positiveCeil(n)
}
ret
}
/** SInt roundToInf
* sign * floor(abs(x) + 0.5)
* */
override def roundToInf(n: Int, align: Boolean = true): SInt = {
require(getWidth > n, s"RoundToInf bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _roundToInf(n).sat(1) else _roundToInf(n)
case _ => this << -n
}
}
/**return w(this)-n+1 bits*/
private def _roundToInf(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
val positive0p5: SInt = (Bits(getWidth-n bits).clearAll ## True ## Bits(n-1 bits).clearAll()).asSInt
val negative0p5: SInt = (Bits(getWidth-n+1 bits).setAll ## Bits(n-1 bits).clearAll).asSInt
val sub0p5ForNeg: SInt = this(getWidth-1 downto 0) +^ negative0p5 //need carry
val add0p5ForPos: SInt = this(getWidth-1 downto 0) +^ positive0p5 //need carry
when(sub0p5ForNeg.sign){
ret := sub0p5ForNeg._negativeCeil(n)
}.otherwise{
ret := add0p5ForPos._floor(n)
}
ret
}
override def roundToEven(n: Int, align: Boolean): SInt = {
require(getWidth > n, s"RoundToEven bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _roundToEven(n).sat(1) else _roundToEven(n)
case _ => this << -n
}
}
private def _roundToEven(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
when (!this(n)) {
ret := _roundDown(n)
} otherwise {
ret := _roundUp(n)
}
ret
}
override def roundToOdd(n: Int, align: Boolean): SInt = {
require(getWidth > n, s"RoundToOdd bit width $n must be less than data bit width $getWidth")
n match {
case 0 => this << 0
case x if x > 0 => if(align) _roundToOdd(n).sat(1) else _roundToOdd(n)
case _ => this << -n
}
}
private def _roundToOdd(n: Int): SInt = {
val ret = SInt(getWidth-n+1 bits)
when (!this(n)) {
ret := _roundUp(n)
} otherwise {
ret := _roundDown(n)
}
ret
}
//SpinalHDL chose roundToInf as default round
override def round(n: Int, align: Boolean = true): SInt = roundToInf(n, align)
def expand: SInt = (this.sign ## this.asBits).asSInt
protected def _fixEntry(roundN: Int, roundType: RoundType, satN: Int): SInt = {
roundType match{
case RoundType.CEIL => this.ceil(roundN, false).sat(satN + 1)
case RoundType.FLOOR => this.floor(roundN).sat(satN)
case RoundType.FLOORTOZERO => this.floorToZero(roundN).sat(satN)
case RoundType.CEILTOINF => this.ceilToInf(roundN, false).sat(satN + 1)
case RoundType.ROUNDUP => this.roundUp(roundN, false).sat(satN + 1)
case RoundType.ROUNDDOWN => this.roundDown(roundN, false).sat(satN + 1)
case RoundType.ROUNDTOZERO => this.roundToZero(roundN, false).sat(satN + 1)
case RoundType.ROUNDTOINF => this.roundToInf(roundN, false).sat(satN + 1)
case RoundType.ROUNDTOEVEN => this.roundToEven(roundN, false).sat(satN + 1)
case RoundType.ROUNDTOODD => this.roundToOdd(roundN, false).sat(satN + 1)
}
}
/**Factory fixTo Function*/
private def fixToWrap(section: Range.Inclusive, roundType: RoundType, sym: Boolean): SInt = {
val w: Int = this.getWidth
val wl: Int = w - 1
val ret = (section.min, section.max, section.size) match {
case (0, _, `w`) => this << 0
case (x, `wl`, _ ) => _fixEntry(x, roundType, satN = 0)
case (0, y, _ ) => this.sat(this.getWidth -1 - y)
case (x, y, _ ) => _fixEntry(x, roundType, satN = this.getWidth -1 - y)
}
if(sym) ret.symmetry else ret
}
def fixTo(section: Range.Inclusive, roundType: RoundType, sym: Boolean): SInt = {
class fixTo(width: Int, section: Range.Inclusive,
roundType: RoundType, sym: Boolean) extends Component{
val symTag = if(sym) "_sym" else ""
definitionName = s"SInt${width}fixTo${section.max}_${section.min}_${roundType}${symTag}"
val din = in SInt(width bits)
val dout = out SInt(section.size bits)
dout := din.fixToWrap(section, roundType, sym)
}
if(GlobalData.get.config.fixToWithWrap) {
val dut = new fixTo(this.getWidth, section, roundType, sym)
dut.din := this
dut.dout
} else {
fixToWrap(section, roundType, sym)
}
}
def fixTo(section: Range.Inclusive, roundType: RoundType): SInt = fixTo(section, roundType, getFixSym())
def fixTo(section: Range.Inclusive): SInt = fixTo(section, getFixRound(), getFixSym())
def fixTo(q: QFormat, roundType: RoundType, sym: Boolean ): SInt = {
val section = getfixSection(q)
fixTo(section, roundType, sym)
}
def fixTo(q: QFormat, roundType: RoundType): SInt = fixTo(q, roundType, getFixSym())
def fixTo(q: QFormat): SInt = fixTo(q, getFixRound(), getFixSym())
/**
* Negative number
* @example{{{ val result = -mySInt }}}
* @return return a negative number
*/
def unary_- : SInt = wrapUnaryOperator(new Operator.SInt.Minus)
def twoComplement(enable: Bool, plusOneEnable : Bool = null): SInt = {
val expended = this.msb ## this
((Mux(enable, ~expended, expended)).asUInt + U(if(plusOneEnable == null) enable else enable && plusOneEnable)).asSInt
}
/**
* Logical shift Right (output width == input width)
* @example{{{ val result = mySInt >> myUIntShift }}}
* @param that the number of right shift
* @return a Bits of width : w(this)
*/
def >>(that: UInt): SInt = wrapBinaryOperator(that, new Operator.SInt.ShiftRightByUInt)
/** Logical shift Left (output width will increase of : w(this) + max(that) bits */
def <<(that: UInt): SInt = wrapBinaryOperator(that, new Operator.SInt.ShiftLeftByUInt)
/**
* Logical shift right (output width == input width)
* @example{{{ val result = myUInt |>> 4 }}}
* @param that the number of right shift
* @return a Bits of width : w(this)
*/
def |>>(that: Int): SInt = wrapConstantOperator(new Operator.SInt.ShiftRightByIntFixedWidth(that))
/** Logical shift left (output width == input width) */
def |<<(that: Int): SInt = wrapConstantOperator(new Operator.SInt.ShiftLeftByIntFixedWidth(that))
/** Logical shift Right (output width == input width) */
def |>>(that: UInt): SInt = this >> that
/** Logical shift left (output width == input width) */
def |<<(that: UInt): SInt = wrapBinaryOperator(that, new Operator.SInt.ShiftLeftByUIntFixedWidth)
override def rotateLeft(that: Int): SInt = {
val width = widthOf(this)
val thatMod = that % width
this(this.high - thatMod downto 0) @@ this(this.high downto this.high - thatMod + 1)
}
override def rotateRight(that: Int): SInt = {
val width = widthOf(this)
val thatMod = that % width
this(thatMod - 1 downto 0) @@ this(this.high downto thatMod)
}
def @*(count: Int): SInt = wrapUnaryOperator(new Operator.SInt.Repeat(count))
/**
* Assign a range value to a SInt
* @example{{{ core.io.interrupt = (0 -> uartCtrl.io.interrupt, 1 -> timerCtrl.io.interrupt, default -> false)}}}
* @param rangesValue The first range value
* @param _rangesValues Others range values
*/
def :=(rangesValue : (Any, Any), _rangesValues: (Any, Any)*) : Unit = {
val rangesValues = rangesValue +: _rangesValues
S.applyTuples(this, rangesValues)
}
def :=(value : String) : Unit = this := S(value)
override def assignFromBits(bits: Bits): Unit = this := bits.asSInt
override def assignFromBits(bits: Bits, hi: Int, lo: Int): Unit = this(hi downto lo).assignFromBits(bits)
/**
* Cast a SInt into an UInt
* @example {{{ myUInt := mySInt.asUInt }}}
* @return a UInt data
*/
def asUInt: UInt = wrapCast(UInt(), new CastSIntToUInt)
override def asBits: Bits = wrapCast(Bits(), new CastSIntToBits)
private[core] override def isEqualTo(that: Any): Bool = that match {
case that: SInt => wrapLogicalOperator(that, new Operator.SInt.Equal)
case that: MaskedLiteral => that === this
case _ => SpinalError(s"Don't know how compare $this with $that"); null
}
private[core] override def isNotEqualTo(that: Any): Bool = that match {
case that: SInt => wrapLogicalOperator(that, new Operator.SInt.NotEqual)
case that: MaskedLiteral => that =/= this
case _ => SpinalError(s"Don't know how compare $this with $that"); null
}
private[core] override def newMultiplexerExpression() = new MultiplexerSInt
private[core] override def newBinaryMultiplexerExpression() = new BinaryMultiplexerSInt
override def resize(width: Int): this.type = wrapWithWeakClone({
val node = new ResizeSInt
node.input = this
node.size = width
node
})
override def resize(width: BitCount) : SInt = resize(width.value)
override def minValue: BigInt = -(BigInt(1) << (getWidth - 1))
override def maxValue: BigInt = (BigInt(1) << (getWidth - 1)) - 1
override def apply(bitId: Int): Bool = newExtract(bitId, new SIntBitAccessFixed)
override def apply(bitId: UInt): Bool = newExtract(bitId, new SIntBitAccessFloating)
override def apply(offset: Int, bitCount: BitCount): this.type = newExtract(offset + bitCount.value - 1, offset, new SIntRangedAccessFixed).setWidth(bitCount.value)
override def apply(offset: UInt, bitCount: BitCount): this.type = newExtract(offset, bitCount.value, new SIntRangedAccessFloating).setWidth(bitCount.value)
private[core] override def weakClone: this.type = new SInt().asInstanceOf[this.type]
override def getZero: this.type = S(0, this.getWidth bits).asInstanceOf[this.type]
override def getZeroUnconstrained: this.type = S(0).asInstanceOf[this.type]
override def getAllTrue: this.type = S(if(getWidth != 0) -1 else 0, this.getWidth bits).asInstanceOf[this.type]
override def setAll(): this.type = {
this := (if(getWidth != 0) -1 else 0)
this
}
override def assignDontCare(): this.type = {
this.assignFrom(SIntLiteral(BigInt(0), (BigInt(1) << this.getWidth) - 1, widthOf(this)))
this
}
override private[core] def formalPast(delay: Int) = this.wrapUnaryOperator(new Operator.Formal.PastSInt(delay))
def reversed = S(B(this.asBools.reverse)).asInstanceOf[this.type]
override def assignFormalRandom(kind: Operator.Formal.RandomExpKind) = this.assignFrom(new Operator.Formal.RandomExpSInt(kind, widthOf(this)))
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy