All Downloads are FREE. Search and download functionalities are using the official Maven repository.

chisel.lib.bitonicsorter.BitonicSorter.scala Maven / Gradle / Ivy

The newest version!
// See README.md for license details.

package chisel.lib.bitonicsorter

import chisel3._
import chisel3.stage.ChiselStage
import chisel3.util._

/**
  * Builds a mux whose that tests its two inputs
  * Construct hardware to swap inputs to outputs or pass them straight through depending on comparison function
  * otherwise
  * @param proto  The type generator for the swapper
  * @param lt     The comparision function
  * @tparam T     The type of the inputs and outputs, derived from proto
  */
class Swapper[T <: Data](proto: T, lt: (T, T) => Bool) extends Module {
  val io = IO(new Bundle {
    val a0 = Input(proto)
    val a1 = Input(proto)
    val z0 = Output(proto)
    val z1 = Output(proto)
  })
  when(lt(io.a1, io.a0)) {
    io.z0 := io.a1
    io.z1 := io.a0
  }.otherwise {
    io.z0 := io.a0
    io.z1 := io.a1
  }
}

/**
  * Bitonic Sorter is a factory for combinational sort hardware.
  * It requires that the elements to be sorted are a power of 2.
  *
  * @see https://en.wikipedia.org/wiki/Bitonic_sorter
  */
object BitonicSorter {
  def apply[T <: Data](a: IndexedSeq[Option[T]], factory: () => Swapper[T]): IndexedSeq[Option[T]] = {
    assert((1 << log2Up(a.length)) == a.length)
    def insertSorter(a: IndexedSeq[Option[T]], lo: Int, hi: Int): IndexedSeq[Option[T]] = {
      (a(lo), a(hi)) match {
        case (_, None)        => a
        case (None, Some(aH)) => a.updated(lo, Some(aH)).updated(hi, None)
        case (Some(aL), Some(aH)) =>
          val m = Module(factory())
          m.io.a0 := aL
          m.io.a1 := aH
          a.updated(lo, Some(m.io.z0)).updated(hi, Some(m.io.z1))
      }
    }
    (for {
      i <- 0 until log2Up(a.length)
      j <- i to 0 by -1
      k0 <- a.indices by (2 << j)
      k1 <- 0 until 1 << j
    } yield {
      val lo = k0 + k1
      val hi = lo + (1 << j)
      if ((lo >> (i + 1)) % 2 == 0) (lo, hi) else (hi, lo)
    }).foldLeft(a) { case (s, (l, h)) => insertSorter(s, l, h) }
  }
}

/**
  * Defines the interface used for the Bitonic Sort module
  * @param n      The number of elements
  * @param proto  An instance of the type of all elements
  * @tparam T     The type as derived from proto
  */
class SorterModuleIfc[T <: Data](val n: Int, proto: T) extends Module {
  val io = IO(new Bundle {
    val a = Input(Vec(n, proto.cloneType))
    val z = Output(Vec(n, proto.cloneType))
  })
}

/*
 * What follows are some example code generation calls.
 */

class BitonicSorterModule[T <: Data](n: Int, proto: T, lt: (T, T) => Bool) extends SorterModuleIfc(n, proto) {
  private val a = IndexedSeq.tabulate(1 << log2Up(io.a.length)) { i => if (i < n) Some(io.a(i)) else None }
  io.z := VecInit(BitonicSorter(a, () => new Swapper(proto.cloneType, lt)).slice(0, n).map(_.get))
}

//scalastyle:off magic.number
object BitonicSorterUInt8_64Driver extends App {
  (new ChiselStage).emitSystemVerilog(new BitonicSorterModule(64, UInt(8.W), (x: UInt, y: UInt) => x < y), args)
}

//scalastyle:off magic.number
object BitonicSorterUInt8_384Driver extends App {
  (new ChiselStage).emitSystemVerilog(new BitonicSorterModule(384, UInt(8.W), (x: UInt, y: UInt) => x < y), args)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy