You're reading an pre-release version of this documentation.
For the latest stable release version, please have a look at master.

Sinus ROM

Let’s imagine that you want to generate a sine wave and also have a filtered version of it (which is completely useless in practice, but let’s do it as an example).

Parameters name

Type

Description

resolutionWidth

Int

Number of bits used to represent numbers

sampleCount

Int

Number of samples in a sine period

IO name

Direction

Type

Description

sin

out

SInt(resolutionWidth bits)

Output which plays the sine wave

sinFiltered

out

SInt(resolutionWidth bits)

Output which plays the filtered version of the sine

So let’s define the Component:

case class SineRom(resolutionWidth: Int, sampleCount: Int) extends Component {
  val io = new Bundle {
    val sin = out SInt(resolutionWidth bits)
    val sinFiltered = out SInt(resolutionWidth bits)
  }
...

To play the sine wave on the sin output, you can define a ROM which contain all samples of a sine period (it could be just a quarter, but let’s do things the most simple way). Then you can read that ROM with an phase counter and this will generate your sine wave.

  // Calculate values for the lookup table
  def sinTable = for(sampleIndex <- 0 until sampleCount) yield {
    val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)
    S((sinValue * ((1<<resolutionWidth)/2-1)).toInt,resolutionWidth bits)
  }

  val rom =  Mem(SInt(resolutionWidth bits),initialContent = sinTable)
  val phase = Reg(UInt(log2Up(sampleCount) bits)) init 0
  phase := phase + 1

  io.sin := rom.readSync(phase)

Then to generate sinFiltered, you can for example use a first order low pass filter implementation:

  io.sinFiltered := RegNext(io.sinFiltered  - (io.sinFiltered  >> 5) + (io.sin >> 5)) init 0

Here is the complete code:

case class SineRom(resolutionWidth: Int, sampleCount: Int) extends Component {
  val io = new Bundle {
    val sin = out SInt(resolutionWidth bits)
    val sinFiltered = out SInt(resolutionWidth bits)
  }

  // Calculate values for the lookup table
  def sinTable = for(sampleIndex <- 0 until sampleCount) yield {
    val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)
    S((sinValue * ((1<<resolutionWidth)/2-1)).toInt,resolutionWidth bits)
  }

  val rom =  Mem(SInt(resolutionWidth bits),initialContent = sinTable)
  val phase = Reg(UInt(log2Up(sampleCount) bits)) init 0
  phase := phase + 1

  io.sin := rom.readSync(phase)

  io.sinFiltered := RegNext(io.sinFiltered  - (io.sinFiltered  >> 5) + (io.sin >> 5)) init 0
}