summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/Chisel/Reg.scala
blob: e69061c58fb1f8e9d3bfbb9165b9677096c09f10 (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
// See LICENSE for license details.

package Chisel

import internal._
import internal.Builder.pushCommand
import internal.firrtl._

object Reg {
  private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = {
    if (t ne null) {
      t.cloneType
    } else if (next ne null) {
      next.cloneTypeWidth(Width())
    } else if (init ne null) {
      init.litArg match {
        // For e.g. Reg(init=UInt(0, k)), fix the Reg's width to k
        case Some(lit) if lit.forcedWidth => init.cloneType
        case _ => init.cloneTypeWidth(Width())
      }
    } else {
      throwException("cannot infer type")
    }
  }

  /** Creates a register with optional next and initialization values.
    *
    * @param t: data type for the register
    * @param next: new value register is to be updated with every cycle (or
    * empty to not update unless assigned to using the := operator)
    * @param init: initialization value on reset (or empty for uninitialized,
    * where the register value persists across a reset)
    *
    * @note this may result in a type error if called from a type parameterized
    * function, since the Scala compiler isn't smart enough to know that null
    * is a valid value. In those cases, you can either use the outType only Reg
    * constructor or pass in `null.asInstanceOf[T]`.
    */
  def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = {
    // TODO: write this in a way that doesn't need nulls (bad Scala style),
    // null.asInstanceOf[T], and two constructors. Using Option types are an
    // option, but introduces cumbersome syntax (wrap everything in a Some()).
    // Implicit conversions to Option (or similar) types were also considered,
    // but Scala's type inferencer and implicit insertion isn't smart enough
    // to resolve all use cases. If the type inferencer / implicit resolution
    // system improves, this may be changed.
    val x = makeType(t, next, init)
    val clock = Node(x._parent.get.clock) // TODO multi-clock
    if (init == null) {
      pushCommand(DefReg(x, clock))
    } else {
      pushCommand(DefRegInit(x, clock, Node(x._parent.get.reset), init.ref))
    }
    if (next != null) {
      x := next
    }
    x
  }

  /** Creates a register without initialization (reset is ignored). Value does
    * not change unless assigned to (using the := operator).
    *
    * @param outType: data type for the register
    */
  def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])
}