summaryrefslogtreecommitdiff
path: root/src/main/scala/chisel3/util/MixedVec.scala
blob: ec15e23abc03aae82878d8938a5851f82ec803d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// See LICENSE for license details.

package chisel3.util

import chisel3._
import chisel3.core.{Data, requireIsChiselType, requireIsHardware}
import chisel3.internal.naming.chiselName

import scala.collection.immutable.ListMap

object MixedVecInit {
  /**
    * Construct a new wire with the given bound values.
    * This is analogous to [[chisel3.core.VecInit]].
    * @param vals Values to create a MixedVec with and assign
    * @return MixedVec with given values assigned
    */
  def apply[T <: Data](vals: Seq[T]): MixedVec[T] = {
    // Create a wire of this type.
    val hetVecWire = Wire(MixedVec(vals.map(_.cloneTypeFull)))
    // Assign the given vals to this new wire.
    for ((a, b) <- hetVecWire.zip(vals)) {
      a := b
    }
    hetVecWire
  }

  /**
    * Construct a new wire with the given bound values.
    * This is analogous to [[chisel3.core.VecInit]].
    * @return MixedVec with given values assigned
    */
  def apply[T <: Data](val0: T, vals: T*): MixedVec[T] = apply(val0 +: vals.toSeq)
}

object MixedVec {
  /**
    * Create a MixedVec from that holds the given types.
    * @param eltsIn Element types. Must be Chisel types.
    * @return MixedVec with the given types.
    */
  def apply[T <: Data](eltsIn: Seq[T]): MixedVec[T] = new MixedVec(eltsIn)

  /**
    * Create a MixedVec from that holds the given types.
    * The types passed to this constructor must be Chisel types.
    * @return MixedVec with the given types.
    */
  def apply[T <: Data](val0: T, vals: T*): MixedVec[T] = new MixedVec(val0 +: vals.toSeq)

  /**
    * Create a new MixedVec from an unbound MixedVec type.
    * @return MixedVec with the given types.
    */
  def apply[T <: Data](mixedVec: MixedVec[T]): MixedVec[T] = new MixedVec(mixedVec.elts)

  /**
    * Create a MixedVec from the type of the given Vec.
    * For example, given a Vec(2, UInt(8.W)), this creates MixedVec(Seq.fill(2){UInt(8.W)}).
    * @param vec Vec to use as template
    * @return MixedVec analogous to the given Vec.
    */
  def apply[T <: Data](vec: Vec[T]): MixedVec[T] = {
    MixedVec(Seq.fill(vec.length)(vec.sample_element))
  }
}

/**
  * A hardware array of elements that can hold values of different types/widths,
  * unlike Vec which can only hold elements of the same type/width.
  *
  * @param eltsIn Element types. Must be Chisel types.
  *
  * @example {{{
  * val v = Wire(MixedVec(Seq(UInt(8.W), UInt(16.W), UInt(32.W))))
  * v(0) := 100.U(8.W)
  * v(1) := 10000.U(16.W)
  * v(2) := 101.U(32.W)
  * }}}
  */
@chiselName
final class MixedVec[T <: Data](private val eltsIn: Seq[T]) extends Record with collection.IndexedSeq[T] {
  // We want to create MixedVec only with Chisel types.
  if (compileOptions.declaredTypeMustBeUnbound) {
    eltsIn.foreach(e => requireIsChiselType(e))
  }

  // Clone the inputs so that we have our own references.
  private val elts: IndexedSeq[T] = eltsIn.map(_.cloneTypeFull).toIndexedSeq

  /**
    * Statically (elaboration-time) retrieve the element at the given index.
    * @param index Index with which to retrieve.
    * @return Retrieved index.
    */
  def apply(index: Int): T = elts(index)

  /** Strong bulk connect, assigning elements in this MixedVec from elements in a Seq.
    *
    * @note the lengths of this and that must match
    */
  def :=(that: Seq[T]): Unit = {
    require(this.length == that.length)
    for ((a, b) <- this zip that)
      a := b
  }

  /**
    * Get the length of this MixedVec.
    * @return Number of elements in this MixedVec.
    */
  def length: Int = elts.length

  override val elements = ListMap(elts.zipWithIndex.map { case (element, index) => (index.toString, element) }: _*)

  // Need to re-clone again since we could have been bound since object creation.
  override def cloneType: this.type = MixedVec(elts.map(_.cloneTypeFull)).asInstanceOf[this.type]

  // IndexedSeq has its own hashCode/equals that we must not use
  override def hashCode: Int = super[Record].hashCode

  override def equals(that: Any): Boolean = super[Record].equals(that)
}