
spinal.core.internals.Node.scala Maven / Gradle / Ivy
/* *\
** _____ ____ _____ _____ __ **
** / ___// __ \/ _/ | / / | / / 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.internals
import spinal.core._
import scala.collection.Seq
object SymplifyNode {
def binaryTakeOther(node: BinaryOperatorWidthableInputs): Expression = {
if (node.left.getWidth == 0) {
node.right
} else if (node.right.getWidth == 0) {
node.left
} else {
node
}
}
def binaryInductZeroWithOtherWidth(zeroFactory: (BigInt, Int) => Expression, strictResize: Boolean = false)(op: BinaryOperatorWidthableInputs): Expression = {
def doIt(left: Expression with WidthProvider, right: Expression with WidthProvider): Expression = {
if(!strictResize || InputNormalize.isStrictlyResizable(left)) {
zeroFactory(0, right.getWidth)
} else {
op
}
}
if (op.left.getWidth == 0) {
return doIt(op.left, op.right)
}
if (op.right.getWidth == 0) {
return doIt(op.right,op.left)
}
op
}
def binaryThatIfBoth(thatFactory: => Expression)(node: BinaryOperatorWidthableInputs): Expression = {
if (node.left.getWidth == 0 && node.right.getWidth == 0)
thatFactory
else
node
}
}
object InputNormalize {
def enumImpl(node: Expression with EnumEncoded, input: Expression with EnumEncoded): Expression with EnumEncoded = {
if(node.getEncoding != input.getEncoding) {
val cast = new CastEnumToEnum(node.getDefinition)
cast.input = input.asInstanceOf[cast.T]
cast.fixEncoding(node.getEncoding)
cast
}
else {
input
}
}
def enumImpl(node: Expression with EnumEncoded): Unit = {
node.remapExpressions {
case input: Expression with EnumEncoded => enumImpl(node, input)
case input => input
}
}
def switchEnumImpl(node: SwitchStatement): Unit = {
val value = node.value.asInstanceOf[Expression with EnumEncoded]
node.remapExpressions {
case input: Expression with EnumEncoded if value.getEncoding != input.getEncoding =>
val cast = new CastEnumToEnum(value.getDefinition)
cast.input = input.asInstanceOf[cast.T]
cast.fixEncoding(value.getEncoding)
cast
case input => input
}
}
def isStrictlyResizable(that: Expression): Boolean = {
that match{
case lit: BitVectorLiteral if !lit.hasSpecifiedBitCount => true
case bv: BitVector if bv.hasTag(tagAutoResize) => true
case _ => false
}
}
def resizedOrUnfixedLit(input: Expression with WidthProvider, targetWidth: Int, factory: => Resize, target: Expression, where: ScalaLocated): Expression with WidthProvider = {
input match{
case lit: BitVectorLiteral if !lit.hasSpecifiedBitCount && lit.minimalValueBitWidth <= targetWidth =>
lit.bitCount = targetWidth
lit
case bt: BitVector if bt.hasTag(tagAutoResize) && bt.getWidth != targetWidth =>
val ret = factory
ret.input = input
ret.size = targetWidth
ret
case _ =>
if(input.getWidth != targetWidth){
PendingError(s"WIDTH MISMATCH (${targetWidth} bits <- ${input.getWidth} bits) on ${target.toStringMultiLine()} at \n${where.getScalaLocationLong}")
}
input
}
}
def assignementResizedOrUnfixedLit(assignement: AssignmentStatement): Expression = {
val targetWidth = assignement.target.asInstanceOf[WidthProvider].getWidth
val inputWidth = assignement.source.asInstanceOf[WidthProvider].getWidth
assignement.source match{
case lit: BitVectorLiteral if !lit.hasSpecifiedBitCount && lit.minimalValueBitWidth <= targetWidth =>
lit.bitCount = targetWidth
lit
case bt: BitVector if bt.hasTag(tagAutoResize) && bt.getWidth != targetWidth =>
val ret = assignement.finalTarget.asInstanceOf[BitVector].resizeFactory
ret.input = assignement.source.asInstanceOf[Expression with WidthProvider]
ret.size = targetWidth
ret
case _ =>
if(inputWidth != targetWidth){
PendingError(s"WIDTH MISMATCH (${targetWidth} bits <- ${inputWidth} bits) on ${assignement.toStringMultiLine} at \n${assignement.getScalaLocationLong}")
}
assignement.source
}
}
def resize(input: Expression with WidthProvider, targetWidth: Int, factory: => Resize): Expression with WidthProvider = {
input match{
case lit: BitVectorLiteral if (! lit.hasSpecifiedBitCount && lit.minimalValueBitWidth <= targetWidth) =>
lit.bitCount = targetWidth
lit
case _ if input.getWidth != targetWidth =>
val ret = factory
ret.input = input
ret.size = targetWidth
ret
case _ =>
input
}
}
}
trait Suffixable {
def elements: Seq[(String, Data)]
}
trait WidthProvider extends ScalaLocated {
def getWidth: Int
}
trait Widthable extends WidthProvider{
private[core] var widthWhenNotInferred = -1
private[core] var inferredWidth = -1
private[core] def calcWidth: Int
override def getWidth: Int = {
if (globalData.nodeAreInferringWidth) {
inferredWidth
} else {
val isFirst = globalData.nodeGetWidthWalkedSet.isEmpty
if (globalData.nodeGetWidthWalkedSet.contains(this))
SpinalError(s"Can't calculate width of $this when design is in construction phase")
globalData.nodeGetWidthWalkedSet += this
var temp: Int = 0
if (isFirst) {
try {
temp = calcWidth
} catch {
case e: Exception =>
globalData.nodeGetWidthWalkedSet.clear()
throw e
}
} else {
temp = calcWidth
}
if (temp == -1) {
globalData.nodeGetWidthWalkedSet.clear()
SpinalError(s"Can't infer width because of unspecified width on ${this.getScalaLocationLong}")
}
globalData.nodeGetWidthWalkedSet -= this
if (isFirst) globalData.nodeGetWidthWalkedSet.clear()
if (widthWhenNotInferred != -1 && widthWhenNotInferred != temp) SpinalError(s"getWidth result differ from last call $getScalaLocationLong")
widthWhenNotInferred = temp
temp
}
}
private[core] def inferWidth: Boolean = {
val newWidth: Int = calcWidth
if (newWidth == -1) {
return true
} else if (newWidth != inferredWidth) {
inferredWidth = newWidth
return true;
} else {
return false
}
}
}
trait EnumEncoded{
def getEncoding: SpinalEnumEncoding
def propagateEncoding = false
def getDefinition: SpinalEnum
//Only used in the inferation phase
def swapEncoding(encoding : SpinalEnumEncoding)
def swapEnum(e : SpinalEnum)
}
trait InferableEnumEncoding{
private[core] def encodingProposal(e: SpinalEnumEncoding): Boolean
def bootInferration(): Unit
}
trait InferableEnumEncodingImplChoice
object InferableEnumEncodingImplChoiceUndone extends InferableEnumEncodingImplChoice
object InferableEnumEncodingImplChoiceFixed extends InferableEnumEncodingImplChoice
object InferableEnumEncodingImplChoiceAnticipated extends InferableEnumEncodingImplChoice
object InferableEnumEncodingImplChoiceInferred extends InferableEnumEncodingImplChoice
trait InferableEnumEncodingImpl extends EnumEncoded with InferableEnumEncoding with ContextUser with ScalaLocated{
private[core] var encodingChoice: InferableEnumEncodingImplChoice = InferableEnumEncodingImplChoiceUndone
private[core] var encoding : SpinalEnumEncoding = null
override def swapEncoding(encoding: SpinalEnumEncoding): Unit = this.encoding = encoding
override def propagateEncoding = encodingChoice == InferableEnumEncodingImplChoiceFixed
override def bootInferration(): Unit = {
if(encodingChoice == InferableEnumEncodingImplChoiceUndone){
encodingChoice = InferableEnumEncodingImplChoiceInferred
encoding = getDefaultEncoding()
}
}
private[core] def getDefaultEncoding(): SpinalEnumEncoding
def fixEncoding(e: SpinalEnumEncoding): this.type = {
encoding = e
encodingChoice = InferableEnumEncodingImplChoiceFixed
this
}
def copyEncodingConfig(that: InferableEnumEncodingImpl): Unit = {
this.encoding = that.encoding
this.encodingChoice = that.encodingChoice
}
private[core] override def encodingProposal(e: SpinalEnumEncoding): Boolean = {
def takeIt: Boolean ={
if(encoding != e) {
encoding = e
encodingChoice = InferableEnumEncodingImplChoiceInferred
true
}else{
false
}
}
encodingChoice match {
case `InferableEnumEncodingImplChoiceUndone` => takeIt
case `InferableEnumEncodingImplChoiceInferred` => takeIt
case `InferableEnumEncodingImplChoiceAnticipated` =>
if(encoding != e){
globalData.pendingErrors += (() => s"$this encoding has change between the elaboration phase and the compilation phase\n${this.getScalaLocationLong}")
}
false
case `InferableEnumEncodingImplChoiceFixed` => false
}
}
override def getEncoding: SpinalEnumEncoding = {
if (globalData.nodeAreInferringEnumEncoding) {
encoding
} else {
if(encodingChoice == InferableEnumEncodingImplChoiceUndone){
encoding = getDefaultEncoding()
encodingChoice = InferableEnumEncodingImplChoiceAnticipated
}
encoding
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy