Examples

There are a few example designs under src/main/scala/examples. The two we will discuss here are the GCD and the Counter.

GCD

The GCD example replicates the same GCD Example in the Async-Click-Library. Cell names have been kept the same to easily see the comparison. In this example, the use of companion objects has been forgone to give the designer a better sense of all of the connections. While it is arguably more verbose than if companion objects had been used, this allows the designer to see each of the node connections a little clearer.

/**
  *   Input and output of the GCD is two UInts. We can set the
  *   width as a paramter
  */
class GCDBundle(width: Int = 8) extends Bundle{
  val a = UInt(width.W)
  val b = UInt(width.W)
}


class GCD(gen : GCDBundle, isTop: Boolean = false)(implicit p: Parameters) extends LazyModule{

  // Note : No (or minimal) companion object use just to keep the ambiguity down
  //        and to more closely match the diagrams in the base click repo

  // input and result are going to be our "ports" that come in/out of the block
  val input   = new OrionSourceNode(Seq(OrionPushPortParameters(Seq(OrionPushParameters(gen, "dataIn")))))
  val result  = new OrionSinkNode  (Seq(OrionPullPortParameters(Seq(OrionPullParameters(gen, "result")))))

  // Defining cells
  val MX0     = LazyModule(new OrionMux(gen))
  val RF0     = LazyModule(new RegFork(gen, pbInit=0, pcInit=0))
  val RF1     = LazyModule(new RegFork(gen, pbInit=0, pcInit=0))
  val R0      = LazyModule(new DecoupReg(Bool(), dataInit=0, poInit=1))
  val F0      = LazyModule(new Fork(Bool()))

  // a != b :
  // Input is two UInts (our GCDBundle)
  // Output is Bool
  val CL0     = LazyModule(new FunctionBlock(gen, Bool())(f => {
    f.out.data := (f.in.data.a =/= f.in.data.b)
  }))

  val DX0     = LazyModule(new Demux(gen))

  // a > b : Output is Bool
  val CL1     = LazyModule(new FunctionBlock(gen, Bool())(f => {
    f.out.data := (f.in.data.a > f.in.data.b)
  }))

  val DX1     = LazyModule(new Demux(gen))


  val CL2     = LazyModule(new FunctionBlock(gen, gen)(f => {
    f.out.data.a := (f.in.data.a - f.in.data.b)
    f.out.data.b := f.in.data.b
  }))
  val CL3     = LazyModule(new FunctionBlock(gen, gen)(f => {
    f.out.data.a := f.in.data.a
    f.out.data.b := (f.in.data.b - f.in.data.a)
  }))

  val ME0     = LazyModule(new Merge(gen))

  // Connecting everything together

  // For Mux/Demux the order of the connections is important. This is why
  // the companion objects could generally be used for more clarity

  // Remember that as you connect multiple edges to a node, you can
  // think of each connection as "appending" to an array, so the first
  // connection is going to be on channel 0, the second on channel 1
  MX0.sel     := R0.out
  MX0.node    := input      // 0
  MX0.node    := ME0.node   // 1

  RF0.in      := MX0.node

  CL0.node    := RF0.out0
  F0.node     := CL0.node

  R0.in       := F0.node

  DX0.sel     := F0.node
  DX0.node    := RF0.out1


  result      := DX0.node   // 0
  RF1.in      := DX0.node   // 1

  CL1.node    := RF1.out0

  DX1.sel     := CL1.node
  DX1.node    := RF1.out1

  CL3.node    := DX1.node
  CL2.node    := DX1.node

  ME0.node    := CL2.node
  ME0.node    := CL3.node


  override lazy val module = new GCDImp(this, gen, isTop)

  ElaborationArtefacts.add("graphml", module.wrapper.graphML)
}


/**
  *   Implementation class to pull out ports if we want to use this as a
  *   top level
  */
class GCDImp(override val wrapper: GCD, gen: GCDBundle, isTop: Boolean = false)(implicit p: Parameters) extends LazyModuleImp(wrapper){
  val in  = if (isTop) Some(IO(Flipped(new OrionBundle(gen)))) else None
  val out = if (isTop) Some(IO(new OrionBundle(gen)))          else None

  if(isTop){
    in.get  <> wrapper.input.out.head._1
    out.get <> wrapper.result.in.head._1
  }
}

GCD Test

Inlcude in the src/test/scala directory is a chiseltest based test called GCDTest. This test will instantiate various implementations of the GCD circuit (with varying UInt widths) and test the GCD circuit for proper operation under randomized input values.

To run this test, you can do the following from the main repo directory:

sbt "testOnly *GCDTest"

Waveforms are saved in VCD format for viewing. Each test will be under the test_run_dir/Orion_GCD_Test_should_check_GCD<width>/ directory.

Counter Example

There is an additional counter example which provides a counter with enable and clear functionality. Included is an accompanying test OrionCounterExampleTest which will enable the counter to count to the max value, clear the counter, and start the count again.

To run this test, you can do the following from the main repo directory:

sbt "testOnly *OrionCounterExampleTest"