GithubHelp home page GithubHelp logo

ucb-bar / dsptools Goto Github PK

View Code? Open in Web Editor NEW
213.0 37.0 38.0 1.85 MB

A Library of Chisel3 Tools for Digital Signal Processing

License: Apache License 2.0

Scala 96.58% Verilog 3.12% Shell 0.31%

dsptools's Introduction

DSP Tools Development Environment

Test

This repository serves as a good starting point for making and easily testing your various DSP generators in Chisel (1 generator at a time). See UC Berkeley Chisel homepage for more information about Chisel.

For a list of common errors, check out the wiki page. Feel free to add your own!


Key Enhancements

Dsptools is a library that can be used with any Chisel library. Some of the goals of dsptools are to enable:

  1. Pipeline delay checking (Isn't it annoying when the delays of two signals into an operation don't line up because you forgot to delay a corresponding signal in your haste to close timing?)

  2. Enhanced support for designing and testing DSP with generic types (i.e. switching between DSPReal for verifying functional correctness with double-precision floating point and FixedPoint for evaluating fixed-point design metrics by changing a single parameter).

  3. More useful and universal testing platform for numeric types!

Numbers are displayed in their correct formats instead of hex for peek, poke, and expect operations. Additionally, if your tester extends DSPTester, you can optionally dump your test sequence to a Verilog testbench that replays the test for functional verification on all simulation platforms (i.e. Xilinx, Altera, etc. instead of only VCS). The tolerance of comparisons with expected values can also be changed via DSPTester.setTol(floTol = decimal_tolerance, fixedTol = number_of_bits).

  1. Miscellaneous additional features
  • Wide range of LUT modules for ease of generating lookup tables from pre-calculated constants (no intermediate representation).
  • Memory modules that abstract out confusion associated with Chisel Mem.
  • Generates useful helper files with each Verilog output (constraints, generator parameters used, etc.).
  • Easier to rename modules & signals and have renaming actually succeed.
  • Expanding Support for non-base-2 math.
  • Adds support for numerical processing in the Chisel Environment via Breeze.

Getting Started

Dsptools is published alongside Chisel, FIRRTL, and the other related projects. It can be used by adding

libraryDependencies += "edu.berkeley.cs" %% "dsptools" % "XXXX"

to your build.sbt, where XXXX is the desired version. See Github for the latest release. Snapshots are also published on Sonatype, which are beneficial if you want to use the latest features.

Projects that dsptools depends on are:


Numeric Typeclasses

This library defines a number of typeclasses for numeric types. A brief explanation of how typeclasses work in scala can be found here. Our DSP-specific typeclasses are built on top of spire.

The goal of these typeclasses is to make it easy to write Chisel modules that treat the number representation as a parameter. For example, using typeclasses you can write Chisel that generates an FIR filter for both real and complex numbers. You can also use typeclasses to write Chisel that generates a circuit implementation using floating point (via Verilog's real type). After testing that your circuit implementation works with floating point, you can use the same code to generate a fixed point version of the circuit suitable for synthesis.

For a additional, more detailed description of the Numeric classes in dsptools: see The Numbers ReadMe

A generic function in Scala programming language is defined like so:

def func[T](in: T): T

This means that you can call func(obj) for an object of any type. If obj is of type Q, you can write func[Q](obj) to specify that we want the Q version of the generic function func, but this is only necessary if the Scala compiler can't figure out what Q is supposed to be.

You can also write

class SomeClass[T]

and use T like it is a real type for any member functions of variables. To write a generic Chisel Module, we might try to write

class Passthrough[T](gen: T) extends Module {
  val io = new IO(Bundle {
    val in = Input(gen)
    val out = Output(gen)
  })
  io.out := io.in
}

Here, gen is a parameter specifying the type you want to use for your IO's, so you could write Module(new Passthrough(SInt(width=10))) or Module(new Passthrough(new Bundle { ... })). Unfortunately, there's a problem with this. T can be any type, and a lot of types don't make sense, like String or ()=>Unit. This will not compile, because Input(), Output(), and := are functions defined on Chisel types. We can fix this problem by writing

class Passthrough[T<:Data](gen: T) extends Module

This type constraint means that we have to choose T to be a subtype of the Chisel type Data. Things like UInt, SInt, and Bundle are subtypes of Data. Now the example above should compile. This example isn't very interesting, though. Data lets you do basic things like assignment and make registers, but doesn't define any mathematical operations, so if we write

class Doubler[T<:Data](gen: T) extends Module {
  val io = IO(new Bundle {
    val in = Input(gen)
    val out = Output(gen)
  })
  io.out := io.in + io.in
}

it won't compile. This is where typeclasses come in. This library defines a trait

trait Real[T] {
  ...
  def plus(x: T, y: T): T
  ...
}

as well as an implicit conversion so that a+b gets converted to Real[T].plus(a,b). Real[T] is a typeclass. Typeclasses are a useful pattern in Scala, so there is syntactic sugar to make using them easy:

import dsptools.numbers._
class Doubler[T<:Data:Real](gen: T) extends Module

Note: If you don't include the :Real at the end, the Scala compiler will think io.in + io.in is string concatenation and you'll get a weird error saying

[error]  found   : T
[error]  required: String

Some useful typeclasses:

  • Ring

    • defines +, *, -, **, zero, one
    • defined in Spire
    • Read: https://en.wikipedia.org/wiki/Ring_(mathematics)
    • Note: We chose to restrict ourselves to Ring rather than Field because division is particularly expensive and nuanced in hardware. Rather than typing a / b we think it is better to require users to instantiate a module and think about what's going on.
  • Eq

    • defines === and =/= (returning Chisel Bools!)
  • PartialOrder

    • extends Eq
    • defines >, <, <=, >= (returning a ValidIO[ComparisonBundle] that has valid false if the objects are not comparable
  • Order

    • extends PartialOrder
    • defines >, <, <=, >=, min, max
  • Sign

    • defines abs, isSignZero, isSignPositive, isSignNegative, isSignNonZero, isSignNonPositive, isSignNonNegative
  • Real

    • extends Ring with Order with Sign
    • defines ceil, round, floor, isWhole
    • defines a bunch of conversion methods from ConvertableTo, e.g. fromDouble, fromInt
  • Integer

    • extends Real
    • defines mod

Rocket-chip

Integration of dsptools with a rocket-chip based project:

The github project Rocket Dsp Utils contains useful tools that can be used to integrate components from this project with a rocket-chip based one.

These tools formerly were contained in this repo under the rocket sub-directory.


This code was maintained by Chick, Angie and Paul. Let us know if you have any questions/feedback!

Copyright (c) 2015 - 2022 The Regents of the University of California. Released under the Apache-2.0 license.

dsptools's People

Contributors

abejgonzalez avatar azidar avatar chick avatar edwardcwang avatar felixonmars avatar grebe avatar harrisonliew avatar jackkoenig avatar jascondley avatar jerryz123 avatar konda-x1 avatar milovanovic avatar sequencer avatar shunshou avatar singularitykchen avatar stevobailey avatar tymcauley avatar ucbjrl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dsptools's Issues

Should we add implicits to dsptools.numbers package object?

I'm finding that 99% of the dsptools code I write requires the following:

import dsptools._
import dsptools.numbers._
import dsptools.numbers.implicits._

I think there is a use case for using dsptools without the numbers, but I'm not so sure it makes sense to use dsptools.numbers without the implicits.

Make dsptools parallel-friendly

Apparently something with ParameterizedSaturatingAdder (or something) plays around with global state that might cause some other tests to fail since chisel runs ScalaTest test cases in parallel.

Not equals

Is there a reason why it's =!=? As opposed to the Chisel standard =/= ?

Edit: Ok, I guess it's b/c it's a Spire macro thing?

Examples should go in a different repo

dsptools is really cluttered... Stuff in my new TODO folder should eventually be moved out into a Utilities repo, and I think Examples should also be another repo (with better examples -- don't need "streamingautocorrelator"; need here's how we do context overflow for x,y,z op. More specific DSP functions should be their own separate Library repo.

Semantics for DspComplex: Imaginary?

Why not be consistent w/ Breeze, etc. and have c.imag instead of c.imaginary?

class DspComplex[T <: Data:Ring](val real: T, val imaginary: T) extends Bundle {
  override def cloneType: this.type = {
    new DspComplex(real.cloneType, imaginary.cloneType).asInstanceOf[this.type]
  }

Still support +&, etc. without DSPContext

Having to type DspContext.withOverflowType(Grow) { io.in.bits.x + io.in.bits.y } is kind of annoying if you know there are particular places [even within a given submodule] that you want +& vs. whatever is standard...

Can someone help me understand what's wrong?

I believe this test compiled, correct?

Which would imply that something like:

val test = -18.3.F(10.BP) should also compile, right?

I'm trying to test ranges, and am running into problems with Chisel being incorrect.

Consider: https://github.com/freechipsproject/chisel3/blob/ec827bef21263517140efd08c3b6dc31e309e52a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala#L95

Or more specifically (code hasn't been updated in ages):

case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
  def name: String = {
    val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
    s"asSInt(${ULit(unsigned, width).name})"
  }
  def minWidth: Int = 1 + n.bitLength
}

case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
  def name: String = {
    val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
    s"asFixedPoint(${SLit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
  }
  def minWidth: Int = 1 + n.bitLength
}

LitArg has a width check to see if the width specified (w) is at least as large as minWidth (1 + n.bitLength). This is fine for FPList BUT s"asFixedPoint(${SLit(unsigned, width).name} creates an SLit that checks this again. Since n for SLit is the unsigned representation, we know that minWidth should be n.bitLength (no +1). Unfortunately, currently width check always throws an exception when NEGATIVE FP or Interval lits are used.

I've made a (temporary?) workaround in the range-related branch for Chisel [I can also make a PR to master, but I figure the only people using FP + Interval Lits are Paul and me right now..., so maybe it's OK to lump this in with whenever ranges become mainstream... and my workaround is probably something that others would find issue issue with], but this looks to very much be a bug.

I just don't understand why it didn't throw the same error in the dsptools test. Is it because of the fact that I created a Lit in a Bundle???

Anyone have time to look into this? @chick @grebe

Someone really needs to go through Range/FP related IR and stuff in Bits right now, 'cause I feel like it's half written. :o I had to make a lot of changes just to get any user code testable. :o And (as we were aware of before) it's also horribly out of sync with master branches, so patches would make this diverge even more from master... @_@

As an FYI -- you can keep track of which branches I'm using (excluding barstools, because I've removed anything referencing it for now) here (see update.bash): https://github.com/ucb-art/Chisel3DSPDependencies/tree/ranges

And the code I'm testing (for those w/ access) is at https://github.com/ucb-art/FFTGen
Specifically: https://github.com/ucb-art/FFTGen/blob/chisel3_transition/src/main/scala/dsptools/intervals/tests/AAPaperExample.scala


As a side note, @chick I can't use the branch of firrtl-interpreter that has the range analysis stuff with a combination of these other branches. Something was added in the combinational loop PR that messed things up (something about .copy??? not existing? -- I lost the actual compile message).

Can you look into that?

We can discuss more at our meeting, but I just wanted to get the issue out to seed the discussion and potentially any work before our meeting.


Couple of other "I can't get proper math behavior" bugs out of range stuff before I check to see if ranges were inferred correctly... Hopefully, I can figure that out. It'd be nice if someone helped write out more simple test cases too, now that I have a way to hook up Interval IO and still use normal Chisel testers (which is what I spent the last couple of days on).

Thx! :)

PaperProject Details

Branches

project branch
firrtl intervals
chisel3 interval-type-2
firrtl-interpreter instrumenting-sizes

Some tests fail now

With the bump-firrtl branches of firrtl-interpreter and chisel-testers, I get these errors:

[info] Exception encountered when attempting to run a suite with class name: dsptools.numbers.BlackBoxFloatSpec *** ABORTED ***
[info] java.lang.NoSuchMethodError: firrtl.FirrtlExecutionOptions$.apply$default$7()Lscala/collection/immutable/List;
[info] at chisel3.BackendCompilationUtilities$$anon$1.(Driver.scala:70)
[info] at chisel3.BackendCompilationUtilities$class.compileFirrtlToVerilog(Driver.scala:68)
[info] at chisel3.testers.TesterDriver$.compileFirrtlToVerilog(TesterDriver.scala:8)
[info] at chisel3.testers.TesterDriver$.execute(TesterDriver.scala:61)
[info] at chisel3.iotesters.ChiselRunners$class.runTester(ChiselSpec.scala:17)
[info] at chisel3.iotesters.ChiselFlatSpec.runTester(ChiselSpec.scala:26)
[info] at chisel3.iotesters.ChiselRunners$class.assertTesterPasses(ChiselSpec.scala:20)
[info] at chisel3.iotesters.ChiselFlatSpec.assertTesterPasses(ChiselSpec.scala:26)
[info] at dsptools.numbers.BlackBoxFloatSpec$$anonfun$6.apply$mcV$sp(BlackBoxFloat.scala:45)
[info] at dsptools.numbers.BlackBoxFloatSpec$$anonfun$6.apply(BlackBoxFloat.scala:45)
[info] ...

Similar for dsptools.numbers.DspComplexExamplesSpec

Does dsp-real-support-2 need to be merged? I'm confused- I thought we merged the blackbox stuff into master.

How to do Double to T conversion?

if I have gen : => R, where R <: Data:Real, how do I get a constant (say 3.3333) of type R?

I would have wanted to try something like gen.fromDouble(3.3333), but I got value fromDouble is not a member of type parameter R.

I saw in Stevo's FFT:

implicitly[Real[R]].fromDouble(3.333333)

At least this compiles...

But my question then is, how do you specify the width, # of fractional bits of the constant?

I assume, through some kind of implicit something or another, if gen was passed FixedPoint(32.W, 16.W), it'd know that the constant would have width = 32, with 16 bit fractional width...

But if I wanted to have another constant with width = 16, fracWidth = 8, would I need another gen? i.e.

gen1 : => R for 32,16
gen2 : => A for 16,8

?

Also, why does gen1.fromDouble / gen2.fromDouble not work? And instead I have to use implicitly[Real[R]].fromDouble, implicitly[Real[A]].fromDouble?

Or rather, is the width just supposed to be auto-inferred somehow?

I noticed that in Chisel3, for FixedPoint, you have:

def fromDouble(value: Double, dummy: PrivateType = PrivateObject, width: Int = -1, binaryPoint: Int = 0)

But the ability to specify width and binary point doesn't seem to be carried over to the fromDouble in ConvertableToFixedPoint in dspTools?

These kinds of things really really really should be documented...

Do any of the features enabled by DSPContext actually work?

Or is it just a shell for yet-to-be implemented stuff?

I can live with overflow always growing, but it'd be good to, by default, register values for fixed multiply/add, etc. and it seems that's not done. Of course, if I go and change it directly in the type class, existing designs will be affected.

Also, there's no option for 3 real multiplier complex multiplies?

This matters more for me because I don't have a straight pipelined architecture, and there's a good amount of computation I need to break up into chunks...

Interfaces should be in a separate repo

You shouldn't need to pull in testchipip and rocket-chip to build small DSP blocks. In general, a lot of things were added here "for convenience", but they bloat DSPtools with non-DSP-y things.

Future DSP Numbers refactoring

Currently, I don't think the way numbers is written is very logical. (File organization, etc.) -- there should be more apparent hierarchy, etc. It's really hard to figure out what's going on by looking at the code...

BlackBoxFloat Ln and Log10

VCS is super unhappy with them (not sure how you can constrain the input to be >0 b/c it keeps saying it's invalid for in < 0)... I've been commenting them out every time I run tests, which kind of sucks. I recall @ducky64 had a PR that pulled ops out (so you wouldn't be importing all of the Real SystemVerilog ops if you only used one or two). We should consider merging ASAP.

Did you guys actually fix fixed point tester problems?

I'm not really sure how any fixed point hardware could've possibly tested out correctly.

I think this tester behavior is the same as in Chisel2:

If you trace a poke, in the backend, the BigInt to the DUT is signed, whereas, if you trace a peek, from the backend, the BigInt is unsigned (although, depending on the data type, it should be interpretted as signed).

This is problematic because:

  1. For chisel-testers, if you want to peek/poke an SInt and then do a compare, the poked (BigInt) input won't equal the unsigned peeked output. Sure, you could convert the value to signed and then things check out.

  2. For dsptesters, the dspExpects should fail on Fixed for the same reason. The doubles that are compared don't make sense for signed outputs. i.e.

expect got 65534.50000000 expect -1.50000000 ( w/ FixedPoint(32.W, 16.BP)).


I recall vaguely that there was some talk about sign conversion, but it doesn't look like this was ever done properly?

The old Chisel2 tester had a sign conversion function that worked...

Am I missing something???

@grebe @chick @stevobailey

Set up Travis CI

@chick @ucbjrl I don't have the permissions to set up travis. We should do this.

I'll add a .travis.yml if one of you don't mind setting up travis's side of things.

@ucbjrl is there a way to set it up to do nightly builds? I'd like to run a script that checks out the head of master of everything and check that it still works. Our last floating point regression shouldn't have been around for so long.

SInt from Double

What should the convention be? Some places, I've seen x.round.toInt; other places I've seen x.toInt... I've been sticking to x.round.toInt, but this should be made consistent...

Using DspReal somewhere should generate warning in verilog

We've talked about adding UInt -> DspReal functionality. We already have DspReal -> UInt. Having both makes it a lot easier for unsynthesizable code to get left in accidentally, especially by library code.

There should be some sort of mechanism that warns a user that unsynthesizeable code is being generated as well as a note about what code is adding it. Perhaps a comment at the top of the emitted verilog as well as a print statement during chisel generation.

Clean up copy pasta...

Whenever someone has time... DSP tester really needs to be refactored.

case "real"  =>
            val bigIntReal      = dspPeek(c.real.asInstanceOf[DspReal]).left.get
            val bigIntImaginary = dspPeek(c.imaginary.asInstanceOf[DspReal]).left.get
            Right(Complex(bigIntReal, bigIntImaginary))

Clearly, the output of dspPeek isn't a "bigInt"... Makes it hard to read the code.

Also, strangely enough, the code in def peek(signal: FixedPoint): is different from that in `case r: FixedPoint =>
val bigInt = super.peek(r)
Left(FixedPoint.toDouble(bigInt, r.binaryPoint.get))

They do the same thing, but make different assumptions: i.e. one does r.binaryPoint.get; the other matches on whether binary point is known.

Knowing when something is in a ring

The following circuit ignores the DspContext directive.

class BadUIntSubtractWithGrow extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val o = Output(UInt(4.W))
  })
  val r = RegNext(DspContext.withOverflowType(Grow) { io.a - io.b })
  io.o := r
}

The reason is that since the IO's are not declared with generators that have been given a Ring constraint the - that is used is the basic chisel one and not the one in UInt Ring.
As a result this circuit compiles, despite that subtract with overflow type Grow is not supported

Seriously questioning whether typeclasses are the right way to do things

Re-emphasizing Chick's problem with having

val a = UInt(3.W)
val b = 2.U * a - a

NOT using the "-" behavior defined by the typeclass.


All of my control logic in Chisel2 ChiselDSP used +, -, * op overrides for UInt, but this was done by explicitly using DSPUInt instead of UInt.

In order to write any control logic using the DspContext behavior for +, -, etc. I NEED to pass in gen's. This is not really tractable and also EXTREMELY confusing to the user.

Reflecting on the use-case, it seems like Typeclasses should NOT be used to override the default behaviors of things using them (only add ops, trackers, etc. on top of them).

@grebe @chick

I think this is a serious flaw, and basically I'm stuck. The API needs to be rethought out, which unfortunately requires updating all of the code yet again, but I guess that won't happen until after tapeout...

Or I just don't make tapeout.

The complex times a fixedpoint problem

@stevobailey has identified a problem where parameterized types being passed to a module may result in operators being applied to two different types. For example: a FixedPoint number being multiplied with a DspComplex[FixedPoint]. Type classes do not help us here because the operand are not of the same type. @grebe created an implementation using additional implicits that allow the FixedPoint to be coerced upward in order to correctly apply the desired operations. After a long discussion with @stevobailey @shunshou @chick and @grebe it was believed that we identified an simpler more explicable scheme involving traits that can be added to modules that would get the desired results. This issue is to make sure we don't lose track of that goal.

Complex + Mux

This shows up... not sure what's going on:

[info]   java.lang.IllegalArgumentException: requirement failed: can't create Mux with non-equivalent types dsptools.numbers.DspComplex@434 and dsptools.numbers.DspComplex@9e
[info]  

Potential issue with Ring[T].zero for Complex

Not really sure what's going on and I found a way around it -- but I was getting non-synthesizable node errors by directly assigning Complex to Ring[T].zero where T <: Data:RealBits.

Just making a note for the future.

Workaround was to individually assign real/imag to Lits.

Also, this wasn't a problem with FixedPoint, only with DspReal.

Context stuff with Reg's

There should be a warning or something else that makes it more obvious that if you want to use anything except the normal clock to clock the ShiftRegisters, you need to explicitly change the corresponding dynamic variable.

Fixed point needs to be populated with features

trait FixedPointIsReal extends Any with IsReal[FixedPoint] with FixedPointOrder with FixedPointSigned with hasContext {
  def toDouble(a: FixedPoint): DspReal = ???
  def ceil(a: FixedPoint): FixedPoint = ???
  def floor(a: FixedPoint): FixedPoint = ???
  def isWhole(a: FixedPoint): Bool = ???
  def round(a: FixedPoint): FixedPoint = ???

Lits not being marked as lits + LUTs

Basically, DspReal relies on a node inside a bundle that is declared as an output, and therefore, even if you're creating a constant that's of type DspReal, x.isLit() will return false. That's inconsistent with Data behavior in the rest of Chisel3.

The same goes for DspComplex.

Granted, even in Chisel3, if you have a Vec of Lits, it seems like Lits aren't registered as such.

Therefore, when I peek one of the aforementioned types, I get "Can't find SimpleModule.lutGen_4 in the emulator..." b/c the isLit check in peek returns false, but Lits aren't actually handled w/ the emulator...

I'll probably go ahead and add some isLit flag for DspComplex and DspReal (not sure if I can just turn something on for DspReal.node to make it indicate it's a Lit or if I need to make an outside val to do that...). I am not really sure how to resolve this issue for Vec.


Also, re: LUTs, I'm not sure if Verilog like

  assign lutGen_0 = 4'shd;
  assign lutGen_1 = 4'she;
  assign lutGen_2 = 4'shf;
  assign lutGen_3 = 4'sh0;
  assign lutGen_4 = 4'sh1;
  assign lutGen_5 = 4'sh2;
  assign lutGen_6 = 4'sh3;

would lead to tools not being able to do some optimization as opposed to the more conventional (at least for FPGAs) way of:

http://www.csee.umbc.edu/~tinoosh/cmpe415/slides/Rom-LUT-verilog.pdf

I have yet to test out any hypothesis regarding this, but it'd suck if we find out last minute that tools are less good about P&Ring or w/e with this kind of output vs. something more standard.

Support for trig functions w/ Verilator

I believe with SystemVerilog, you can do stuff like $atan, so I assume this should work with Verilator? I'd like to be able to compute an angle with CORDIC, which only operates on synthesizable bits, but also be able to swap the CORDIC block out with some non-synthesizable trig function + appropriate delays, for the purposes of simulating SQNR/performance degradation between floating pt and fixed pt types in a full system**. I can get around having it in dsptools by ExtModuling a BB Verilog wrapper, which might make sense... but at the same time, it might make more sense to wrap CORDIC in a function with params that can be switched off with a non-synthesizable implementation.

And just as a reference, apparently trig stuff was supported in Chisel2 Flo.

BlackBoxFloat

@chick I get these warnings:

%Warning-COMBDLY: /Users/angie.wang/Chisel3FFAST/FFTGen/test_run_dir/FFASTTopTB/dspblocks.fft.FFASTTopSpec260459830/BlackBoxFloat.v:46: Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).
%Warning-COMBDLY: Use "/* verilator lint_off COMBDLY */" and lint_on around source to disable this message.
%Warning-COMBDLY: *** See the manual before disabling this,
%Warning-COMBDLY: else you may end up with different sim results.
%Warning-COMBDLY: /Users/angie.wang/Chisel3FFAST/FFTGen/test_run_dir/FFASTTopTB/dspblocks.fft.FFASTTopSpec260459830/BlackBoxFloat.v:26: Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).
%Warning-COMBDLY: /Users/angie.wang/Chisel3FFAST/FFTGen/test_run_dir/FFASTTopTB/dspblocks.fft.FFASTTopSpec260459830/BlackBoxFloat.v:172: Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).
%Warning-COMBDLY: /Users/angie.wang/Chisel3FFAST/FFTGen/test_run_dir/FFASTTopTB/dspblocks.fft.FFASTTopSpec260459830/BlackBoxFloat.v:16: Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).

Probably best to clean up?

Does fromDoubleWithFixedWidth work?

@chick See chipsalliance/chisel#558
I'm using fromDoubleWithFixedWidth, so if it's getting width = 26 instead of width = 28 for the constants, it implies this thing didn't work... I have no idea why... (unless Chisel also doesn't width pad in reality... despite supporting the construct).

Can you please look into this for me?

I'm just running into so many problems that I can't get any hardware done.

DSP Type parameterization suggestion

In general, if you want to switch between DspReal and FixedPoint, I think it makes sense to be able to externally specify # fixed point bits via your favorite case class, CDE, or other parameterization method.

Really, I think I just care that I pass in Fixed, Real, and then within the module itself, have some custom chiselCloneType that lets you specify you want a Fixed with width blah and fracWidth blah2.

Parameterization = # of bits, # frac bits
Selecting Real/Fixed types is a separate thing

It's easier to pass in one genType and store Ints representing # of bits in a case class rather than genW32F16, genW16F14.

--- This would also make more sense for generating constants of type T -- you specify frac bits along with the actual constant.

Thorough DSP Tests

Here's a bunch of scenarios I thought up that need to be tested. I hope i addressed these all in my code, but I could've missed some things... so it'd be nice if someone other than me tested. @chick

Sorry this might be confusing -- feel free to ask what I mean.


Test with Verilator + FirrtlInterpreter: mostly test w/ Verilator.

In general, don't need to test with too many bits, fractional bits (probably something like 8.W, 4.BP), but you should test across the full range of values (incrementing by say something like 0.05).

All DspContexts should be checked -- understand overflow behavior given Grow/Wrap and see that the result is correct. Good thing to have someone else who didn't write the code make the TB to ensure that the functionality is clear.

For SInt, Fixed, check that taking the absolute value of the most negative # supported by the width does the right thing -- it depends on Overflow behavior.

-(Most negative number) should also have different results based off of Context.

Inputs to operators should have different bitwidths and binary points to make sure things get padded out correctly (from brief experimentation, things look right).

Add/subtract/multiply numbers of different signs: ++, --, -+, +-
a + b might be like
q = Seq( -3.7, -3.3, -2.7, -2.2, -1.7, -1.1, -0.7, -0.5, -0.4, 0.0, 0.4, 0.7, 1.1, 1.7, 2.2,2.7, 3.3, 3.7)
a = q ++ q.reverse
b = q ++ q
Make sure that rounding in either direction is tested (i.e. -3.7, 3.3 have different outputs)

When testing shift left, shift right, make sure you also shift more than the bitwidth (shift in increments of 1) to test out expected behavior.

Test connection from DspReal/FixedPoint to FixedPoint/DspReal for golden model verification (even though the design isn't synthesizable).

Check that ops requiring using different rounding modes: FixedPoint multiply, FixedPoint div2, Round, etc. (refer to README) overflow correctly (context dependent) when rounding up (and the original value is the max representable).

Check that Chisel + Firrtl known widths and known binary points match up. For example, setBinaryPoint doesn't seem to work when more binary points than current are specified (only in Chisel). In Chisel, the # of fractional bits increase, but the width stays the same, implying you're losing MSBs. Firrtl does this properly, but if I'm query-ing the Chisel KnownWidth, I'd be mislead. In general, the Chisel + Firrtl width + binary point inference for anything known should be double checked.

Try changing DspContext @ different levels: Module, operation, top level design and make sure the context is correct within the {}. Also, I assume the user might have

class XMod extends Module {
  DspContext.blah.withValue(x) {
    /* code */ 
  }
}

vs.

class TopMod extends Module {
...
  DspContext.blah.withValue(y) {
    val inst = new XMod()
  }
...
}

Double check that add/multiply delays work -- especially for complex multiply + comples.abssq. Check that in both those cases, trim + overflow work too. (More interesting use case since they require both add and multiply -- so lots of context options come into play). Try for different delays and make sure that DspContext.complexMulDly changes when numAddPipes and numMulPipes changes.

Check that Width < BinaryPoint is legal and correct.


When you do ops on FixedPoint numbers, your scala.math operations should mimic the results exactly (bit accurate) based off of the binaryPoint. i.e. FixedTolLSBs should be 0, and expects should pass.

Test bit growth of 1 (especially common) for things like FixedPoint multiply, and make sure the result is bit accurate. You should be able to expect how the trimming works.


Also, purposely come up with a case where having tolerance = 0 fails but tolerance of say 1-2 LSBs works to test out that Tester tolerances work.

For the sin, cos, tan approximations in Verilator, I tested with expect tolerance of 1e-8, and for most reasonable inputs, they seemed to work, but I'm not sure if I was 100% comprehensive.

DSPTester peek/poke printing more useful info

I think you shouldn't directly be using TesterOptionsManager and should have a DSPTesterOptionsManager that lets you customize verbosity.

I finally got the standard PeekPokeTester to print out something, but evidently, things are just printed out as BigInt converted to base 10.

My old DSPTester printout allowed for much more thorough debugging:

You could print out base 10/hex bits flavor. It would also directly print out the decimal version of DspReal/FixedPoint peek/pokes... and for fixed point, it would also show # integer bits + # fractional bits used (or it might've been range, I forget) to compute the Double result for fixed point (that helps to double check that width inference, etc. were working correctly).

All of these features help to make the debug process easier.

For example: If I want to test the correctness of implicitly[Real[R]].fromDouble(3.333333)

And I'm not super sure how many Fixed point fractional/integer bits are allocated, I'd like to use the tester to debug...

I'm also not loving the fact that expect prints twice (the first line is ugly and non-informative -- you don't even know which signal it's referring to):

expect got 2.00000000 expect 2.00000000
EXPECT AT 15 add 1.0 + 1.0 => 2.0 should have been 2.0 PASS

Expect should look more like the peek/poke strings, and if you supply a string, it should only print something like the 2nd line, but with a signal name [without you having to manually pass in result and expected vals].

Little details like this speed up the design/debug process considerably...


Edit: Ok, DspTester needs its own verbosity, so you can turn off _verbose for PeekPokeTester and override all the prints for Dsp specific things with something that's more useful...

Hard "real" functions punched through the tester?

Would this be a possibility? For stuff like atan, sin, cos, or fixedtodouble... Could you have the inputs/outputs at whatever module layer be either punched through to top level or be peek/pokable so that you could take say peek an atan input, process it in scala, and then poke it to the result? That gives the whole golden model with swapping fixed/float at intermediate block levels that would be super cool to have directly in scala...

DspReal usage

Somewhat on the lines of what @stevobailey and @grebe did -- If we're using Verilator or VCS as the main mode of testing with Dsp-y things, it might make sense to have all DspReal nodes be 1 bit ports (since there's no notion of signed/unsigned there). The nodes should then be (via annotation or otherwise w/ the IfDef stuff) typed as "real" or not for simulation vs. synthesis.

I don't think it's correct to do this on an AnalogType, because, really, AnalogType is more talking about directionality rather than how to represent the data.

Opinions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.