generalize NastiReadDataArbiter
This commit is contained in:
		@@ -311,48 +311,6 @@ class NastiArbiter(val arbN: Int)(implicit p: Parameters) extends NastiModule {
 | 
			
		||||
  } else { io.slave <> io.master.head }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Locking RR arbiter for Nasti read data channel
 | 
			
		||||
 *  Arbiter locks until last message in channel is sent */
 | 
			
		||||
class NastiReadDataArbiter(arbN: Int)(implicit p: Parameters) extends NastiModule {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val in = Vec(Decoupled(new NastiReadDataChannel), arbN).flip
 | 
			
		||||
    val out = Decoupled(new NastiReadDataChannel)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def rotateLeft[T <: Data](norm: Vec[T], rot: UInt): Vec[T] = {
 | 
			
		||||
    val n = norm.size
 | 
			
		||||
    Vec.tabulate(n) { i =>
 | 
			
		||||
      Mux(rot < UInt(n - i), norm(UInt(i) + rot), norm(rot - UInt(n - i)))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val lockIdx = Reg(init = UInt(0, log2Up(arbN)))
 | 
			
		||||
  val locked = Reg(init = Bool(false))
 | 
			
		||||
 | 
			
		||||
  // use rotation to give priority to the input after the last one granted
 | 
			
		||||
  val choice = PriorityMux(
 | 
			
		||||
    rotateLeft(Vec(io.in.map(_.valid)), lockIdx + UInt(1)),
 | 
			
		||||
    rotateLeft(Vec((0 until arbN).map(UInt(_))), lockIdx + UInt(1)))
 | 
			
		||||
 | 
			
		||||
  val chosen = Mux(locked, lockIdx, choice)
 | 
			
		||||
 | 
			
		||||
  for (i <- 0 until arbN) {
 | 
			
		||||
    io.in(i).ready := io.out.ready && chosen === UInt(i)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.out.valid := io.in(chosen).valid
 | 
			
		||||
  io.out.bits := io.in(chosen).bits
 | 
			
		||||
 | 
			
		||||
  when (io.out.fire()) {
 | 
			
		||||
    when (!locked) {
 | 
			
		||||
      lockIdx := choice
 | 
			
		||||
      locked := !io.out.bits.last
 | 
			
		||||
    } .elsewhen (io.out.bits.last) {
 | 
			
		||||
      locked := Bool(false)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** A slave that send decode error for every request it receives */
 | 
			
		||||
class NastiErrorSlave(implicit p: Parameters) extends NastiModule {
 | 
			
		||||
  val io = (new NastiIO).flip
 | 
			
		||||
@@ -466,7 +424,10 @@ class NastiRouter(addrmap: Seq[(BigInt, BigInt)])(implicit p: Parameters) extend
 | 
			
		||||
  io.master.w.ready := w_ready || err_slave.io.w.ready
 | 
			
		||||
 | 
			
		||||
  val b_arb = Module(new RRArbiter(new NastiWriteResponseChannel, nSlaves + 1))
 | 
			
		||||
  val r_arb = Module(new NastiReadDataArbiter(nSlaves + 1))
 | 
			
		||||
  val r_arb = Module(new JunctionsPeekingArbiter(
 | 
			
		||||
    new NastiReadDataChannel, nSlaves + 1,
 | 
			
		||||
    // we can unlock if it's the last beat
 | 
			
		||||
    (r: NastiReadDataChannel) => r.last))
 | 
			
		||||
 | 
			
		||||
  for (i <- 0 until nSlaves) {
 | 
			
		||||
    b_arb.io.in(i) <> io.slave(i).b
 | 
			
		||||
 
 | 
			
		||||
@@ -58,3 +58,87 @@ object HellaQueue {
 | 
			
		||||
    q.io.deq
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** A generalized locking RR arbiter that addresses the limitations of the
 | 
			
		||||
 *  version in the Chisel standard library */
 | 
			
		||||
abstract class JunctionsAbstractLockingArbiter[T <: Data](typ: T, arbN: Int)
 | 
			
		||||
    extends Module {
 | 
			
		||||
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val in = Vec(Decoupled(typ.cloneType), arbN).flip
 | 
			
		||||
    val out = Decoupled(typ.cloneType)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def rotateLeft[T <: Data](norm: Vec[T], rot: UInt): Vec[T] = {
 | 
			
		||||
    val n = norm.size
 | 
			
		||||
    Vec.tabulate(n) { i =>
 | 
			
		||||
      Mux(rot < UInt(n - i), norm(UInt(i) + rot), norm(rot - UInt(n - i)))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val lockIdx = Reg(init = UInt(0, log2Up(arbN)))
 | 
			
		||||
  val locked = Reg(init = Bool(false))
 | 
			
		||||
 | 
			
		||||
  val choice = PriorityMux(
 | 
			
		||||
    rotateLeft(Vec(io.in.map(_.valid)), lockIdx + UInt(1)),
 | 
			
		||||
    rotateLeft(Vec((0 until arbN).map(UInt(_))), lockIdx + UInt(1)))
 | 
			
		||||
 | 
			
		||||
  val chosen = Mux(locked, lockIdx, choice)
 | 
			
		||||
 | 
			
		||||
  for (i <- 0 until arbN) {
 | 
			
		||||
    io.in(i).ready := io.out.ready && chosen === UInt(i)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  io.out.valid := io.in(chosen).valid
 | 
			
		||||
  io.out.bits := io.in(chosen).bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** This locking arbiter determines when it is safe to unlock
 | 
			
		||||
 *  by peeking at the data */
 | 
			
		||||
class JunctionsPeekingArbiter[T <: Data](
 | 
			
		||||
    typ: T, arbN: Int,
 | 
			
		||||
    canUnlock: T => Bool,
 | 
			
		||||
    needsLock: Option[T => Bool] = None)
 | 
			
		||||
    extends JunctionsAbstractLockingArbiter(typ, arbN) {
 | 
			
		||||
 | 
			
		||||
  def realNeedsLock(data: T): Bool =
 | 
			
		||||
    needsLock.map(_(data)).getOrElse(Bool(true))
 | 
			
		||||
 | 
			
		||||
  when (io.out.fire()) {
 | 
			
		||||
    when (!locked && realNeedsLock(io.out.bits)) {
 | 
			
		||||
      lockIdx := choice
 | 
			
		||||
      locked := Bool(true)
 | 
			
		||||
    }
 | 
			
		||||
    // the unlock statement takes precedent
 | 
			
		||||
    when (canUnlock(io.out.bits)) {
 | 
			
		||||
      locked := Bool(false)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** This arbiter determines when it is safe to unlock by counting transactions */
 | 
			
		||||
class JunctionsCountingArbiter[T <: Data](
 | 
			
		||||
    typ: T, arbN: Int, count: Int,
 | 
			
		||||
    val needsLock: Option[T => Bool] = None)
 | 
			
		||||
    extends JunctionsAbstractLockingArbiter(typ, arbN) {
 | 
			
		||||
 | 
			
		||||
  def realNeedsLock(data: T): Bool =
 | 
			
		||||
    needsLock.map(_(data)).getOrElse(Bool(true))
 | 
			
		||||
 | 
			
		||||
  // if count is 1, you should use a non-locking arbiter
 | 
			
		||||
  require(count > 1, "CountingArbiter cannot have count <= 1")
 | 
			
		||||
 | 
			
		||||
  val lock_ctr = Counter(count)
 | 
			
		||||
 | 
			
		||||
  when (io.out.fire()) {
 | 
			
		||||
    when (!locked && realNeedsLock(io.out.bits)) {
 | 
			
		||||
      lockIdx := choice
 | 
			
		||||
      locked := Bool(true)
 | 
			
		||||
      lock_ctr.inc()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    when (locked) {
 | 
			
		||||
      when (lock_ctr.inc()) { locked := Bool(false) }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user