chipsalliance / chisel

Chisel: A Modern Hardware Design Language

Home Page:https://www.chisel-lang.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] expose outer class of `ChiselEnum#Type`

Anillc opened this issue · comments

Type of issue: Feature Request

Is your feature request related to a problem? Please describe.

I'm extending ChiselEnum for some features.

An inner class in the ChiselEnum is bad for extending. It's not possible to override an inner class. Expose the outer class might not be a good solution, but it's effective for me.

Describe the solution you'd like

class Type extends EnumType(this)

Maybe change to class Type(val factor: ChiselEnum) extends EnumType(this)

Additional context

It's possible to use implict class to extend ChiselEnum#Type, but we can't apply implict conversion automatically at runtime.

For example:

trait Default {
  def default: Data
}

abstract class ChiselEnumDefault extends ChiselEnum {
  def default: Type
  implicit class TypeExtension(ty: Type) extends Default {
    override def default = ChiselEnumDefault.this.default
  }
}

object E extends ChiselEnumDefault {
  val a, b, c = Value
  override def default = a
}

val e1 = E()
val foo = e1.default
//  ^ E.a
val e2 = E().asInstanceOf[Data]
val bar = e2.asInstanceOf[Default].default
//           ^ runtime exception   class chisel3.ChiselEnum$Type cannot be cast to class Default

What is the use case for implementing this feature?

Here are some examples:

object Extension {
  implicit class ChiselEnumExtension[T <: ChiselEnum](value: T#Type) {
    def is(select: T => Data) = {
      val field = value.getClass.getField("$outer")
      select(field.get(value).asInstanceOf[T]) === value
    }
  }
}

So we can use foo.is(Foo.bar) instead of foo === Foo.bar. It's shorter.

abstract class EnumDefault extends ChiselEnum {
  def default: Type
}

object Extension {
  implicit class TypeExtension(ty: EnumDefault#Type) {
    def default = {
      val field = ty.getClass.getField("$outer")
      field.get(ty).asInstanceOf[EnumDefault].default
    }
  }
}

object AluOp extends EnumDefault {
  val n, add, sub = Value
  def default = n
}

So we can use AluOp().default to get a literal value.