summaryrefslogtreecommitdiff
path: root/src/main/scala/Chisel/Builder.scala
blob: 723470d08731a5ee351be55e78b04063ae74d7a1 (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
package Chisel
import scala.util.DynamicVariable
import scala.collection.mutable.{ArrayBuffer, HashMap}

private class IdGen {
  private var counter = -1L
  def next: Long = {
    counter += 1
    counter
  }
}

class RefMap {
  private val _refmap = new HashMap[Long,Immediate]()

  def setRef(id: Id, ref: Immediate): Unit =
    _refmap(id._id) = ref

  def setRefForId(id: Id, name: String): Unit =
    if (!_refmap.contains(id._id))
      setRef(id, Ref(Builder.globalNamespace.name(name)))

  def setFieldForId(parentid: Id, id: Id, name: String): Unit = {
    _refmap(id._id) = Slot(Alias(parentid), name)
  }

  def setIndexForId(parentid: Id, id: Id, index: Int): Unit =
    _refmap(id._id) = Index(Alias(parentid), index)

  def apply(id: Id): Immediate = _refmap(id._id)
}

private class DynamicContext {
  val idGen = new IdGen
  val globalNamespace = new FIRRTLNamespace
  val globalRefMap = new RefMap
  val components = ArrayBuffer[Component]()
  val currentModuleVar = new DynamicVariable[Option[Module]](None)
  val currentParamsVar = new DynamicVariable[Parameters](Parameters.empty)
  val parameterDump = new ParameterDump

  def getCurrentModule = currentModuleVar.value
  def moduleScope[T](body: => T): T = {
    currentModuleVar.withValue(getCurrentModule)(body)
  }
  def forceCurrentModule[T](m: Module) { // Used in Module constructor
    currentModuleVar.value = Some(m)
  }
  def pushCommand(c: Command) {
    currentModuleVar.value.foreach(_._commands += c)
  }

  def getParams: Parameters = currentParamsVar.value
  def paramsScope[T](p: Parameters)(body: => T): T = {
    currentParamsVar.withValue(p)(body)
  }
}

private object Builder {
  // All global mutable state must be referenced via dynamicContextVar!!
  private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)

  def dynamicContext = dynamicContextVar.value.get
  def idGen = dynamicContext.idGen
  def globalNamespace = dynamicContext.globalNamespace
  def globalRefMap = dynamicContext.globalRefMap
  def components = dynamicContext.components
  def parameterDump = dynamicContext.parameterDump

  def pushCommand(c: Command) = dynamicContext.pushCommand(c)
  def pushOp[T <: Data](cmd: DefPrim[T]) = {
    pushCommand(cmd)
    cmd.id
  }

  def build[T <: Module](f: => T): Circuit = {
    dynamicContextVar.withValue(Some(new DynamicContext)) {
      val mod = f
      globalRefMap.setRefForId(mod, mod.name)
      Circuit(components.last.name, components, globalRefMap, parameterDump)
    }
  }
}