2014-12-07 12:02:20 +01:00
|
|
|
// See LICENSE for license details.
|
|
|
|
|
|
|
|
package uncore
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import scala.math._
|
|
|
|
|
2015-04-04 02:24:44 +02:00
|
|
|
class Unsigned(x: Int) {
|
|
|
|
require(x >= 0)
|
|
|
|
def clog2: Int = { require(x > 0); ceil(log(x)/log(2)).toInt }
|
|
|
|
def log2: Int = { require(x > 0); floor(log(x)/log(2)).toInt }
|
|
|
|
def isPow2: Boolean = x > 0 && (x & (x-1)) == 0
|
|
|
|
def nextPow2: Int = if (x == 0) 1 else 1 << clog2
|
|
|
|
}
|
|
|
|
|
2014-12-07 12:02:20 +01:00
|
|
|
object MuxBundle {
|
|
|
|
def apply[T <: Data] (default: T, mapping: Seq[(Bool, T)]): T = {
|
|
|
|
mapping.reverse.foldLeft(default)((b, a) => Mux(a._1, a._2, b))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Produces 0-width value when counting to 1
|
|
|
|
class ZCounter(val n: Int) {
|
|
|
|
val value = Reg(init=UInt(0, log2Ceil(n)))
|
|
|
|
def inc(): Bool = {
|
|
|
|
if (n == 1) Bool(true)
|
|
|
|
else {
|
|
|
|
val wrap = value === UInt(n-1)
|
|
|
|
value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1))
|
|
|
|
wrap
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object ZCounter {
|
|
|
|
def apply(n: Int) = new ZCounter(n)
|
|
|
|
def apply(cond: Bool, n: Int): (UInt, Bool) = {
|
|
|
|
val c = new ZCounter(n)
|
|
|
|
var wrap: Bool = null
|
|
|
|
when (cond) { wrap = c.inc() }
|
|
|
|
(c.value, cond && wrap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-06 06:41:46 +02:00
|
|
|
class FlowThroughSerializer[T <: Bundle with HasTileLinkData](gen: T, n: Int) extends Module {
|
2014-12-07 12:02:20 +01:00
|
|
|
val io = new Bundle {
|
2015-07-16 03:06:27 +02:00
|
|
|
val in = Decoupled(gen).flip
|
|
|
|
val out = Decoupled(gen)
|
2014-12-07 12:02:20 +01:00
|
|
|
val cnt = UInt(OUTPUT, log2Up(n))
|
|
|
|
val done = Bool(OUTPUT)
|
|
|
|
}
|
2015-03-24 10:06:53 +01:00
|
|
|
val narrowWidth = io.in.bits.data.getWidth / n
|
|
|
|
require(io.in.bits.data.getWidth % narrowWidth == 0)
|
2014-12-07 12:02:20 +01:00
|
|
|
|
|
|
|
if(n == 1) {
|
2015-08-02 06:09:00 +02:00
|
|
|
io.out <> io.in
|
2015-07-31 08:45:48 +02:00
|
|
|
io.cnt := UInt(0)
|
2014-12-07 12:02:20 +01:00
|
|
|
io.done := Bool(true)
|
|
|
|
} else {
|
|
|
|
val cnt = Reg(init=UInt(0, width = log2Up(n)))
|
|
|
|
val wrap = cnt === UInt(n-1)
|
2015-07-16 03:06:27 +02:00
|
|
|
val rbits = Reg{io.in.bits}
|
2014-12-07 12:02:20 +01:00
|
|
|
val active = Reg(init=Bool(false))
|
|
|
|
|
2015-08-27 18:47:02 +02:00
|
|
|
val shifter = Vec(Bits(width = narrowWidth), n)
|
2014-12-07 12:02:20 +01:00
|
|
|
(0 until n).foreach {
|
2015-03-24 10:06:53 +01:00
|
|
|
i => shifter(i) := rbits.data((i+1)*narrowWidth-1,i*narrowWidth)
|
2014-12-07 12:02:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
io.done := Bool(false)
|
|
|
|
io.cnt := cnt
|
|
|
|
io.in.ready := !active
|
|
|
|
io.out.valid := active || io.in.valid
|
|
|
|
io.out.bits := io.in.bits
|
|
|
|
when(!active && io.in.valid) {
|
2015-03-24 10:06:53 +01:00
|
|
|
when(io.in.bits.hasData()) {
|
2014-12-07 12:02:20 +01:00
|
|
|
cnt := Mux(io.out.ready, UInt(1), UInt(0))
|
|
|
|
rbits := io.in.bits
|
|
|
|
active := Bool(true)
|
|
|
|
}
|
2015-03-24 10:06:53 +01:00
|
|
|
io.done := !io.in.bits.hasData()
|
2014-12-07 12:02:20 +01:00
|
|
|
}
|
|
|
|
when(active) {
|
|
|
|
io.out.bits := rbits
|
2015-03-24 10:06:53 +01:00
|
|
|
io.out.bits.data := shifter(cnt)
|
2014-12-07 12:02:20 +01:00
|
|
|
when(io.out.ready) {
|
|
|
|
cnt := cnt + UInt(1)
|
|
|
|
when(wrap) {
|
|
|
|
cnt := UInt(0)
|
|
|
|
io.done := Bool(true)
|
|
|
|
active := Bool(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-24 10:06:53 +01:00
|
|
|
|
|
|
|
object FlowThroughSerializer {
|
2015-10-06 06:41:46 +02:00
|
|
|
def apply[T <: Bundle with HasTileLinkData](in: DecoupledIO[T], n: Int): DecoupledIO[T] = {
|
2015-03-24 10:06:53 +01:00
|
|
|
val fs = Module(new FlowThroughSerializer(in.bits, n))
|
|
|
|
fs.io.in.valid := in.valid
|
|
|
|
fs.io.in.bits := in.bits
|
|
|
|
in.ready := fs.io.in.ready
|
|
|
|
fs.io.out
|
|
|
|
}
|
|
|
|
}
|
2015-10-13 18:49:22 +02:00
|
|
|
|
|
|
|
class ReorderQueueWrite[T <: Data](dType: T, tagWidth: Int) extends Bundle {
|
|
|
|
val data = dType.cloneType
|
|
|
|
val tag = UInt(width = tagWidth)
|
|
|
|
|
|
|
|
override def cloneType =
|
|
|
|
new ReorderQueueWrite(dType, tagWidth).asInstanceOf[this.type]
|
|
|
|
}
|
|
|
|
|
|
|
|
class ReorderQueue[T <: Data](dType: T, tagWidth: Int, size: Int)
|
|
|
|
extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val enq = Decoupled(new ReorderQueueWrite(dType, tagWidth)).flip
|
|
|
|
val deq = new Bundle {
|
|
|
|
val valid = Bool(INPUT)
|
|
|
|
val tag = UInt(INPUT, tagWidth)
|
|
|
|
val data = dType.cloneType.asOutput
|
|
|
|
}
|
|
|
|
val full = Bool(OUTPUT)
|
|
|
|
}
|
|
|
|
|
|
|
|
val roq_data = Reg(Vec(dType.cloneType, size))
|
|
|
|
val roq_tags = Reg(Vec(UInt(width = tagWidth), size))
|
|
|
|
val roq_free = Reg(init = Vec.fill(size)(Bool(true)))
|
|
|
|
|
|
|
|
val roq_enq_addr = PriorityEncoder(roq_free)
|
|
|
|
val roq_deq_addr = PriorityEncoder(roq_tags.map(_ === io.deq.tag))
|
|
|
|
|
|
|
|
io.enq.ready := roq_free.reduce(_ || _)
|
|
|
|
io.deq.data := roq_data(roq_deq_addr)
|
|
|
|
|
|
|
|
when (io.enq.valid && io.enq.ready) {
|
|
|
|
roq_data(roq_enq_addr) := io.enq.bits.data
|
|
|
|
roq_tags(roq_enq_addr) := io.enq.bits.tag
|
|
|
|
roq_free(roq_enq_addr) := Bool(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
when (io.deq.valid) {
|
|
|
|
roq_free(roq_deq_addr) := Bool(true)
|
|
|
|
}
|
|
|
|
}
|
2015-10-20 02:25:33 +02:00
|
|
|
|
|
|
|
object DecoupledHelper {
|
|
|
|
def apply(rvs: Bool*) = new DecoupledHelper(rvs)
|
|
|
|
}
|
|
|
|
|
|
|
|
class DecoupledHelper(val rvs: Seq[Bool]) {
|
|
|
|
def fire(exclude: Bool, includes: Bool*) = {
|
|
|
|
(rvs.filter(_ ne exclude) ++ includes).reduce(_ && _)
|
|
|
|
}
|
|
|
|
}
|