Introduction

This example will show a simple implementation (without optimization) of a Mandelbrot fractal calculator by using data streams and fixed point calculations.

Specification

The component will receive one Stream of pixel tasks (which contain the XY coordinates in the Mandelbrot space) and will produce one Stream of pixel results (which contain the number of iterations done for the corresponding task).

Let’s specify the IO of our component:

IO Name Direction Type Description
cmd slave Stream[PixelTask] Provide XY coordinates to process
rsp master Stream[PixelResult] Return iteration count needed for the corresponding cmd transaction

Let’s specify the PixelTask Bundle:

Element Name Type Description
x SFix Coordinate in the Mandelbrot space
y SFix Coordinate in the Mandelbrot space

Let’s specify the PixelResult Bundle:

Element Name Type Description
iteration UInt Number of iterations required to solve the Mandelbrot coordinates

Elaboration parameters (Generics)

Let’s define the class that will provide construction parameters of our system:

case class PixelSolverGenerics(fixAmplitude : Int,
                               fixResolution : Int,
                               iterationLimit : Int){
  val iterationWidth = log2Up(iterationLimit+1)
  def iterationType = UInt(iterationWidth bits)
  def fixType = SFix(
    peak = fixAmplitude exp,
    resolution = fixResolution exp
  )
}

Bundle definition

case class PixelTask(g : PixelSolverGenerics) extends Bundle{
  val x,y = g.fixType
}

case class PixelResult(g : PixelSolverGenerics) extends Bundle{
  val iteration = g.iterationType
}

Component implementation

And now the implementation. The one below is a very simple one without pipelining / multi-threading.

case class PixelSolver(g : PixelSolverGenerics) extends Component{
  val io = new Bundle{
    val cmd = slave  Stream(PixelTask(g))
    val rsp = master Stream(PixelResult(g))
  }

  import g._

  //Define states
  val x,y       = Reg(fixType) init(0)
  val iteration = Reg(iterationType) init(0)

  //Do some shared calculation
  val xx = x*x
  val yy = y*y
  val xy = x*y

  //Apply default assignement
  io.cmd.ready := False
  io.rsp.valid := False
  io.rsp.iteration := iteration

  when(io.cmd.valid) {
    //Is the mandelbrot iteration done ?
    when(xx + yy >= 4.0 || iteration === iterationLimit) {
      io.rsp.valid := True
      when(io.rsp.ready){
        io.cmd.ready := True
        x := 0
        y := 0
        iteration := 0
      }
    } otherwise {
      x := (xx - yy + io.cmd.x).truncated
      y := (((xy) << 1) + io.cmd.y).truncated
      iteration := iteration + 1
    }
  }
}
Tags: