Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dsptools examples #457

Merged
merged 27 commits into from
Apr 20, 2020
Merged

Dsptools examples #457

merged 27 commits into from
Apr 20, 2020

Conversation

ryan-lund
Copy link
Contributor

Adds two examples of accelerators created using dsptools that can be attached to a Rocket Core as MMIOs. The blocks are:

  1. Passthrough (sanity check)
  2. Generic FIR Filter

@alonamid alonamid requested review from grebe and alonamid March 7, 2020 01:10
case PassthroughKey => Some(PassthroughParams(depth = 8))
})

class WithUIntTestFIR extends Config((site, here, up) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example should probably use FixedPoint for the FIR filter.

io.in.ready := directCells.head.in.ready

// connect adjacent cells
for ((current, next) <- directCells.zip(directCells.tail)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is doing something a little tricky, and the comment should probably reflect that. directCells.tail is one element shorter than directCells, and zip doesn't look at the last element of directCells. Maybe we should call dropRight? I'm not sure what's least confusing. It definitely works as written, but I think it would be good to make the example easy to understand. What do you think?

PassthroughBlock[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle, T](proto)
with TLDspBlock

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this commented out stuff. I think it actually should work to do this way, but as currently written I think it makes a better example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I in this case remove the initial PassthroughChain implementation?

* @param p
* @tparam T Type parameter for passthrough, i.e. FixedPoint or DspReal
*/
class TLPassthroughThing[T<:Data:Ring](params: PassthroughParams, proto: T)(implicit p: Parameters)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of Thing, let's call it something else. Maybe Chain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as below

genIn, genOut, coeffs
) with TLDspBlock

class TLGenericFIRThing[T<:Data:Ring] (genIn: T, genOut: T, coeffs: Seq[T], params: GenericFIRParams)(implicit p: Parameters)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this something other than Thing, perhaps Chain? MM?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed in latest update (TLGenericFIRChain)

@alonamid
Copy link
Contributor

alonamid commented Mar 9, 2020

Some initial comments:

@grebe
Copy link
Collaborator

grebe commented Mar 10, 2020

Maybe StreamingPassthrough?

@ryan-lund
Copy link
Contributor Author

Maybe StreamingPassthrough?

As of now I've changed Passthrough to this.

Dsptools Blocks
===============

Another way to create a MMIO peripheral is to use the Dsptools library for Chisel. In this method, a chain is created by placing a custom module inside a ``DspBlock`` and sandwiching that block between a ``ReadQueue`` and ``WriteQueue``. Those queues then act as memory mapped interfaces to the Rocket Chip SoCs. This section will again primarily focuso n designing Tilelink-based peripherals. However, through the resources provided in Dsptools, one could also define an AXI4-based peripheral by following similar steps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say "chain", do you mean a streaming interface?

@@ -0,0 +1,105 @@
.. _dsptools-blocks:

Dsptools Blocks
Copy link
Contributor

@alonamid alonamid Mar 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There needs to be some introduction here.
What is the main use-case here? (DSP chains....)
What are we trying to do?
Why does this main use-case need a different flow than the standard MMIO method?


Another way to create a MMIO peripheral is to use the Dsptools library for Chisel. In this method, a chain is created by placing a custom module inside a ``DspBlock`` and sandwiching that block between a ``ReadQueue`` and ``WriteQueue``. Those queues then act as memory mapped interfaces to the Rocket Chip SoCs. This section will again primarily focuso n designing Tilelink-based peripherals. However, through the resources provided in Dsptools, one could also define an AXI4-based peripheral by following similar steps.

For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a documentation page somewhere that talks about how to write an FIR filter using Dsptools?


For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``.

We module ``GenericFIR`` links together a variable number of ``GenericFIRDirectCell`` submodules which work togther to perform the filtering. It is important to note that both modules are type generic, which means that they can be instantiated for any datatype that implements ``Ring`` operations per the specifications on ``T``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify the first sentence here?

@@ -0,0 +1,105 @@
.. _dsptools-blocks:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grebe , I think there should be some introduction to DSP tools. I know there is some in the dsp-tools README, but I don't think it's sufficient.

This page talks about Ring operations which could use some additional introduction

@alonamid
Copy link
Contributor

I would also like to see the documentation page generalized to a general DSP blocks. The FIR walkthrough should still be there, but as an example, rather than a target design. The target audience of this page should be someone writing an arbitrary DSP block (correlator, averaging window, FFT, etc.), and they should be able to understand what is specific to an FIR filter in this example, and what is generally applicable to their DSP block.

def apply[T<:Data:Ring](proto: T): StreamingPassthroughIO[T] = new StreamingPassthroughIO(proto)
}

class StreamingPassthrough[T<:Data:Ring](proto: T) extends Module {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the file name as well to StreamingPassthrough?

@@ -5,7 +5,7 @@ LDFLAGS= -static

include libgloss.mk

PROGRAMS = pwm blkdev accum charcount nic-loopback big-blkdev pingd
PROGRAMS = pwm blkdev accum charcount nic-loopback big-blkdev pingd passthrough fir
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the "passthrough" name here as well?

Dsptools Blocks
===============

Another way to create a MMIO peripheral is to use the Dsptools library for Chisel. In this method, a memory interface is created by creating a "chain". This chain consists of a custom module placed inside a ``DspBlock``, which is then sandwiched between a ``ReadQueue`` and ``WriteQueue``. Those queues then act as memory mapped interfaces to the Rocket Chip SoCs. This section will again primarily focus on designing Tilelink-based peripherals. However, through the resources provided in Dsptools, one could also define an AXI4-based peripheral by following similar steps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify the difference between adding an MMIO peripheral using this method vs. the "usual" method. In other words: is this a "special case" of the general method, or is this an alternative?


Another way to create a MMIO peripheral is to use the Dsptools library for Chisel. In this method, a memory interface is created by creating a "chain". This chain consists of a custom module placed inside a ``DspBlock``, which is then sandwiched between a ``ReadQueue`` and ``WriteQueue``. Those queues then act as memory mapped interfaces to the Rocket Chip SoCs. This section will again primarily focus on designing Tilelink-based peripherals. However, through the resources provided in Dsptools, one could also define an AXI4-based peripheral by following similar steps.

For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``. That being said, one could substitute any module with a ready valid interface in the place of the FIR and achieve the same results. As long as the read and valid signals of the module are attached to those of a corresponding ``DSPBlock`` wrapper, and that wrapper is placed in a chain with a ``ReadQueue`` and a ``WriteQueue``, following the general outline establised by these steps will allow you to interact with that block as a memory mapped IO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``. That being said, one could substitute any module with a ready valid interface in the place of the FIR and achieve the same results. As long as the read and valid signals of the module are attached to those of a corresponding ``DSPBlock`` wrapper, and that wrapper is placed in a chain with a ``ReadQueue`` and a ``WriteQueue``, following the general outline establised by these steps will allow you to interact with that block as a memory mapped IO
For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``. That being said, one could substitute any module with a ready valid interface in the place of the FIR and achieve the same results. As long as the ready and valid signals of the module are attached to those of a corresponding ``DSPBlock`` wrapper, and that wrapper is placed in a chain with a ``ReadQueue`` and a ``WriteQueue``, following the general outline established by these steps will allow you to interact with that block as a memory mapped IO

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what would be other good examples of things other than FIR to implement using this method?


For this example, we will show you how to connect a simple FIR filter created using Dsptools as an MMIO peripheral. The full code can be found in ``generators/example/src/main/scala/dsptools/GenericFIR.scala``. That being said, one could substitute any module with a ready valid interface in the place of the FIR and achieve the same results. As long as the read and valid signals of the module are attached to those of a corresponding ``DSPBlock`` wrapper, and that wrapper is placed in a chain with a ``ReadQueue`` and a ``WriteQueue``, following the general outline establised by these steps will allow you to interact with that block as a memory mapped IO

The module ``GenericFIR`` is the overall wrapper of our FIR module. This module links together a variable number of ``GenericFIRDirectCell`` submodules, each of which performs the computations for one coefficient in a FIR direct form architecture. It is important to note that both modules are type generic, which means that they can be instantiated for any datatype that implements ``Ring`` operations per the specifications on ``T``.
Copy link
Contributor

@alonamid alonamid Apr 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a diagram to clarify this? Seems like there are at least 3 different layers of wrappers here...

:start-after: DOC include start: CanHavePeripheryUIntTestFIR chisel
:end-before: DOC include end: CanHavePeripheryUIntTestFIR chisel

Note that this is the point at which we decide the datatype for our FIR. It is also possible with some reworking to push the datatype selection out to the top level.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're not going to explain what "reworking" you're talking about, I would just remove that comment

Testing
-------

We can now test that the FIR is working. The test program is found in ``tests/gcd.c``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We can now test that the FIR is working. The test program is found in ``tests/gcd.c``.
We can now test that the FIR is working. The test program is found in ``tests/fir.c``.

@@ -11,7 +11,9 @@ These guides will walk you through customization of your system-on-chip:

- Adding custom MMIO widgets to the Chipyard memory system by Tilelink or AXI4, with custom Top-level IOs

- Standard practices for using keys, traits, and configs to parameterize your design
- Adding custom Dsptools based blocks as MMIO widgets.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider putting this in a different place, since it is in fact a "special case" of the previous section


class UIntStreamingPassthroughRocketConfig extends Config(
new chipyard.example.WithUIntStreamingPassthrough ++ // use top with tilelink-controlled passthrough
new RocketConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our current approach is to use explicit expanded configs rather than this inherited one (see every other config in this file)

// DOC include start: FIRRocketConfig
class UIntTestFIRRocketConfig extends Config (
new chipyard.example.WithUIntTestFIR ++ // use top with tilelink-controlled FIR
new RocketConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our current approach is to use explicit expanded configs rather than this inherited one (see every other config in this file)

@alonamid
Copy link
Contributor

A few additional comments:

  • @grebe , at some point, can you PR this into a branch within the chipyard repo (not dev), and then open a new PR to dev so CI will run?
  • For consistency sake, make sure passthrough is replaced with streaming-passthrough everywhere (including file names, C files, documentation, etc.)
  • Maybe talk about the streaming-passthrough example in the documentation as well?
  • From a documentation and organization perspective, is this a "special case" of an MMIO peripheral, or an alternative? We've been describing RoCC and MMIO as a pseudo "dichotomy" for custom blocks, and I think it's worth clarifying where do these dsptools examples fit in this world. I believe you're trying to put an emphasis on streaming chains, but I'm not sure this idea is conveyed well enough. If this is a special case of MMIO, I would prefer to put perhaps put it as a subsection of the general MMIO explanation, or clarify that this is essentially another example of the same method.
  • Add a CI test for dsptools

@ryan-lund ryan-lund changed the base branch from dev to dev-dsptools April 16, 2020 19:39
@grebe grebe merged commit 35cba5d into ucb-bar:dev-dsptools Apr 20, 2020
@alonamid alonamid mentioned this pull request May 30, 2020
@lpppeipei
Copy link

I would also like to see the documentation page generalized to a general DSP blocks. The FIR walkthrough should still be there, but as an example, rather than a target design. The target audience of this page should be someone writing an arbitrary DSP block (correlator, averaging window, FFT, etc.), and they should be able to understand what is specific to an FIR filter in this example, and what is generally applicable to their DSP block.

About " The target audience of this page should be someone writing an arbitrary DSP block (correlator, averaging window, FFT, etc.)", now I would like to write a FFT DSP Block , is there some information for me? Thanks a lot !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants