summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/core/Binder.scala
blob: c7346dcec596270ce260cea4da7e58704fc8718b (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
package chisel3.core

/**
* A Binder is a function from UnboundBinding to some Binding.
*
* These are used exclusively by Binding.bind and sealed in order to keep
* all of them in one place. There are two flavors of Binders:
* Non-terminal (returns another UnboundBinding): These are used to reformat an
*   UnboundBinding (like setting direction) before it is terminally bound.
* Terminal (returns any other Binding): Due to the nature of Bindings, once a
*   Data is bound to anything but an UnboundBinding, it is forever locked to
*   being that type (as it now represents something in the hardware graph).
*
* Note that some Binders require extra arguments to be constructed, like the
* enclosing Module.
*/

sealed trait Binder[Out <: Binding] extends Function1[UnboundBinding, Out]{
  def apply(in: UnboundBinding): Out
}

// THE NON-TERMINAL BINDERS
// These 'rebind' to another unbound node of different direction!
case object InputBinder extends Binder[UnboundBinding] {
  def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Input))
}
case object OutputBinder extends Binder[UnboundBinding] {
  def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Output))
}
case object FlippedBinder extends Binder[UnboundBinding] {
  def apply(in: UnboundBinding) = UnboundBinding(in.direction.map(_.flip))
  // TODO(twigg): flipping a None should probably be a warning/error
}
// The need for this should be transient.
case object NoDirectionBinder extends Binder[UnboundBinding] {
  def apply(in: UnboundBinding) = UnboundBinding(None)
}

// THE TERMINAL BINDERS
case object LitBinder extends Binder[LitBinding] {
  def apply(in: UnboundBinding) = LitBinding()
}

case class MemoryPortBinder(enclosure: Module) extends Binder[MemoryPortBinding] {
  def apply(in: UnboundBinding) = MemoryPortBinding(enclosure)
}

case class OpBinder(enclosure: Module) extends Binder[OpBinding] {
  def apply(in: UnboundBinding) = OpBinding(enclosure)
}

// Notice how PortBinder uses the direction of the UnboundNode
case class PortBinder(enclosure: Module) extends Binder[PortBinding] {
  def apply(in: UnboundBinding) = PortBinding(enclosure, in.direction)
}

case class RegBinder(enclosure: Module) extends Binder[RegBinding] {
  def apply(in: UnboundBinding) = RegBinding(enclosure)
}

case class WireBinder(enclosure: Module) extends Binder[WireBinding] {
  def apply(in: UnboundBinding) = WireBinding(enclosure)
}