Search code examples
scalafixed-pointchisel

How to use chisel dsptools with floats


I need to convert a Float32 into a Chisel FixedPoint, perform some computation and convert back FixedPoint to Float32.

For example, I need the following:

val a = 3.1F
val b = 2.2F
val res = a * b // REPL returns res: Float 6.82

Now, I do this:

import chisel3.experimental.FixedPoint

val fp_tpe = FixedPoint(6.W, 2.BP)
val a_fix = a.Something (fp_tpe) // convert a to FixPoint
val b_fix = b.Something (fp_tpe) // convert b to FixPoint
val res_fix = a_fix * b_fix
val res0 = res_fix.Something (fp_tpe) // convert back to Float

As a result, I'd expect the delta to be in a range of , e.g

val eps = 1e-4
assert ( abs(res - res0) < eps, "The error is too big")

Who can provide a working example for Chisel3 FixedPoint class for the pseudocode above?


Solution

  • Take a look at the following code:

    import chisel3._
    import chisel3.core.FixedPoint
    import dsptools._
    
    
    class FPMultiplier extends Module {
      val io = IO(new Bundle {
        val a = Input(FixedPoint(6.W, binaryPoint = 2.BP))
        val b = Input(FixedPoint(6.W, binaryPoint = 2.BP))
        val c = Output(FixedPoint(12.W, binaryPoint = 4.BP))
      })
    
      io.c := io.a * io.b
    }
    
    class FPMultiplierTester(c: FPMultiplier) extends DspTester(c) {
      //
      // This will PASS, there is sufficient precision to model the inputs
      //
      poke(c.io.a, 3.25)
      poke(c.io.b, 2.5)
    
      step(1)
      expect(c.io.c, 8.125)
    
      //
      // This will FAIL, there is not sufficient precision to model the inputs
      // But this is only caught on output, this is likely the right approach
      // because you can't really pass in wrong precision data in hardware.
      //
      poke(c.io.a, 3.1)
      poke(c.io.b, 2.2)
    
      step(1)
      expect(c.io.c, 6.82)
    }
    
    
    object FPMultiplierMain {
      def main(args: Array[String]): Unit = {
        iotesters.Driver.execute(Array("-fiv"), () => new FPMultiplier) { c =>
          new FPMultiplierTester(c)
        }
      }
    }
    

    I'd also suggest looking at ParameterizedAdder in dsptools, that gives you a feel of how to write hardware modules that you pass different types. Generally you start with DspReals, confirm the model then start experimenting/calculating with FixedPoint sizes that return results with the desired precision.