Skip to content

Commit

Permalink
Add support for Property literals, starting with existing int types. (c…
Browse files Browse the repository at this point in the history
…hipsalliance#3482)

This includes the API, Chisel IR, Converter, FIRRTL IR, and Serializer
support for Property literals.
  • Loading branch information
mikeurbach authored Aug 12, 2023
1 parent abd88ac commit 39d4107
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 1 deletion.
6 changes: 5 additions & 1 deletion core/src/main/scala/chisel3/internal/Binding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package chisel3.internal

import chisel3._
import chisel3.experimental.BaseModule
import chisel3.internal.firrtl.LitArg
import chisel3.internal.firrtl.{LitArg, PropertyLit}

import scala.collection.immutable.VectorMap

Expand Down Expand Up @@ -162,3 +162,7 @@ case class BundleLitBinding(litMap: Map[Data, LitArg]) extends LitBinding
// Literal binding attached to the root of a Vec, containing literal values of its children.
@deprecated(deprecatedPublicAPIMsg, "Chisel 3.6")
case class VecLitBinding(litMap: VectorMap[Data, LitArg]) extends LitBinding
// Literal binding attached to a Property.
private[chisel3] case class PropertyLitBinding(litProp: PropertyLit[_])
extends UnconstrainedBinding
with ReadOnlyBinding
3 changes: 3 additions & 0 deletions core/src/main/scala/chisel3/internal/firrtl/Converter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ private[chisel3] object Converter {
// TODO Simplify
case lit: ILit =>
throw new InternalErrorException(s"Unexpected ILit: $lit")
case PropertyLit(lit: Int) => fir.IntegerPropertyLiteral(lit)
case PropertyLit(lit: Long) => fir.IntegerPropertyLiteral(lit)
case PropertyLit(lit: BigInt) => fir.IntegerPropertyLiteral(lit)
case e @ ProbeExpr(probe) =>
fir.ProbeExpr(convert(probe, ctx, info))
case e @ RWProbeExpr(probe) =>
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import firrtl.{ir => fir}
import chisel3._
import chisel3.internal._
import chisel3.experimental._
import chisel3.properties.{Property, PropertyType => PropertyTypeclass}
import _root_.firrtl.{ir => firrtlir}
import _root_.firrtl.{PrimOps, RenameMap}
import _root_.firrtl.annotations.Annotation
Expand Down Expand Up @@ -168,6 +169,24 @@ case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
}
}

/** Literal property value.
*
* These are not LitArgs, because not all property literals are integers.
*/
private[chisel3] case class PropertyLit[T: PropertyTypeclass](lit: T) extends Arg {
def name: String = s"PropertyLit($lit)"
def minWidth: Int = 0
def cloneWithWidth(newWidth: Width): this.type = PropertyLit[T](lit).asInstanceOf[this.type]

/** Expose a bindLitArg API for PropertyLit, similar to LitArg.
*/
def bindLitArg(elem: Property[T]): Property[T] = {
elem.bind(PropertyLitBinding(this))
elem.setRef(this)
elem
}
}

@deprecated(deprecatedPublicAPIMsg, "Chisel 3.6")
case class Ref(name: String) extends Arg

Expand Down
8 changes: 8 additions & 0 deletions core/src/main/scala/chisel3/properties/Property.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,12 @@ object Property {
def apply[T: PropertyType](): Property[T] = {
new Property[T]
}

/** Create a new Property literal of type T.
*/
def apply[T: PropertyType](lit: T): Property[T] = {
val literal = ir.PropertyLit[T](lit)
val result = new Property[T]
literal.bindLitArg(result)
}
}
13 changes: 13 additions & 0 deletions docs/src/explanations/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,16 @@ class ConnectExample extends RawModule {
Connections are only supported between the same `Property` type. For example, a
`Property[Int]` may only be connected to a `Property[Int]`. This is enforced by
the Scala compiler.

### Property Literals

The legal `Property` types may be used to construct literals by applying the
`Property` object to a literal value of the `Property` type. For example, a
`Property` literal may be connected to an output `Property` type port:

```scala mdoc:silent
class LiteralExample extends RawModule {
val outPort = IO(Output(Property[Int]()))
outPort := Property(123)
}
```
6 changes: 6 additions & 0 deletions firrtl/src/main/scala/firrtl/ir/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ object SIntLiteral {
def minWidth(value: BigInt): Width = IntWidth(value.bitLength + 1)
def apply(value: BigInt): SIntLiteral = new SIntLiteral(value, minWidth(value))
}

case class IntegerPropertyLiteral(value: BigInt) extends Literal with UseSerializer {
def tpe = IntegerPropertyType
val width = UnknownWidth
}

case class DoPrim(op: PrimOp, args: Seq[Expression], consts: Seq[BigInt], tpe: Type)
extends Expression
with UseSerializer
Expand Down
2 changes: 2 additions & 0 deletions firrtl/src/main/scala/firrtl/ir/Serializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ object Serializer {
case ValidIf(cond, value, _) => b ++= "validif("; s(cond); b ++= ", "; s(value); b += ')'
case SIntLiteral(value, width) =>
b ++= "SInt"; s(width); b ++= "(0h"; b ++= value.toString(16); b ++= ")"
case IntegerPropertyLiteral(value) =>
b ++= "Integer("; b ++= value.toString(10); b ++= ")"
case ProbeExpr(expr, _) => b ++= "probe("; s(expr); b += ')'
case RWProbeExpr(expr, _) => b ++= "rwprobe("; s(expr); b += ')'
case ProbeRead(expr, _) => b ++= "read("; s(expr); b += ')'
Expand Down
40 changes: 40 additions & 0 deletions src/test/scala/chiselTests/properties/PropertySpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ class PropertySpec extends ChiselFlatSpec with MatchesAndOmits {
""")
}

it should "fail to compile with unsupported Property literals" in {
assertTypeError("""
class MyThing
val badProp = Property(new MyThing)
""")
}

it should "support Int as a Property type" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val intProp = IO(Input(Property[Int]()))
Expand All @@ -27,6 +34,17 @@ class PropertySpec extends ChiselFlatSpec with MatchesAndOmits {
)()
}

it should "support Int as a Property literal" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val propOut = IO(Output(Property[Int]()))
propOut := Property(123)
})

matchesAndOmits(chirrtl)(
"propassign propOut, Integer(123)"
)()
}

it should "support Long as a Property type" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val longProp = IO(Input(Property[Long]()))
Expand All @@ -37,6 +55,17 @@ class PropertySpec extends ChiselFlatSpec with MatchesAndOmits {
)()
}

it should "support Long as a Property literal" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val propOut = IO(Output(Property[Long]()))
propOut := Property(123)
})

matchesAndOmits(chirrtl)(
"propassign propOut, Integer(123)"
)()
}

it should "support BigInt as a Property type" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val bigIntProp = IO(Input(Property[BigInt]()))
Expand All @@ -47,6 +76,17 @@ class PropertySpec extends ChiselFlatSpec with MatchesAndOmits {
)()
}

it should "support BigInt as a Property literal" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val propOut = IO(Output(Property[BigInt]()))
propOut := Property(123)
})

matchesAndOmits(chirrtl)(
"propassign propOut, Integer(123)"
)()
}

it should "support connecting Property types of the same type" in {
val chirrtl = ChiselStage.emitCHIRRTL(new RawModule {
val propIn = IO(Input(Property[Int]()))
Expand Down

0 comments on commit 39d4107

Please sign in to comment.