Как использовать долотовидные инструменты dsptools с поплавками

Мне нужно преобразовать Float32 в Chisel FixedPoint, выполнить некоторые вычисления и снова преобразовать FixedPoint в Float32.

Например, мне нужно следующее:

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

Теперь я делаю это:

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

В результате я бы ожидал, что дельта будет в диапазоне, например

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

Кто может предоставить рабочий пример класса Chisel3 FixedPoint для псевдокода выше?


person Tampler    schedule 23.09.2018    source источник


Ответы (3)


Взгляните на следующий код:

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)
    }
  }
}

Я также предлагаю посмотреть на ParameterizedAdder в dsptools, который дает вам представление о том, как писать аппаратные модули, которые вы проходят разные типы. Обычно вы начинаете с DspReals, подтверждаете модель, затем начинаете экспериментировать / вычислять с размерами фиксированных точек, которые возвращают результаты с желаемой точностью.

person Chick Markley    schedule 24.09.2018
comment
Я не могу скомпилировать этот код вместе с параметризованным сумматором в домашней папке dsptools. Если я сделаю: sbt test: runMain examples.ParametrizedAdderSpec или sbt test: runMain my_pkg.FPMultiplierMain, я получаю Неразрешенные зависимости: Примечание: Путь неразрешенных зависимостей: [предупреждение] edu.berkeley.cs: chisel3_2.12: 3.2-SNAPSHOT (/ home /bku/work/cores/bar/dsptools/build.sbt#L99) [предупреждение] + - edu.berkeley.cs: dsptools_2.12: 1.3-SNAPSHOT [предупреждение] edu.berkeley.cs: chisel-iotesters_2.12: 1.3-SNAPSHOT (/home/bku/work/cores/bar/dsptools/build.sbt#L99) - person Tampler; 24.09.2018
comment
Dsptools все еще находится в процессе официального выпуска и имеет некоторые проблемы в основной (разрабатываемой) ветке. Попробуйте перейти на версию 1.1.3, запустив git checkout 1.1.3, а затем запустив тест - person Chick Markley; 24.09.2018
comment
Отлично, сработало! Теперь, как мне установить допуск взгляда? Я пробовал DspTester.setTol (1e-4, 8) и this.setTol (1e-4, 8), но они не компилируются - person Tampler; 24.09.2018
comment
Я думаю, что элементы управления, которые вы ищете, находятся в src / main / scala / dsptools / tester / DspTesterOptions.scala. Вы передаете эти элементы управления, добавляя флаги к экземпляру dspTestersOptions в DspTesterOptionsManager. - person Chick Markley; 26.09.2018
comment
Да, это именно то, что я сделал. Я нашел решение для этого, но не могу понять, как передать комплексные числа в свой модуль. В вашем проекте dsptools нет примеров сложных вещей! Пожалуйста, проверьте мой последний код в вопросе. Я опубликовал параметризованную реализацию, и мне нужно обновить ее для поддержки сложного кольца. Спасибо! - person Tampler; 26.09.2018
comment
Привет, @ChickMarkley. Я пытался использовать упомянутый здесь формат FixedPoint, но когда я передаю это значение, скажем, 4.BP, я получаю сообщение об ошибке: ›значение BP не является членом Int. Вы можете помочь мне исправить эту ошибку? Есть ли новый способ представления чисел FixedPoint в долоте, о котором я не знаю? - person CV_Ruddha; 23.07.2020

Для других я предлагаю улучшенное решение от @Chick, переписанное на более абстрактный Scala с переменными допусками DSP.

package my_pkg

import chisel3._
import chisel3.core.{FixedPoint => FP}

import dsptools.{DspTester, DspTesterOptions, DspTesterOptionsManager}

class FPGenericIO (inType:FP, outType:FP) extends Bundle {
  val a = Input(inType)
  val b = Input(inType)
  val c = Output(outType)
}

class FPMul (inType:FP, outType:FP) extends Module {
  val io  = IO(new FPGenericIO(inType, outType))
  io.c := io.a * io.b
}

class FPMulTester(c: FPMul) extends DspTester(c) {

  val uut = c.io

  // This will PASS, there is sufficient precision to model the inputs
  poke(uut.a, 3.25)
  poke(uut.b, 2.5)

  step(1)
  expect(uut.c, 3.25*2.5)

  // This will FAIL, if you won't increase tolerance, which is eps = 0.0 by default
  poke(uut.a, 3.1)
  poke(uut.b, 2.2)

  step(1)
  expect(uut.c, 3.1*2.2)
}


object FPUMain extends App {

  val fpInType  = FP(8.W, 4.BP)
  val fpOutType = FP(12.W, 6.BP)

// Update default DspTester options and increase tolerance
  val opts = new DspTesterOptionsManager {

    dspTesterOptions = DspTesterOptions(
      fixTolLSBs = 2,
      genVerilogTb = false,
      isVerbose = true
    )
  }

  dsptools.Driver.execute (() => new FPMul(fpInType, fpOutType), opts) {
    c => new FPMulTester(c)
  }
}
person Tampler    schedule 25.09.2018

Вот моя окончательная реализация умножителя DSP, которая должна поддерживать числа как FixedPoint, так и DspComplex. @ChickMarkley, как мне обновить этот класс, чтобы реализовать сложное умножение?

package my_pkg

import chisel3._

import dsptools.numbers.{Ring,DspComplex}
import dsptools.numbers.implicits._
import dsptools.{DspContext}

import chisel3.core.{FixedPoint => FP}
import dsptools.{DspTester, DspTesterOptions, DspTesterOptionsManager}


class FPGenericIO[A <: Data:Ring, B <: Data:Ring] (inType:A, outType:B) extends Bundle {
  val a = Input(inType.cloneType)
  val b = Input(inType.cloneType)
  val c = Output(outType.cloneType)

  override def cloneType = (new FPGenericIO(inType, outType)).asInstanceOf[this.type]

}

class FPMul[A <: Data:Ring, B <: Data:Ring] (inType:A, outType:B) extends Module {

  val io  = IO(new FPGenericIO(inType, outType))

  DspContext.withNumMulPipes(3) {
    io.c := io.a * io.b
  }
}

class FPMulTester[A <: Data:Ring, B <: Data:Ring](c: FPMul[A,B]) extends DspTester(c) {

  val uut = c.io

  //
  // This will PASS, there is sufficient precision to model the inputs
  //
  poke(uut.a, 3.25)
  poke(uut.b, 2.5)

  step(1)
  expect(uut.c, 3.25*2.5)

  //
  // 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(uut.a, 3.1)
  poke(uut.b, 2.2)

  step(1)
  expect(uut.c, 3.1*2.2)
}


object FPUMain extends App {

  val fpInType  = FP(8.W, 4.BP)
  val fpOutType = FP(12.W, 6.BP)
  //val comp = DspComplex[Double] // How to declare a complex DSP type ?

  val opts = new DspTesterOptionsManager {

    dspTesterOptions = DspTesterOptions(
      fixTolLSBs = 0,
      genVerilogTb = false,
      isVerbose = true
    )
  }

  dsptools.Driver.execute (() => new FPMul(fpInType, fpOutType), opts) {
  //dsptools.Driver.execute (() => new FPMul(comp, comp), opts) { // <-- this won't compile
    c => new FPMulTester(c)
  }
}
person Tampler    schedule 25.09.2018