Search code examples
chisel

How to writing a accumulator by using ScalaBlackBox?


I want to create some new number types that like DspReal for dsptools, such as DspPosit and DspQuire. DspPosit bases on posit which I have some Java code, and DspQuire bases on quire which is a kind of accumulator for posit. Because I just want to simulation now, so I have write many ScalaBlackBox for their operation like DspReal. However, I found that ScalaBlackBox can't construct sequential logic. For example, current output of the quire accumulator depends on it's input and last output. But ScalaBlackBox can't get the value of the output. In addition, step(n) also influences the output. Because accumulator will read its input per clock cycle.

I found some system problems of treadle. First, the function of ScalaBlackBox, twoOp and oneOp and so on, will be called many times. I don't know why. Second, step(n) is the function of PeekPokeTester, which can't be access by ScalaBlackBox. Third, I try to read current output but system gives errors.

trait DspBlackBlackBoxImpl extends BlackBoxImplementation with ScalaBlackBox

abstract class DspQuireAccumulator extends DspBlackBlackBoxImpl {

  lazy val accValue = Quire32() // initial value

  /**
    * sub-classes must implement this two argument function
    *
    * @param posit  accumulate element
    * @return       quire operation result
    */
  def accOp(posit: Posit32): Unit

  def outputDependencies(outputName: String): Seq[(String)] = {
    outputName match {
      case "out" => Seq("in") // Seq("out", "in") gives errors
      case _ => Seq.empty
    }
  }

  def cycle(): Unit = {}

  def execute(inputValues: Seq[Concrete], tpe: Type, outputName: String): Concrete = {
    val arg1 :: _ = inputValues
    val positArg = Posit32(arg1.value)
    accOp(positArg)
    val result = quire32ToBigInt(accValue)
    ConcreteSInt(result, DspQuire.underlyingWidth, arg1.poisoned).asUInt
  }

  def getOutput(inputValues: Seq[BigInt], tpe: Type, outputName: String): BigInt = {
    val arg1 :: _ = inputValues
    val positArg = Posit32(arg1)
    accOp(positArg)
    quire32ToBigInt(accValue)
  }
}
class DspQuireAddAcc(val name: String) extends DspQuireAccumulator {
  def accOp(posit: Posit32): Unit = accValue += posit
}
class QuireBlackboxAccOperand extends BlackBox {
  val io = IO(new Bundle() {
    val in = Input(UInt(DspPosit.underlyingWidth.W))
    val out = Output(UInt(DspQuire.underlyingWidth.W))
  })
}

class BBQAddAcc extends QuireBlackboxAccOperand

class TreadleDspQuireFactory extends ScalaBlackBoxFactory {
  def createInstance(instanceName: String, blackBoxName: String): Option[ScalaBlackBox] = {
    blackBoxName match {
      case "BBQAddAcc" => Some(add(new DspQuireAddAcc(instanceName)))
...

accOp will be called many times. So, if I want to accumulate List(1, 2, 3), the result maybe 0 + 1 + 1 + 2 + 2 + ... And peek function will call accOp one time again, this makes me confused also.


Solution

  • I believe most of your problems at this point are caused by mixing two different approaches. I think you should not be using BlackBoxImplmentation because it is an older scheme used in with the firrtl-interpreter. Just use the ScalaBlackBox and implement the methods as described in the wiki page Black Boxes and Treadle and shown in the TreadleTest BlackBoxWithState.

    Don't use outputDependencies, and instead specify any dependencies between inputs and outputs with with getDependencies. inputChanged will be called whenever an input IO is changed. So in that method you want to record or update the internal state of your black box. clockChange will be called whenever a clock is changed and will provide the transition information so you can decide what happens then. Treadle will call getOutput whenever it needs that output of your black box, since you will not have used outputDependencies you can ignore the inputs and just provide the output value depending on your internal state.

    I am still trying to reproduce a running version of your code here but it will be a little time for me to put it together, if you can try my suggestions above and let me know how it goes that would be helpful. I am interested in making this feature of Treadle better and easier to use so all feedback is appreciated.