@@ -50,8 +50,21 @@ abstract class BaseNode
 | 
				
			|||||||
  protected[diplomacy] def colour:  String
 | 
					  protected[diplomacy] def colour:  String
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait InwardNode[DI, UI, BI <: Data] extends BaseNode
 | 
					case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
 | 
				
			||||||
 | 
					  (inward: InwardNode[DI, UI, BI], outward: OutwardNode[DO, UO, BO])
 | 
				
			||||||
 | 
					  extends Object with InwardNodeHandle[DI, UI, BI] with OutwardNodeHandle[DO, UO, BO]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait InwardNodeHandle[DI, UI, BI <: Data]
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  val inward: InwardNode[DI, UI, BI]
 | 
				
			||||||
 | 
					  def := (h: OutwardNodeHandle[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] =
 | 
				
			||||||
 | 
					    inward.:=(h)(sourceInfo)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI, UI, BI]
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val inward = this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protected[diplomacy] val numPI: Range.Inclusive
 | 
					  protected[diplomacy] val numPI: Range.Inclusive
 | 
				
			||||||
  require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
 | 
					  require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
 | 
				
			||||||
  require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
 | 
					  require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
 | 
				
			||||||
@@ -75,8 +88,15 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode
 | 
				
			|||||||
  protected[diplomacy] def iConnect: Vec[BI]
 | 
					  protected[diplomacy] def iConnect: Vec[BI]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode
 | 
					trait OutwardNodeHandle[DO, UO, BO <: Data]
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  val outward: OutwardNode[DO, UO, BO]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO, UO, BO]
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  val outward = this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protected[diplomacy] val numPO: Range.Inclusive
 | 
					  protected[diplomacy] val numPO: Range.Inclusive
 | 
				
			||||||
  require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
 | 
					  require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
 | 
				
			||||||
  require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
 | 
					  require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
 | 
				
			||||||
@@ -136,8 +156,9 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
 | 
				
			|||||||
  def iConnect = bundleIn
 | 
					  def iConnect = bundleIn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // connects the outward part of a node with the inward part of this node
 | 
					  // connects the outward part of a node with the inward part of this node
 | 
				
			||||||
  def := (y: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
 | 
					  override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
 | 
				
			||||||
    val x = this // x := y
 | 
					    val x = this // x := y
 | 
				
			||||||
 | 
					    val y = h.outward
 | 
				
			||||||
    val info = sourceLine(sourceInfo, " at ", "")
 | 
					    val info = sourceLine(sourceInfo, " at ", "")
 | 
				
			||||||
    require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
 | 
					    require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
 | 
				
			||||||
    val i = x.iPushed
 | 
					    val i = x.iPushed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,47 +7,79 @@ import chisel3.util.{Irrevocable}
 | 
				
			|||||||
import util.{AsyncQueue,AsyncResetRegVec}
 | 
					import util.{AsyncQueue,AsyncResetRegVec}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A very simple flow control state machine, run in the specified clock domain
 | 
					// A very simple flow control state machine, run in the specified clock domain
 | 
				
			||||||
class BusyRegisterCrossing(clock: Clock, reset: Bool)
 | 
					class BusyRegisterCrossing extends Module {
 | 
				
			||||||
    extends Module(_clock = clock, _reset = reset) {
 | 
					 | 
				
			||||||
  val io = new Bundle {
 | 
					  val io = new Bundle {
 | 
				
			||||||
    val progress       = Bool(INPUT)
 | 
					    val bypass                  = Bool(INPUT)
 | 
				
			||||||
    val request_valid  = Bool(INPUT)
 | 
					    val master_request_valid    = Bool(INPUT)
 | 
				
			||||||
    val response_ready = Bool(INPUT)
 | 
					    val master_request_ready    = Bool(OUTPUT)
 | 
				
			||||||
    val busy           = Bool(OUTPUT)
 | 
					    val master_response_valid   = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val master_response_ready   = Bool(INPUT)
 | 
				
			||||||
 | 
					    val crossing_request_valid  = Bool(OUTPUT)
 | 
				
			||||||
 | 
					    val crossing_request_ready  = Bool(INPUT)
 | 
				
			||||||
 | 
					    // ... no crossing_response_ready; we are always ready
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val busy   = RegInit(Bool(false))
 | 
					  val busy   = RegInit(Bool(false))
 | 
				
			||||||
  when (io.progress) {
 | 
					  val bypass = Reg(Bool())
 | 
				
			||||||
    busy := Mux(busy, !io.response_ready, io.request_valid)
 | 
					
 | 
				
			||||||
 | 
					  when (io.crossing_request_ready || Mux(busy, bypass, io.bypass)) {
 | 
				
			||||||
 | 
					    busy := Mux(busy, !io.master_response_ready, io.master_request_valid)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  io.busy := busy
 | 
					
 | 
				
			||||||
 | 
					  when (io.master_request_valid && io.master_request_ready) {
 | 
				
			||||||
 | 
					    bypass := io.bypass
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.crossing_request_valid := io.master_request_valid && !io.bypass && !busy
 | 
				
			||||||
 | 
					  io.master_request_ready   := (io.bypass || io.crossing_request_ready) && !busy
 | 
				
			||||||
 | 
					  io.master_response_valid  := (bypass    || io.crossing_request_ready) &&  busy
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RegisterCrossingAssertion extends Module {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val master_bypass = Bool(INPUT)
 | 
				
			||||||
 | 
					    val slave_reset = Bool(INPUT)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert (io.master_bypass || !io.slave_reset)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegField should support connecting to one of these
 | 
					// RegField should support connecting to one of these
 | 
				
			||||||
class RegisterWriteIO[T <: Data](gen: T) extends Bundle {
 | 
					class RegisterWriteIO[T <: Data](gen: T) extends Bundle {
 | 
				
			||||||
  val request  = Decoupled(gen).flip()
 | 
					  val request  = Decoupled(gen).flip
 | 
				
			||||||
  val response = Irrevocable(Bool()) // ignore .bits
 | 
					  val response = Irrevocable(Bool()) // ignore .bits
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// To turn on/off a domain:
 | 
					// To turn off=>on a domain:
 | 
				
			||||||
//  1. lower allow on the other side
 | 
					//  A. To turn disable the master domain
 | 
				
			||||||
 | 
					//    1. wait for all inflight traffic to resolve
 | 
				
			||||||
 | 
					//    2. assert master reset
 | 
				
			||||||
 | 
					//    3. (optional) stop the master clock
 | 
				
			||||||
 | 
					//    --- YOU MAY NOT TURN OFF POWER ---
 | 
				
			||||||
 | 
					//    4. re-enable the clock
 | 
				
			||||||
 | 
					//    5. deassert reset
 | 
				
			||||||
 | 
					//  B. To turn off the slave domain
 | 
				
			||||||
 | 
					//    1. assert bypass
 | 
				
			||||||
//    2. wait for inflight traffic to resolve
 | 
					//    2. wait for inflight traffic to resolve
 | 
				
			||||||
//  3. assert reset in the domain
 | 
					//    3. assert slave reset
 | 
				
			||||||
//  4. turn off the domain
 | 
					//    4. (optional) stop the slave clock
 | 
				
			||||||
//  5. turn on the domain
 | 
					//    --- YOU MAY NOT TURN OFF POWER ---
 | 
				
			||||||
//  6. deassert reset in the domain
 | 
					//    5. re-enable the clock
 | 
				
			||||||
//  7. raise allow on the other side
 | 
					//    6. deassert reset
 | 
				
			||||||
 | 
					//    7. deassert bypass
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If you need to cut power, use something that support isolation gates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RegisterWriteCrossingIO[T <: Data](gen: T) extends Bundle {
 | 
					class RegisterWriteCrossingIO[T <: Data](gen: T) extends Bundle {
 | 
				
			||||||
  // Master clock domain
 | 
					  // Master clock domain
 | 
				
			||||||
  val master_clock   = Clock(INPUT)
 | 
					  val master_clock   = Clock(INPUT)
 | 
				
			||||||
  val master_reset   = Bool(INPUT)
 | 
					  val master_reset   = Bool(INPUT)
 | 
				
			||||||
  val master_allow   = Bool(INPUT) // actually wait for the slave
 | 
					 | 
				
			||||||
  val master_port    = new RegisterWriteIO(gen)
 | 
					  val master_port    = new RegisterWriteIO(gen)
 | 
				
			||||||
 | 
					  // Bypass requests from the master to be noops
 | 
				
			||||||
 | 
					  val master_bypass  = Bool(INPUT)
 | 
				
			||||||
  // Slave clock domain
 | 
					  // Slave clock domain
 | 
				
			||||||
  val slave_clock    = Clock(INPUT)
 | 
					  val slave_clock    = Clock(INPUT)
 | 
				
			||||||
  val slave_reset    = Bool(INPUT)
 | 
					  val slave_reset    = Bool(INPUT)
 | 
				
			||||||
  val slave_allow    = Bool(INPUT) // honour requests from the master
 | 
					 | 
				
			||||||
  val slave_register = gen.asOutput
 | 
					  val slave_register = gen.asOutput
 | 
				
			||||||
  val slave_valid    = Bool(OUTPUT) // is high on 1st cycle slave_register has a new value
 | 
					  val slave_valid    = Bool(OUTPUT) // is high on 1st cycle slave_register has a new value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -55,37 +87,40 @@ class RegisterWriteCrossingIO[T <: Data](gen: T) extends Bundle {
 | 
				
			|||||||
class RegisterWriteCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
 | 
					class RegisterWriteCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
 | 
				
			||||||
  val io = new RegisterWriteCrossingIO(gen)
 | 
					  val io = new RegisterWriteCrossingIO(gen)
 | 
				
			||||||
  // The crossing must only allow one item inflight at a time
 | 
					  // The crossing must only allow one item inflight at a time
 | 
				
			||||||
 | 
					  val control = Module(new BusyRegisterCrossing)
 | 
				
			||||||
  val crossing = Module(new AsyncQueue(gen, 1, sync))
 | 
					  val crossing = Module(new AsyncQueue(gen, 1, sync))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // We can just randomly reset one-side of a single entry AsyncQueue.
 | 
					  control.clock := io.master_clock
 | 
				
			||||||
  // If the enq side is reset, at worst deq.bits is reassigned from mem(0), which stays fixed.
 | 
					  control.reset := io.master_reset
 | 
				
			||||||
  // If the deq side is reset, at worst the master rewrites mem(0) once, deq.bits stays fixed.
 | 
					 | 
				
			||||||
  crossing.io.enq_clock := io.master_clock
 | 
					  crossing.io.enq_clock := io.master_clock
 | 
				
			||||||
  crossing.io.enq_reset := io.master_reset
 | 
					  crossing.io.enq_reset := io.master_reset
 | 
				
			||||||
  crossing.io.deq_clock := io.slave_clock
 | 
					  crossing.io.deq_clock := io.slave_clock
 | 
				
			||||||
  crossing.io.deq_reset := io.slave_reset
 | 
					  crossing.io.deq_reset := io.slave_reset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  control.io.bypass := io.master_bypass
 | 
				
			||||||
 | 
					  control.io.master_request_valid  := io.master_port.request.valid
 | 
				
			||||||
 | 
					  control.io.master_response_ready := io.master_port.response.ready
 | 
				
			||||||
 | 
					  io.master_port.request.ready  := control.io.master_request_ready
 | 
				
			||||||
 | 
					  io.master_port.response.valid := control.io.master_response_valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  control.io.crossing_request_ready := crossing.io.enq.ready
 | 
				
			||||||
 | 
					  crossing.io.enq.valid := control.io.crossing_request_valid
 | 
				
			||||||
  crossing.io.enq.bits := io.master_port.request.bits
 | 
					  crossing.io.enq.bits := io.master_port.request.bits
 | 
				
			||||||
  io.slave_register := crossing.io.deq.bits
 | 
					 | 
				
			||||||
  io.slave_valid    := crossing.io.deq.valid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // If the slave is not operational, just drop the write.
 | 
					 | 
				
			||||||
  val progress = crossing.io.enq.ready || !io.master_allow
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  val control = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
 | 
					 | 
				
			||||||
  control.io.progress := progress
 | 
					 | 
				
			||||||
  control.io.request_valid  := io.master_port.request.valid
 | 
					 | 
				
			||||||
  control.io.response_ready := io.master_port.response.ready
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  crossing.io.deq.ready := Bool(true)
 | 
					  crossing.io.deq.ready := Bool(true)
 | 
				
			||||||
  crossing.io.enq.valid := io.master_port.request.valid && !control.io.busy
 | 
					  io.slave_valid := crossing.io.deq.valid
 | 
				
			||||||
  io.master_port.request.ready  := progress && !control.io.busy
 | 
					  io.slave_register := crossing.io.deq.bits
 | 
				
			||||||
  io.master_port.response.valid := progress && control.io.busy
 | 
					
 | 
				
			||||||
 | 
					  val assertion = Module(new RegisterCrossingAssertion)
 | 
				
			||||||
 | 
					  assertion.clock := io.master_clock
 | 
				
			||||||
 | 
					  assertion.reset := io.master_reset
 | 
				
			||||||
 | 
					  assertion.io.master_bypass := io.master_bypass
 | 
				
			||||||
 | 
					  assertion.io.slave_reset := io.slave_reset
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegField should support connecting to one of these
 | 
					// RegField should support connecting to one of these
 | 
				
			||||||
class RegisterReadIO[T <: Data](gen: T) extends Bundle {
 | 
					class RegisterReadIO[T <: Data](gen: T) extends Bundle {
 | 
				
			||||||
  val request  = Decoupled(Bool()).flip() // ignore .bits
 | 
					  val request  = Decoupled(Bool()).flip // ignore .bits
 | 
				
			||||||
  val response = Irrevocable(gen)
 | 
					  val response = Irrevocable(gen)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,43 +128,46 @@ class RegisterReadCrossingIO[T <: Data](gen: T) extends Bundle {
 | 
				
			|||||||
  // Master clock domain
 | 
					  // Master clock domain
 | 
				
			||||||
  val master_clock   = Clock(INPUT)
 | 
					  val master_clock   = Clock(INPUT)
 | 
				
			||||||
  val master_reset   = Bool(INPUT)
 | 
					  val master_reset   = Bool(INPUT)
 | 
				
			||||||
  val master_allow   = Bool(INPUT) // actually wait for the slave
 | 
					 | 
				
			||||||
  val master_port    = new RegisterReadIO(gen)
 | 
					  val master_port    = new RegisterReadIO(gen)
 | 
				
			||||||
 | 
					  // Bypass requests from the master to be noops
 | 
				
			||||||
 | 
					  val master_bypass  = Bool(INPUT)
 | 
				
			||||||
  // Slave clock domain
 | 
					  // Slave clock domain
 | 
				
			||||||
  val slave_clock    = Clock(INPUT)
 | 
					  val slave_clock    = Clock(INPUT)
 | 
				
			||||||
  val slave_reset    = Bool(INPUT)
 | 
					  val slave_reset    = Bool(INPUT)
 | 
				
			||||||
  val slave_allow    = Bool(INPUT) // honour requests from the master
 | 
					 | 
				
			||||||
  val slave_register = gen.asInput
 | 
					  val slave_register = gen.asInput
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RegisterReadCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
 | 
					class RegisterReadCrossing[T <: Data](gen: T, sync: Int = 3) extends Module {
 | 
				
			||||||
  val io = new RegisterReadCrossingIO(gen)
 | 
					  val io = new RegisterReadCrossingIO(gen)
 | 
				
			||||||
  // The crossing must only allow one item inflight at a time
 | 
					  // The crossing must only allow one item inflight at a time
 | 
				
			||||||
 | 
					  val control = Module(new BusyRegisterCrossing)
 | 
				
			||||||
  val crossing = Module(new AsyncQueue(gen, 1, sync))
 | 
					  val crossing = Module(new AsyncQueue(gen, 1, sync))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // We can just randomly reset one-side of a single entry AsyncQueue.
 | 
					  control.clock := io.master_clock
 | 
				
			||||||
  // If the enq side is reset, at worst deq.bits is reassigned from mem(0), which stays fixed.
 | 
					  control.reset := io.master_reset
 | 
				
			||||||
  // If the deq side is reset, at worst the slave rewrites mem(0) once, deq.bits stays fixed.
 | 
					 | 
				
			||||||
  crossing.io.enq_clock := io.slave_clock
 | 
					 | 
				
			||||||
  crossing.io.enq_reset := io.slave_reset
 | 
					 | 
				
			||||||
  crossing.io.deq_clock := io.master_clock
 | 
					  crossing.io.deq_clock := io.master_clock
 | 
				
			||||||
  crossing.io.deq_reset := io.master_reset
 | 
					  crossing.io.deq_reset := io.master_reset
 | 
				
			||||||
 | 
					  crossing.io.enq_clock := io.slave_clock
 | 
				
			||||||
 | 
					  crossing.io.enq_reset := io.slave_reset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  crossing.io.enq.bits := io.slave_register
 | 
					  control.io.bypass := io.master_bypass
 | 
				
			||||||
 | 
					  control.io.master_request_valid  := io.master_port.request.valid
 | 
				
			||||||
 | 
					  control.io.master_response_ready := io.master_port.response.ready
 | 
				
			||||||
 | 
					  io.master_port.request.ready  := control.io.master_request_ready
 | 
				
			||||||
 | 
					  io.master_port.response.valid := control.io.master_response_valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  control.io.crossing_request_ready := crossing.io.deq.valid
 | 
				
			||||||
 | 
					  crossing.io.deq.ready := control.io.crossing_request_valid
 | 
				
			||||||
  io.master_port.response.bits := crossing.io.deq.bits
 | 
					  io.master_port.response.bits := crossing.io.deq.bits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // If the slave is not operational, just repeat the last value we saw.
 | 
					 | 
				
			||||||
  val progress = crossing.io.deq.valid || !io.master_allow
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  val control = Module(new BusyRegisterCrossing(io.master_clock, io.master_reset))
 | 
					 | 
				
			||||||
  control.io.progress := progress
 | 
					 | 
				
			||||||
  control.io.request_valid  := io.master_port.request.valid
 | 
					 | 
				
			||||||
  control.io.response_ready := io.master_port.response.ready
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  io.master_port.response.valid := progress && control.io.busy
 | 
					 | 
				
			||||||
  io.master_port.request.ready  := progress && !control.io.busy
 | 
					 | 
				
			||||||
  crossing.io.deq.ready := io.master_port.request.valid && !control.io.busy
 | 
					 | 
				
			||||||
  crossing.io.enq.valid := Bool(true)
 | 
					  crossing.io.enq.valid := Bool(true)
 | 
				
			||||||
 | 
					  crossing.io.enq.bits := io.slave_register
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val assertion = Module(new RegisterCrossingAssertion)
 | 
				
			||||||
 | 
					  assertion.clock := io.master_clock
 | 
				
			||||||
 | 
					  assertion.reset := io.master_reset
 | 
				
			||||||
 | 
					  assertion.io.master_bypass := io.master_bypass
 | 
				
			||||||
 | 
					  assertion.io.slave_reset := io.slave_reset
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Wrapper to create an
 | 
					/** Wrapper to create an
 | 
				
			||||||
@@ -151,8 +189,7 @@ object AsyncRWSlaveRegField {
 | 
				
			|||||||
    width:  Int,
 | 
					    width:  Int,
 | 
				
			||||||
    init: Int,
 | 
					    init: Int,
 | 
				
			||||||
    name: Option[String] = None,
 | 
					    name: Option[String] = None,
 | 
				
			||||||
    master_allow: Bool = Bool(true),
 | 
					    master_bypass: Bool = Bool(true)
 | 
				
			||||||
    slave_allow: Bool = Bool(true)
 | 
					 | 
				
			||||||
  ): (UInt, RegField) = {
 | 
					  ): (UInt, RegField) = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val async_slave_reg = Module(new AsyncResetRegVec(width, init))
 | 
					    val async_slave_reg = Module(new AsyncResetRegVec(width, init))
 | 
				
			||||||
@@ -165,10 +202,9 @@ object AsyncRWSlaveRegField {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    wr_crossing.io.master_clock  := master_clock
 | 
					    wr_crossing.io.master_clock  := master_clock
 | 
				
			||||||
    wr_crossing.io.master_reset  := master_reset
 | 
					    wr_crossing.io.master_reset  := master_reset
 | 
				
			||||||
    wr_crossing.io.master_allow := master_allow
 | 
					    wr_crossing.io.master_bypass := master_bypass
 | 
				
			||||||
    wr_crossing.io.slave_clock   := slave_clock
 | 
					    wr_crossing.io.slave_clock   := slave_clock
 | 
				
			||||||
    wr_crossing.io.slave_reset   := slave_reset
 | 
					    wr_crossing.io.slave_reset   := slave_reset
 | 
				
			||||||
    wr_crossing.io.slave_allow  := slave_allow
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async_slave_reg.io.en := wr_crossing.io.slave_valid
 | 
					    async_slave_reg.io.en := wr_crossing.io.slave_valid
 | 
				
			||||||
    async_slave_reg.io.d  := wr_crossing.io.slave_register
 | 
					    async_slave_reg.io.d  := wr_crossing.io.slave_register
 | 
				
			||||||
@@ -178,10 +214,9 @@ object AsyncRWSlaveRegField {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    rd_crossing.io.master_clock  := master_clock
 | 
					    rd_crossing.io.master_clock  := master_clock
 | 
				
			||||||
    rd_crossing.io.master_reset  := master_reset
 | 
					    rd_crossing.io.master_reset  := master_reset
 | 
				
			||||||
    rd_crossing.io.master_allow := master_allow
 | 
					    rd_crossing.io.master_bypass := master_bypass
 | 
				
			||||||
    rd_crossing.io.slave_clock   := slave_clock
 | 
					    rd_crossing.io.slave_clock   := slave_clock
 | 
				
			||||||
    rd_crossing.io.slave_reset   := slave_reset
 | 
					    rd_crossing.io.slave_reset   := slave_reset
 | 
				
			||||||
    rd_crossing.io.slave_allow  := slave_allow
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rd_crossing.io.slave_register := async_slave_reg.io.q
 | 
					    rd_crossing.io.slave_register := async_slave_reg.io.q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,5 +5,5 @@ import diplomacy._
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package object axi4
 | 
					package object axi4
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  type AXI4OutwardNode = OutwardNode[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
 | 
					  type AXI4OutwardNode = OutwardNodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -226,6 +226,9 @@ final class AsyncBundle[T <: Data](val depth: Int, gen: T) extends Bundle
 | 
				
			|||||||
  val ridx = UInt(width = log2Up(depth)+1).flip
 | 
					  val ridx = UInt(width = log2Up(depth)+1).flip
 | 
				
			||||||
  val widx = UInt(width = log2Up(depth)+1)
 | 
					  val widx = UInt(width = log2Up(depth)+1)
 | 
				
			||||||
  val mem  = Vec(depth, gen)
 | 
					  val mem  = Vec(depth, gen)
 | 
				
			||||||
 | 
					  val source_reset_n = Bool()
 | 
				
			||||||
 | 
					  val sink_reset_n = Bool().flip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type]
 | 
					  override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -236,6 +239,8 @@ object FromAsyncBundle
 | 
				
			|||||||
    x.ridx := sink.io.ridx
 | 
					    x.ridx := sink.io.ridx
 | 
				
			||||||
    sink.io.widx := x.widx
 | 
					    sink.io.widx := x.widx
 | 
				
			||||||
    sink.io.mem  := x.mem
 | 
					    sink.io.mem  := x.mem
 | 
				
			||||||
 | 
					    sink.io.source_reset_n := x.source_reset_n
 | 
				
			||||||
 | 
					    x.sink_reset_n := !sink.reset
 | 
				
			||||||
    val out = Wire(Irrevocable(x.mem(0)))
 | 
					    val out = Wire(Irrevocable(x.mem(0)))
 | 
				
			||||||
    out.valid := sink.io.deq.valid
 | 
					    out.valid := sink.io.deq.valid
 | 
				
			||||||
    out.bits := sink.io.deq.bits
 | 
					    out.bits := sink.io.deq.bits
 | 
				
			||||||
@@ -255,6 +260,8 @@ object ToAsyncBundle
 | 
				
			|||||||
    source.io.ridx := out.ridx
 | 
					    source.io.ridx := out.ridx
 | 
				
			||||||
    out.mem := source.io.mem
 | 
					    out.mem := source.io.mem
 | 
				
			||||||
    out.widx := source.io.widx
 | 
					    out.widx := source.io.widx
 | 
				
			||||||
 | 
					    source.io.sink_reset_n := out.sink_reset_n
 | 
				
			||||||
 | 
					    out.source_reset_n := !source.reset
 | 
				
			||||||
    out
 | 
					    out
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,16 +18,22 @@ class TLAsyncCrossingSource(sync: Int = 3) extends LazyModule
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
 | 
					    ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
 | 
				
			||||||
 | 
					      val sink_reset_n = out.a.sink_reset_n
 | 
				
			||||||
      val bce = edgeIn.manager.anySupportAcquire && edgeIn.client.anySupportProbe
 | 
					      val bce = edgeIn.manager.anySupportAcquire && edgeIn.client.anySupportProbe
 | 
				
			||||||
      val depth = edgeOut.manager.depth
 | 
					      val depth = edgeOut.manager.depth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      out.a <> ToAsyncBundle(in.a, depth, sync)
 | 
					      out.a <> ToAsyncBundle(in.a, depth, sync)
 | 
				
			||||||
      in.d <> FromAsyncBundle(out.d, sync)
 | 
					      in.d <> FromAsyncBundle(out.d, sync)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      assert (!in.a.valid || sink_reset_n, "A channel request sent to a missing manager")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (bce) {
 | 
					      if (bce) {
 | 
				
			||||||
        in.b <> FromAsyncBundle(out.b, sync)
 | 
					        in.b <> FromAsyncBundle(out.b, sync)
 | 
				
			||||||
        out.c <> ToAsyncBundle(in.c, depth, sync)
 | 
					        out.c <> ToAsyncBundle(in.c, depth, sync)
 | 
				
			||||||
        out.e <> ToAsyncBundle(in.e, depth, sync)
 | 
					        out.e <> ToAsyncBundle(in.e, depth, sync)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert (!in.c.valid || sink_reset_n, "C channel response sent to a missing manager")
 | 
				
			||||||
 | 
					        assert (!in.e.valid || sink_reset_n, "E channel response sent to a missing manager")
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        in.b.valid := Bool(false)
 | 
					        in.b.valid := Bool(false)
 | 
				
			||||||
        in.c.ready := Bool(true)
 | 
					        in.c.ready := Bool(true)
 | 
				
			||||||
@@ -51,15 +57,20 @@ class TLAsyncCrossingSink(depth: Int = 8, sync: Int = 3) extends LazyModule
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
 | 
					    ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
 | 
				
			||||||
 | 
					      val source_reset_n = in.a.source_reset_n
 | 
				
			||||||
      val bce = edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe
 | 
					      val bce = edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      out.a <> FromAsyncBundle(in.a, sync)
 | 
					      out.a <> FromAsyncBundle(in.a, sync)
 | 
				
			||||||
      in.d <> ToAsyncBundle(out.d, depth, sync)
 | 
					      in.d <> ToAsyncBundle(out.d, depth, sync)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      assert (!out.d.valid || source_reset_n, "D channel respose sent to missing client")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (bce) {
 | 
					      if (bce) {
 | 
				
			||||||
        in.b <> ToAsyncBundle(out.b, depth, sync)
 | 
					        in.b <> ToAsyncBundle(out.b, depth, sync)
 | 
				
			||||||
        out.c <> FromAsyncBundle(in.c, sync)
 | 
					        out.c <> FromAsyncBundle(in.c, sync)
 | 
				
			||||||
        out.e <> FromAsyncBundle(in.e, sync)
 | 
					        out.e <> FromAsyncBundle(in.e, sync)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert (!out.b.valid || source_reset_n, "B channel request sent to missing client")
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        in.b.widx := UInt(0)
 | 
					        in.b.widx := UInt(0)
 | 
				
			||||||
        in.c.ridx := UInt(0)
 | 
					        in.c.ridx := UInt(0)
 | 
				
			||||||
@@ -96,6 +107,7 @@ class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  val nodeIn = TLInputNode()
 | 
					  val nodeIn = TLInputNode()
 | 
				
			||||||
  val nodeOut = TLOutputNode()
 | 
					  val nodeOut = TLOutputNode()
 | 
				
			||||||
 | 
					  val node = NodeHandle(nodeIn, nodeOut)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val source = LazyModule(new TLAsyncCrossingSource(sync))
 | 
					  val source = LazyModule(new TLAsyncCrossingSource(sync))
 | 
				
			||||||
  val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
 | 
					  val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
 | 
				
			||||||
@@ -140,8 +152,8 @@ class TLRAMCrossing extends LazyModule {
 | 
				
			|||||||
  val cross = LazyModule(new TLAsyncCrossing)
 | 
					  val cross = LazyModule(new TLAsyncCrossing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  model.node := fuzz.node
 | 
					  model.node := fuzz.node
 | 
				
			||||||
  cross.nodeIn := TLFragmenter(4, 256)(model.node)
 | 
					  cross.node := TLFragmenter(4, 256)(model.node)
 | 
				
			||||||
  val monitor = (ram.node := cross.nodeOut)
 | 
					  val monitor = (ram.node := cross.node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
 | 
					  lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
 | 
				
			||||||
    io.finished := fuzz.module.io.finished
 | 
					    io.finished := fuzz.module.io.finished
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ package uncore.tilelink2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Chisel._
 | 
					import Chisel._
 | 
				
			||||||
import chisel3.internal.sourceinfo.SourceInfo
 | 
					import chisel3.internal.sourceinfo.SourceInfo
 | 
				
			||||||
 | 
					import chisel3.util.IrrevocableIO
 | 
				
			||||||
import diplomacy._
 | 
					import diplomacy._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TLEdge(
 | 
					class TLEdge(
 | 
				
			||||||
@@ -218,6 +219,20 @@ class TLEdge(
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def firstlast(bits: TLChannel, fire: Bool): (Bool, Bool, UInt) = {
 | 
				
			||||||
 | 
					    val beats1   = numBeats1(bits)
 | 
				
			||||||
 | 
					    val counter  = RegInit(UInt(0, width = log2Up(maxTransfer / manager.beatBytes)))
 | 
				
			||||||
 | 
					    val counter1 = counter - UInt(1)
 | 
				
			||||||
 | 
					    val first = counter === UInt(0)
 | 
				
			||||||
 | 
					    val last  = counter === UInt(1) || beats1 === UInt(0)
 | 
				
			||||||
 | 
					    when (fire) {
 | 
				
			||||||
 | 
					      counter := Mux(first, beats1, counter1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    (first, last, beats1 & ~counter1)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def firstlast(x: IrrevocableIO[TLChannel]): (Bool, Bool, UInt) = firstlast(x.bits, x.fire())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TLEdgeOut(
 | 
					class TLEdgeOut(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,19 +113,11 @@ class TLFuzzer(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Progress within each operation
 | 
					    // Progress within each operation
 | 
				
			||||||
    val a = out.a.bits
 | 
					    val a = out.a.bits
 | 
				
			||||||
    val a_beats1 = edge.numBeats1(a)
 | 
					    val (a_first, a_last, _) = edge.firstlast(out.a)
 | 
				
			||||||
    val a_counter = RegInit(UInt(0, width = maxLgBeats))
 | 
					 | 
				
			||||||
    val a_counter1 = a_counter - UInt(1)
 | 
					 | 
				
			||||||
    val a_first = a_counter === UInt(0)
 | 
					 | 
				
			||||||
    val a_last  = a_counter === UInt(1) || a_beats1 === UInt(0)
 | 
					 | 
				
			||||||
    val req_done = out.a.fire() && a_last
 | 
					    val req_done = out.a.fire() && a_last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val d = out.d.bits
 | 
					    val d = out.d.bits
 | 
				
			||||||
    val d_beats1 = edge.numBeats1(d)
 | 
					    val (d_first, d_last, _) = edge.firstlast(out.d)
 | 
				
			||||||
    val d_counter = RegInit(UInt(0, width = maxLgBeats))
 | 
					 | 
				
			||||||
    val d_counter1 = d_counter - UInt(1)
 | 
					 | 
				
			||||||
    val d_first = d_counter === UInt(0)
 | 
					 | 
				
			||||||
    val d_last  = d_counter === UInt(1) || d_beats1 === UInt(0)
 | 
					 | 
				
			||||||
    val resp_done = out.d.fire() && d_last
 | 
					    val resp_done = out.d.fire() && d_last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Source ID generation
 | 
					    // Source ID generation
 | 
				
			||||||
@@ -199,14 +191,12 @@ class TLFuzzer(
 | 
				
			|||||||
    inc := !legal || req_done
 | 
					    inc := !legal || req_done
 | 
				
			||||||
    inc_beat := !legal || out.a.fire()
 | 
					    inc_beat := !legal || out.a.fire()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    when (out.a.fire()) {
 | 
					    when (out.a.fire() && a_last) {
 | 
				
			||||||
      a_counter := Mux(a_first, a_beats1, a_counter1)
 | 
					      num_reqs := num_reqs - UInt(1)
 | 
				
			||||||
      when(a_last) { num_reqs := num_reqs - UInt(1) }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    when (out.d.fire()) {
 | 
					    when (out.d.fire() && d_last) {
 | 
				
			||||||
      d_counter := Mux(d_first, d_beats1, d_counter1)
 | 
					      num_resps := num_resps - UInt(1)
 | 
				
			||||||
      when(d_last) { num_resps := num_resps - UInt(1) }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -229,8 +219,8 @@ class TLFuzzRAM extends LazyModule
 | 
				
			|||||||
  xbar2.node := TLAtomicAutomata()(model.node)
 | 
					  xbar2.node := TLAtomicAutomata()(model.node)
 | 
				
			||||||
  ram2.node := TLFragmenter(16, 256)(xbar2.node)
 | 
					  ram2.node := TLFragmenter(16, 256)(xbar2.node)
 | 
				
			||||||
  xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
 | 
					  xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
 | 
				
			||||||
  cross.nodeIn := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
 | 
					  cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
 | 
				
			||||||
  val monitor = (ram.node := cross.nodeOut)
 | 
					  val monitor = (ram.node := cross.node)
 | 
				
			||||||
  gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
 | 
					  gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
 | 
					  lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,38 +33,20 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
 | 
				
			|||||||
    val smartClients = edgeIn.client.clients.map(_.supportsHint.max == edgeIn.client.maxTransfer).reduce(_&&_)
 | 
					    val smartClients = edgeIn.client.clients.map(_.supportsHint.max == edgeIn.client.maxTransfer).reduce(_&&_)
 | 
				
			||||||
    val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
 | 
					    val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (supportManagers && !smartManagers) {
 | 
					    if (supportManagers && !(passthrough && smartManagers)) {
 | 
				
			||||||
      // State of the Hint bypass
 | 
					 | 
				
			||||||
      val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
 | 
					 | 
				
			||||||
      val hintHoldsD = RegInit(Bool(false))
 | 
					 | 
				
			||||||
      val outerHoldsD = counter =/= UInt(0)
 | 
					 | 
				
			||||||
      // Only one of them can hold it
 | 
					 | 
				
			||||||
      assert (!hintHoldsD || !outerHoldsD)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Count outer D beats
 | 
					 | 
				
			||||||
      val beats1 = edgeOut.numBeats1(out.d.bits)
 | 
					 | 
				
			||||||
      when (out.d.fire()) { counter := Mux(outerHoldsD, counter - UInt(1), beats1) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Who wants what?
 | 
					 | 
				
			||||||
      val address = edgeIn.address(in.a.bits)
 | 
					      val address = edgeIn.address(in.a.bits)
 | 
				
			||||||
      val handleA = if (passthrough) !edgeOut.manager.supportsHintFast(address, edgeIn.size(in.a.bits)) else Bool(true)
 | 
					      val handleA = if (passthrough) !edgeOut.manager.supportsHintFast(address, edgeIn.size(in.a.bits)) else Bool(true)
 | 
				
			||||||
      val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint
 | 
					      val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint
 | 
				
			||||||
      val hintWantsD = in.a.valid && hintBitsAtA
 | 
					      val hint = Wire(out.d)
 | 
				
			||||||
      val outerWantsD = out.d.valid
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Prioritize existing D traffic over HintAck (and finish multibeat xfers)
 | 
					      hint.valid  := in.a.valid &&  hintBitsAtA
 | 
				
			||||||
      val hintWinsD = hintHoldsD || (!outerHoldsD && !outerWantsD)
 | 
					 | 
				
			||||||
      hintHoldsD := hintWantsD && hintWinsD && !in.d.ready
 | 
					 | 
				
			||||||
      // Hint can only hold D b/c it still wants it from last cycle
 | 
					 | 
				
			||||||
      assert (!hintHoldsD || hintWantsD)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      in.d.valid  := Mux(hintWinsD, hintWantsD, outerWantsD)
 | 
					 | 
				
			||||||
      in.d.bits   := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address)), out.d.bits)
 | 
					 | 
				
			||||||
      out.d.ready := in.d.ready && !hintHoldsD
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      in.a.ready  := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready)
 | 
					 | 
				
			||||||
      out.a.valid := in.a.valid && !hintBitsAtA
 | 
					      out.a.valid := in.a.valid && !hintBitsAtA
 | 
				
			||||||
 | 
					      in.a.ready := Mux(hintBitsAtA, hint.ready, out.a.ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      hint.bits := edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address))
 | 
				
			||||||
      out.a.bits := in.a.bits
 | 
					      out.a.bits := in.a.bits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats(out.d.bits), out.d), (UInt(1), hint))
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      out.a.valid := in.a.valid
 | 
					      out.a.valid := in.a.valid
 | 
				
			||||||
      in.a.ready := out.a.ready
 | 
					      in.a.ready := out.a.ready
 | 
				
			||||||
@@ -75,37 +57,19 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
 | 
				
			|||||||
      in.d.bits := out.d.bits
 | 
					      in.d.bits := out.d.bits
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (supportClients && !smartClients) {
 | 
					    if (supportClients && !(passthrough && smartClients)) {
 | 
				
			||||||
      // State of the Hint bypass
 | 
					 | 
				
			||||||
      val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
 | 
					 | 
				
			||||||
      val hintHoldsC = RegInit(Bool(false))
 | 
					 | 
				
			||||||
      val innerHoldsC = counter =/= UInt(0)
 | 
					 | 
				
			||||||
      // Only one of them can hold it
 | 
					 | 
				
			||||||
      assert (!hintHoldsC || !innerHoldsC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Count inner C beats
 | 
					 | 
				
			||||||
      val beats1 = edgeIn.numBeats1(in.c.bits)
 | 
					 | 
				
			||||||
      when (in.c.fire()) { counter := Mux(innerHoldsC, counter - UInt(1), beats1) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Who wants what?
 | 
					 | 
				
			||||||
      val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true)
 | 
					      val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true)
 | 
				
			||||||
      val hintBitsAtB = handleB && out.b.bits.opcode === TLMessages.Hint
 | 
					      val hintBitsAtB = handleB && out.b.bits.opcode === TLMessages.Hint
 | 
				
			||||||
      val hintWantsC = out.b.valid && hintBitsAtB
 | 
					      val hint = Wire(in.c)
 | 
				
			||||||
      val innerWantsC = in.c.valid
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Prioritize existing C traffic over HintAck (and finish multibeat xfers)
 | 
					      hint.valid := out.b.valid &&  hintBitsAtB
 | 
				
			||||||
      val hintWinsC = hintHoldsC || (!innerHoldsC && !innerWantsC)
 | 
					 | 
				
			||||||
      hintHoldsC := hintWantsC && hintWinsC && !out.c.ready
 | 
					 | 
				
			||||||
      // Hint can only hold C b/c it still wants it from last cycle
 | 
					 | 
				
			||||||
      assert (!hintHoldsC || hintWantsC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      out.c.valid := Mux(hintWinsC, hintWantsC, innerWantsC)
 | 
					 | 
				
			||||||
      out.c.bits  := Mux(hintWinsC, edgeOut.HintAck(out.b.bits), in.c.bits)
 | 
					 | 
				
			||||||
      in.c.ready  := out.c.ready && !hintHoldsC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      out.b.ready := Mux(hintBitsAtB, hintWinsC && out.c.ready, in.b.ready)
 | 
					 | 
				
			||||||
      in.b.valid := out.b.valid && !hintBitsAtB
 | 
					      in.b.valid := out.b.valid && !hintBitsAtB
 | 
				
			||||||
 | 
					      out.b.ready := Mux(hintBitsAtB, hint.ready, in.b.ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      hint.bits := edgeOut.HintAck(out.b.bits)
 | 
				
			||||||
      in.b.bits := out.b.bits
 | 
					      in.b.bits := out.b.bits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats(in.c.bits), in.c), (UInt(1), hint))
 | 
				
			||||||
    } else if (bce) {
 | 
					    } else if (bce) {
 | 
				
			||||||
      in.b.valid := out.b.valid
 | 
					      in.b.valid := out.b.valid
 | 
				
			||||||
      out.b.ready := in.b.ready
 | 
					      out.b.ready := in.b.ready
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import Chisel._
 | 
				
			|||||||
import chisel3.internal.sourceinfo.SourceInfo
 | 
					import chisel3.internal.sourceinfo.SourceInfo
 | 
				
			||||||
import diplomacy._
 | 
					import diplomacy._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// READ the comments in the TLIsolation object before you instantiate this module
 | 
				
			||||||
class TLIsolation(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt) extends LazyModule
 | 
					class TLIsolation(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt) extends LazyModule
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  val node = TLAsyncIdentityNode()
 | 
					  val node = TLAsyncIdentityNode()
 | 
				
			||||||
@@ -30,6 +31,11 @@ class TLIsolation(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt) extends
 | 
				
			|||||||
      in .d.widx := ISOi(out.d.widx)
 | 
					      in .d.widx := ISOi(out.d.widx)
 | 
				
			||||||
      in .d.mem  := ISOi(out.d.mem)
 | 
					      in .d.mem  := ISOi(out.d.mem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      out.a.source_reset_n := ISOo(in .a.source_reset_n)
 | 
				
			||||||
 | 
					      in .a.sink_reset_n   := ISOi(out.a.sink_reset_n)
 | 
				
			||||||
 | 
					      out.d.sink_reset_n   := ISOo(in .d.sink_reset_n)
 | 
				
			||||||
 | 
					      in .d.source_reset_n := ISOi(out.d.source_reset_n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (edgeOut.manager.base.anySupportAcquire && edgeOut.client.base.anySupportProbe) {
 | 
					      if (edgeOut.manager.base.anySupportAcquire && edgeOut.client.base.anySupportProbe) {
 | 
				
			||||||
        in .b.widx := ISOi(out.b.widx)
 | 
					        in .b.widx := ISOi(out.b.widx)
 | 
				
			||||||
        in .c.ridx := ISOi(out.c.ridx)
 | 
					        in .c.ridx := ISOi(out.c.ridx)
 | 
				
			||||||
@@ -40,6 +46,13 @@ class TLIsolation(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt) extends
 | 
				
			|||||||
        in .b.mem  := ISOi(out.b.mem)
 | 
					        in .b.mem  := ISOi(out.b.mem)
 | 
				
			||||||
        out.c.mem  := ISOo(in .c.mem)
 | 
					        out.c.mem  := ISOo(in .c.mem)
 | 
				
			||||||
        out.e.mem  := ISOo(in .e.mem)
 | 
					        out.e.mem  := ISOo(in .e.mem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        out.b.sink_reset_n   := ISOo(in .b.sink_reset_n)
 | 
				
			||||||
 | 
					        in .b.source_reset_n := ISOi(out.b.source_reset_n)
 | 
				
			||||||
 | 
					        out.c.source_reset_n := ISOo(in .c.source_reset_n)
 | 
				
			||||||
 | 
					        in .c.sink_reset_n   := ISOi(out.c.sink_reset_n)
 | 
				
			||||||
 | 
					        out.e.source_reset_n := ISOo(in .e.source_reset_n)
 | 
				
			||||||
 | 
					        in .e.sink_reset_n   := ISOi(out.e.sink_reset_n)
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        in .b.widx := UInt(0)
 | 
					        in .b.widx := UInt(0)
 | 
				
			||||||
        in .c.ridx := UInt(0)
 | 
					        in .c.ridx := UInt(0)
 | 
				
			||||||
@@ -55,9 +68,10 @@ class TLIsolation(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt) extends
 | 
				
			|||||||
object TLIsolation
 | 
					object TLIsolation
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // applied to the TL source node; y.node := TLIsolation(fOut, fIn)(x.node)
 | 
					  // applied to the TL source node; y.node := TLIsolation(fOut, fIn)(x.node)
 | 
				
			||||||
  // f should insert an isolation gate between the input UInt and its result
 | 
					  // f* should insert an isolation gate between the input UInt and its result
 | 
				
			||||||
  // fOut is applied for data flowing from client to manager
 | 
					  // fOut is applied to data flowing from client to manager
 | 
				
			||||||
  // fIn  is applied for data flowing from manager to client
 | 
					  // fIn  is applied to data flowing from manager to client
 | 
				
			||||||
 | 
					  // **** WARNING: the isolation functions must bring the values to 0 ****
 | 
				
			||||||
  def apply(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt)(x: TLAsyncOutwardNode)(implicit sourceInfo: SourceInfo): (TLAsyncOutwardNode, () => (Bool, Bool)) = {
 | 
					  def apply(fOut: (Bool, UInt) => UInt, fIn: (Bool, UInt) => UInt)(x: TLAsyncOutwardNode)(implicit sourceInfo: SourceInfo): (TLAsyncOutwardNode, () => (Bool, Bool)) = {
 | 
				
			||||||
    val iso = LazyModule(new TLIsolation(fOut, fIn))
 | 
					    val iso = LazyModule(new TLIsolation(fOut, fIn))
 | 
				
			||||||
    iso.node := x
 | 
					    iso.node := x
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -282,23 +282,20 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def legalizeMultibeatA(a: IrrevocableSnoop[TLBundleA], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeMultibeatA(a: IrrevocableSnoop[TLBundleA], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					    val (a_first, _, _) = edge.firstlast(a.bits, a.fire())
 | 
				
			||||||
    val opcode  = Reg(UInt())
 | 
					    val opcode  = Reg(UInt())
 | 
				
			||||||
    val param   = Reg(UInt())
 | 
					    val param   = Reg(UInt())
 | 
				
			||||||
    val size    = Reg(UInt())
 | 
					    val size    = Reg(UInt())
 | 
				
			||||||
    val source  = Reg(UInt())
 | 
					    val source  = Reg(UInt())
 | 
				
			||||||
    val addr_hi = Reg(UInt())
 | 
					    val addr_hi = Reg(UInt())
 | 
				
			||||||
    when (a.valid && counter =/= UInt(0)) {
 | 
					    when (a.valid && !a_first) {
 | 
				
			||||||
      assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation" + extra)
 | 
					      assert (a.bits.opcode === opcode, "'A' channel opcode changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (a.bits.param  === param,  "'A' channel param changed within multibeat operation" + extra)
 | 
					      assert (a.bits.param  === param,  "'A' channel param changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (a.bits.size   === size,   "'A' channel size changed within multibeat operation" + extra)
 | 
					      assert (a.bits.size   === size,   "'A' channel size changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (a.bits.source === source, "'A' channel source changed within multibeat operation" + extra)
 | 
					      assert (a.bits.source === source, "'A' channel source changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (a.bits.addr_hi=== addr_hi,"'A' channel addr_hi changed with multibeat operation" + extra)
 | 
					      assert (a.bits.addr_hi=== addr_hi,"'A' channel addr_hi changed with multibeat operation" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    when (a.fire()) {
 | 
					    when (a.fire() && a_first) {
 | 
				
			||||||
      counter := counter - UInt(1)
 | 
					 | 
				
			||||||
      when (counter === UInt(0)) {
 | 
					 | 
				
			||||||
        counter := edge.numBeats(a.bits) - UInt(1)
 | 
					 | 
				
			||||||
      opcode  := a.bits.opcode
 | 
					      opcode  := a.bits.opcode
 | 
				
			||||||
      param   := a.bits.param
 | 
					      param   := a.bits.param
 | 
				
			||||||
      size    := a.bits.size
 | 
					      size    := a.bits.size
 | 
				
			||||||
@@ -306,26 +303,22 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      addr_hi := a.bits.addr_hi
 | 
					      addr_hi := a.bits.addr_hi
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def legalizeMultibeatB(b: IrrevocableSnoop[TLBundleB], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeMultibeatB(b: IrrevocableSnoop[TLBundleB], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					    val (b_first, _, _) = edge.firstlast(b.bits, b.fire())
 | 
				
			||||||
    val opcode  = Reg(UInt())
 | 
					    val opcode  = Reg(UInt())
 | 
				
			||||||
    val param   = Reg(UInt())
 | 
					    val param   = Reg(UInt())
 | 
				
			||||||
    val size    = Reg(UInt())
 | 
					    val size    = Reg(UInt())
 | 
				
			||||||
    val source  = Reg(UInt())
 | 
					    val source  = Reg(UInt())
 | 
				
			||||||
    val addr_hi = Reg(UInt())
 | 
					    val addr_hi = Reg(UInt())
 | 
				
			||||||
    when (b.valid && counter =/= UInt(0)) {
 | 
					    when (b.valid && !b_first) {
 | 
				
			||||||
      assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation" + extra)
 | 
					      assert (b.bits.opcode === opcode, "'B' channel opcode changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (b.bits.param  === param,  "'B' channel param changed within multibeat operation" + extra)
 | 
					      assert (b.bits.param  === param,  "'B' channel param changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (b.bits.size   === size,   "'B' channel size changed within multibeat operation" + extra)
 | 
					      assert (b.bits.size   === size,   "'B' channel size changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (b.bits.source === source, "'B' channel source changed within multibeat operation" + extra)
 | 
					      assert (b.bits.source === source, "'B' channel source changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (b.bits.addr_hi=== addr_hi,"'B' channel addr_hi changed with multibeat operation" + extra)
 | 
					      assert (b.bits.addr_hi=== addr_hi,"'B' channel addr_hi changed with multibeat operation" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    when (b.fire()) {
 | 
					    when (b.fire() && b_first) {
 | 
				
			||||||
      counter := counter - UInt(1)
 | 
					 | 
				
			||||||
      when (counter === UInt(0)) {
 | 
					 | 
				
			||||||
        counter := edge.numBeats(b.bits) - UInt(1)
 | 
					 | 
				
			||||||
      opcode  := b.bits.opcode
 | 
					      opcode  := b.bits.opcode
 | 
				
			||||||
      param   := b.bits.param
 | 
					      param   := b.bits.param
 | 
				
			||||||
      size    := b.bits.size
 | 
					      size    := b.bits.size
 | 
				
			||||||
@@ -333,17 +326,16 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      addr_hi := b.bits.addr_hi
 | 
					      addr_hi := b.bits.addr_hi
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def legalizeMultibeatC(c: IrrevocableSnoop[TLBundleC], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeMultibeatC(c: IrrevocableSnoop[TLBundleC], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					    val (c_first, _, _) = edge.firstlast(c.bits, c.fire())
 | 
				
			||||||
    val opcode  = Reg(UInt())
 | 
					    val opcode  = Reg(UInt())
 | 
				
			||||||
    val param   = Reg(UInt())
 | 
					    val param   = Reg(UInt())
 | 
				
			||||||
    val size    = Reg(UInt())
 | 
					    val size    = Reg(UInt())
 | 
				
			||||||
    val source  = Reg(UInt())
 | 
					    val source  = Reg(UInt())
 | 
				
			||||||
    val addr_hi = Reg(UInt())
 | 
					    val addr_hi = Reg(UInt())
 | 
				
			||||||
    val addr_lo = Reg(UInt())
 | 
					    val addr_lo = Reg(UInt())
 | 
				
			||||||
    when (c.valid && counter =/= UInt(0)) {
 | 
					    when (c.valid && !c_first) {
 | 
				
			||||||
      assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation" + extra)
 | 
					      assert (c.bits.opcode === opcode, "'C' channel opcode changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (c.bits.param  === param,  "'C' channel param changed within multibeat operation" + extra)
 | 
					      assert (c.bits.param  === param,  "'C' channel param changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (c.bits.size   === size,   "'C' channel size changed within multibeat operation" + extra)
 | 
					      assert (c.bits.size   === size,   "'C' channel size changed within multibeat operation" + extra)
 | 
				
			||||||
@@ -351,10 +343,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      assert (c.bits.addr_hi=== addr_hi,"'C' channel addr_hi changed with multibeat operation" + extra)
 | 
					      assert (c.bits.addr_hi=== addr_hi,"'C' channel addr_hi changed with multibeat operation" + extra)
 | 
				
			||||||
      assert (c.bits.addr_lo=== addr_lo,"'C' channel addr_lo changed with multibeat operation" + extra)
 | 
					      assert (c.bits.addr_lo=== addr_lo,"'C' channel addr_lo changed with multibeat operation" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    when (c.fire()) {
 | 
					    when (c.fire() && c_first) {
 | 
				
			||||||
      counter := counter - UInt(1)
 | 
					 | 
				
			||||||
      when (counter === UInt(0)) {
 | 
					 | 
				
			||||||
        counter := edge.numBeats(c.bits) - UInt(1)
 | 
					 | 
				
			||||||
      opcode  := c.bits.opcode
 | 
					      opcode  := c.bits.opcode
 | 
				
			||||||
      param   := c.bits.param
 | 
					      param   := c.bits.param
 | 
				
			||||||
      size    := c.bits.size
 | 
					      size    := c.bits.size
 | 
				
			||||||
@@ -363,17 +352,16 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      addr_lo := c.bits.addr_lo
 | 
					      addr_lo := c.bits.addr_lo
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def legalizeMultibeatD(d: IrrevocableSnoop[TLBundleD], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeMultibeatD(d: IrrevocableSnoop[TLBundleD], edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    val counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					    val (d_first, _, _) = edge.firstlast(d.bits, d.fire())
 | 
				
			||||||
    val opcode  = Reg(UInt())
 | 
					    val opcode  = Reg(UInt())
 | 
				
			||||||
    val param   = Reg(UInt())
 | 
					    val param   = Reg(UInt())
 | 
				
			||||||
    val size    = Reg(UInt())
 | 
					    val size    = Reg(UInt())
 | 
				
			||||||
    val source  = Reg(UInt())
 | 
					    val source  = Reg(UInt())
 | 
				
			||||||
    val sink    = Reg(UInt())
 | 
					    val sink    = Reg(UInt())
 | 
				
			||||||
    val addr_lo = Reg(UInt())
 | 
					    val addr_lo = Reg(UInt())
 | 
				
			||||||
    when (d.valid && counter =/= UInt(0)) {
 | 
					    when (d.valid && !d_first) {
 | 
				
			||||||
      assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation" + extra)
 | 
					      assert (d.bits.opcode === opcode, "'D' channel opcode changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (d.bits.param  === param,  "'D' channel param changed within multibeat operation" + extra)
 | 
					      assert (d.bits.param  === param,  "'D' channel param changed within multibeat operation" + extra)
 | 
				
			||||||
      assert (d.bits.size   === size,   "'D' channel size changed within multibeat operation" + extra)
 | 
					      assert (d.bits.size   === size,   "'D' channel size changed within multibeat operation" + extra)
 | 
				
			||||||
@@ -381,10 +369,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      assert (d.bits.sink   === sink,   "'D' channel sink changed with multibeat operation" + extra)
 | 
					      assert (d.bits.sink   === sink,   "'D' channel sink changed with multibeat operation" + extra)
 | 
				
			||||||
      assert (d.bits.addr_lo=== addr_lo,"'D' channel addr_lo changed with multibeat operation" + extra)
 | 
					      assert (d.bits.addr_lo=== addr_lo,"'D' channel addr_lo changed with multibeat operation" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    when (d.fire()) {
 | 
					    when (d.fire() && d_first) {
 | 
				
			||||||
      counter := counter - UInt(1)
 | 
					 | 
				
			||||||
      when (counter === UInt(0)) {
 | 
					 | 
				
			||||||
        counter := edge.numBeats(d.bits) - UInt(1)
 | 
					 | 
				
			||||||
      opcode  := d.bits.opcode
 | 
					      opcode  := d.bits.opcode
 | 
				
			||||||
      param   := d.bits.param
 | 
					      param   := d.bits.param
 | 
				
			||||||
      size    := d.bits.size
 | 
					      size    := d.bits.size
 | 
				
			||||||
@@ -393,7 +378,6 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
      addr_lo := d.bits.addr_lo
 | 
					      addr_lo := d.bits.addr_lo
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def legalizeMultibeat(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeMultibeat(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    legalizeMultibeatA(bundle.a, edge)
 | 
					    legalizeMultibeatA(bundle.a, edge)
 | 
				
			||||||
@@ -425,15 +409,8 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
  def legalizeSourceUnique(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
					  def legalizeSourceUnique(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) {
 | 
				
			||||||
    val inflight = RegInit(UInt(0, width = edge.client.endSourceId))
 | 
					    val inflight = RegInit(UInt(0, width = edge.client.endSourceId))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val a_counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					    val (_, a_last, _) = edge.firstlast(bundle.a.bits, bundle.a.fire())
 | 
				
			||||||
    val a_beats1 = edge.numBeats1(bundle.a.bits)
 | 
					    val (_, d_last, _) = edge.firstlast(bundle.d.bits, bundle.d.fire())
 | 
				
			||||||
    val a_first = a_counter === UInt(0)
 | 
					 | 
				
			||||||
    val a_last = a_counter === UInt(1) || a_beats1 === UInt(0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val d_counter = RegInit(UInt(0, width = log2Up(edge.maxTransfer)))
 | 
					 | 
				
			||||||
    val d_beats1 = edge.numBeats1(bundle.d.bits)
 | 
					 | 
				
			||||||
    val d_first = d_counter === UInt(0)
 | 
					 | 
				
			||||||
    val d_last = d_counter === UInt(1) || d_beats1 === UInt(0)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val bypass = bundle.a.bits.source === bundle.d.bits.source
 | 
					    val bypass = bundle.a.bits.source === bundle.d.bits.source
 | 
				
			||||||
    val a_bypass = bypass && bundle.d.valid && d_last
 | 
					    val a_bypass = bypass && bundle.d.valid && d_last
 | 
				
			||||||
@@ -445,14 +422,12 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    val a_set = Wire(init = UInt(0, width = edge.client.endSourceId))
 | 
					    val a_set = Wire(init = UInt(0, width = edge.client.endSourceId))
 | 
				
			||||||
    when (bundle.a.fire()) {
 | 
					    when (bundle.a.fire()) {
 | 
				
			||||||
      a_counter := Mux(a_first, a_beats1, a_counter - UInt(1))
 | 
					 | 
				
			||||||
      when (a_last) { a_set := UIntToOH(bundle.a.bits.source) }
 | 
					      when (a_last) { a_set := UIntToOH(bundle.a.bits.source) }
 | 
				
			||||||
      assert(a_bypass || !inflight(bundle.a.bits.source), "'A' channel re-used a source ID" + extra)
 | 
					      assert(a_bypass || !inflight(bundle.a.bits.source), "'A' channel re-used a source ID" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val d_clr = Wire(init = UInt(0, width = edge.client.endSourceId))
 | 
					    val d_clr = Wire(init = UInt(0, width = edge.client.endSourceId))
 | 
				
			||||||
    when (bundle.d.fire() && bundle.d.bits.opcode =/= TLMessages.ReleaseAck) {
 | 
					    when (bundle.d.fire() && bundle.d.bits.opcode =/= TLMessages.ReleaseAck) {
 | 
				
			||||||
      d_counter := Mux(d_first, d_beats1, d_counter - UInt(1))
 | 
					 | 
				
			||||||
      when (d_last) { d_clr := UIntToOH(bundle.d.bits.source) }
 | 
					      when (d_last) { d_clr := UIntToOH(bundle.d.bits.source) }
 | 
				
			||||||
      assert(d_bypass || inflight(bundle.d.bits.source), "'D' channel acknowledged for nothing inflight" + extra)
 | 
					      assert(d_bypass || inflight(bundle.d.bits.source), "'D' channel acknowledged for nothing inflight" + extra)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -110,13 +110,10 @@ class TLRAMModel extends LazyModule
 | 
				
			|||||||
    // Process A access requests
 | 
					    // Process A access requests
 | 
				
			||||||
    val a = Reg(next = in.a.bits)
 | 
					    val a = Reg(next = in.a.bits)
 | 
				
			||||||
    val a_fire = Reg(next = in.a.fire(), init = Bool(false))
 | 
					    val a_fire = Reg(next = in.a.fire(), init = Bool(false))
 | 
				
			||||||
    val a_beats1 = edge.numBeats1(a)
 | 
					    val (a_first, a_last, a_address_inc) = edge.firstlast(a, a_fire)
 | 
				
			||||||
    val a_size = edge.size(a)
 | 
					    val a_size = edge.size(a)
 | 
				
			||||||
    val a_sizeOH = UIntToOH(a_size)
 | 
					    val a_sizeOH = UIntToOH(a_size)
 | 
				
			||||||
    val a_counter = RegInit(UInt(0, width = maxLgBeats))
 | 
					    val a_addr_hi = a.addr_hi | a_address_inc
 | 
				
			||||||
    val a_counter1 = a_counter - UInt(1)
 | 
					 | 
				
			||||||
    val a_first = a_counter === UInt(0)
 | 
					 | 
				
			||||||
    val a_addr_hi = a.addr_hi | (a_beats1 & ~a_counter1)
 | 
					 | 
				
			||||||
    val a_base = edge.address(a)
 | 
					    val a_base = edge.address(a)
 | 
				
			||||||
    val a_mask = edge.mask(a_base, a_size)
 | 
					    val a_mask = edge.mask(a_base, a_size)
 | 
				
			||||||
    val a_fifo = edge.manager.hasFifoIdFast(a_base)
 | 
					    val a_fifo = edge.manager.hasFifoIdFast(a_base)
 | 
				
			||||||
@@ -133,8 +130,6 @@ class TLRAMModel extends LazyModule
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    when (a_fire) {
 | 
					    when (a_fire) {
 | 
				
			||||||
      // Record the request so we can handle it's response
 | 
					      // Record the request so we can handle it's response
 | 
				
			||||||
      a_counter := Mux(a_first, a_beats1, a_counter1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      assert (a.opcode =/= TLMessages.Acquire)
 | 
					      assert (a.opcode =/= TLMessages.Acquire)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Mark the operation as valid
 | 
					      // Mark the operation as valid
 | 
				
			||||||
@@ -199,15 +194,11 @@ class TLRAMModel extends LazyModule
 | 
				
			|||||||
    // Process D access responses
 | 
					    // Process D access responses
 | 
				
			||||||
    val d = RegNext(out.d.bits)
 | 
					    val d = RegNext(out.d.bits)
 | 
				
			||||||
    val d_fire = Reg(next = out.d.fire(), init = Bool(false))
 | 
					    val d_fire = Reg(next = out.d.fire(), init = Bool(false))
 | 
				
			||||||
    val d_beats1 = edge.numBeats1(d)
 | 
					    val (d_first, d_last, d_address_inc) = edge.firstlast(d, d_fire)
 | 
				
			||||||
    val d_size = edge.size(d)
 | 
					    val d_size = edge.size(d)
 | 
				
			||||||
    val d_sizeOH = UIntToOH(d_size)
 | 
					    val d_sizeOH = UIntToOH(d_size)
 | 
				
			||||||
    val d_counter = RegInit(UInt(0, width = maxLgBeats))
 | 
					 | 
				
			||||||
    val d_counter1 = d_counter - UInt(1)
 | 
					 | 
				
			||||||
    val d_first = d_counter === UInt(0)
 | 
					 | 
				
			||||||
    val d_last  = d_counter === UInt(1) || d_beats1 === UInt(0)
 | 
					 | 
				
			||||||
    val d_base = d_flight.base
 | 
					    val d_base = d_flight.base
 | 
				
			||||||
    val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1)
 | 
					    val d_addr_hi = d_base >> shift | d_address_inc
 | 
				
			||||||
    val d_mask = edge.mask(d_base, d_size)
 | 
					    val d_mask = edge.mask(d_base, d_size)
 | 
				
			||||||
    val d_fifo = edge.manager.hasFifoIdFast(d_flight.base)
 | 
					    val d_fifo = edge.manager.hasFifoIdFast(d_flight.base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -224,8 +215,6 @@ class TLRAMModel extends LazyModule
 | 
				
			|||||||
    val d_valid = valid(d.source)
 | 
					    val d_valid = valid(d.source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    when (d_fire) {
 | 
					    when (d_fire) {
 | 
				
			||||||
      d_counter := Mux(d_first, d_beats1, d_counter1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Check the response is correct
 | 
					      // Check the response is correct
 | 
				
			||||||
      assert (d_size === d_flight.size)
 | 
					      assert (d_size === d_flight.size)
 | 
				
			||||||
      assert (edge.manager.findIdStartFast(d_flight.base) <= d.sink)
 | 
					      assert (edge.manager.findIdStartFast(d_flight.base) <= d.sink)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -231,18 +231,16 @@ trait RRTest1Module extends Module with HasRegMap
 | 
				
			|||||||
    val readCross = Module(new RegisterReadCrossing(field))
 | 
					    val readCross = Module(new RegisterReadCrossing(field))
 | 
				
			||||||
    readCross.io.master_clock  := clock
 | 
					    readCross.io.master_clock  := clock
 | 
				
			||||||
    readCross.io.master_reset  := reset
 | 
					    readCross.io.master_reset  := reset
 | 
				
			||||||
    readCross.io.master_allow := Bool(true)
 | 
					    readCross.io.master_bypass := Bool(false)
 | 
				
			||||||
    readCross.io.slave_clock   := clocks.io.clock_out
 | 
					    readCross.io.slave_clock   := clocks.io.clock_out
 | 
				
			||||||
    readCross.io.slave_reset   := reset
 | 
					    readCross.io.slave_reset   := reset
 | 
				
			||||||
    readCross.io.slave_allow := Bool(true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val writeCross = Module(new RegisterWriteCrossing(field))
 | 
					    val writeCross = Module(new RegisterWriteCrossing(field))
 | 
				
			||||||
    writeCross.io.master_clock  := clock
 | 
					    writeCross.io.master_clock  := clock
 | 
				
			||||||
    writeCross.io.master_reset  := reset
 | 
					    writeCross.io.master_reset  := reset
 | 
				
			||||||
    writeCross.io.master_allow := Bool(true)
 | 
					    writeCross.io.master_bypass := Bool(false)
 | 
				
			||||||
    writeCross.io.slave_clock   := clocks.io.clock_out
 | 
					    writeCross.io.slave_clock   := clocks.io.clock_out
 | 
				
			||||||
    writeCross.io.slave_reset   := reset
 | 
					    writeCross.io.slave_reset   := reset
 | 
				
			||||||
    writeCross.io.slave_allow := Bool(true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    readCross.io.slave_register := writeCross.io.slave_register
 | 
					    readCross.io.slave_register := writeCross.io.slave_register
 | 
				
			||||||
    RegField(bits, readCross.io.master_port, writeCross.io.master_port)
 | 
					    RegField(bits, readCross.io.master_port, writeCross.io.master_port)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,9 @@ import diplomacy._
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package object tilelink2
 | 
					package object tilelink2
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  type TLOutwardNode = OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]
 | 
					  type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
 | 
				
			||||||
  type TLAsyncOutwardNode = OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
 | 
					  type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
 | 
				
			||||||
  type IntOutwardNode = OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
 | 
					  type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
 | 
				
			||||||
  def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x)
 | 
					  def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x)
 | 
				
			||||||
  def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
 | 
					  def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
 | 
				
			||||||
  def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None
 | 
					  def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,19 +4,19 @@ package util
 | 
				
			|||||||
import Chisel._
 | 
					import Chisel._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object GrayCounter {
 | 
					object GrayCounter {
 | 
				
			||||||
  def apply(bits: Int, increment: Bool = Bool(true), name: String = "binary"): UInt = {
 | 
					  def apply(bits: Int, increment: Bool = Bool(true), clear: Bool = Bool(false), name: String = "binary"): UInt = {
 | 
				
			||||||
    val incremented = Wire(UInt(width=bits))
 | 
					    val incremented = Wire(UInt(width=bits))
 | 
				
			||||||
    val binary = AsyncResetReg(incremented, name)
 | 
					    val binary = AsyncResetReg(incremented, name)
 | 
				
			||||||
    incremented := binary + increment.asUInt()
 | 
					    incremented := Mux(clear, UInt(0), binary + increment.asUInt())
 | 
				
			||||||
    incremented ^ (incremented >> UInt(1))
 | 
					    incremented ^ (incremented >> UInt(1))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object AsyncGrayCounter {
 | 
					object UIntSyncChain {
 | 
				
			||||||
  def apply(in: UInt, sync: Int, name: String = "gray"): UInt = {
 | 
					  def apply(in: UInt, sync: Int, name: String = "gray"): UInt = {
 | 
				
			||||||
    val syncv = List.tabulate(sync)(i =>
 | 
					    val syncv = List.tabulate(sync) { i =>
 | 
				
			||||||
      Module (new AsyncResetRegVec(w = in.getWidth, 0)).suggestName(s"${name}_sync_${i}")
 | 
					      Module (new AsyncResetRegVec(w = in.getWidth, 0)).suggestName(s"${name}_sync_${i}")
 | 
				
			||||||
    )
 | 
					    }
 | 
				
			||||||
    syncv.last.io.d := in
 | 
					    syncv.last.io.d := in
 | 
				
			||||||
    syncv.last.io.en := Bool(true)
 | 
					    syncv.last.io.en := Bool(true)
 | 
				
			||||||
      (syncv.init zip syncv.tail).foreach { case (sink, source) =>
 | 
					      (syncv.init zip syncv.tail).foreach { case (sink, source) =>
 | 
				
			||||||
@@ -31,27 +31,38 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int) extends Module
 | 
				
			|||||||
  val bits = log2Ceil(depth)
 | 
					  val bits = log2Ceil(depth)
 | 
				
			||||||
  val io = new Bundle {
 | 
					  val io = new Bundle {
 | 
				
			||||||
    // These come from the source domain
 | 
					    // These come from the source domain
 | 
				
			||||||
    val enq  = Decoupled(gen).flip()
 | 
					    val enq  = Decoupled(gen).flip
 | 
				
			||||||
    // These cross to the sink clock domain
 | 
					    // These cross to the sink clock domain
 | 
				
			||||||
    val ridx = UInt(INPUT,  width = bits+1)
 | 
					    val ridx = UInt(INPUT,  width = bits+1)
 | 
				
			||||||
    val widx = UInt(OUTPUT, width = bits+1)
 | 
					    val widx = UInt(OUTPUT, width = bits+1)
 | 
				
			||||||
    val mem  = Vec(depth, gen).asOutput
 | 
					    val mem  = Vec(depth, gen).asOutput
 | 
				
			||||||
 | 
					    // Reset for the other side
 | 
				
			||||||
 | 
					    val sink_reset_n = Bool().flip
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // extend the sink reset to a full cycle (assertion latency <= 1 cycle)
 | 
				
			||||||
 | 
					  val catch_sink_reset_n = AsyncResetReg(Bool(true), clock, !io.sink_reset_n, "catch_sink_reset_n")
 | 
				
			||||||
 | 
					  // reset_n has a 1 cycle shorter path to ready than ridx does
 | 
				
			||||||
 | 
					  val sink_reset_n = UIntSyncChain(catch_sink_reset_n.asUInt, sync, "sink_reset_n")(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val mem = Reg(Vec(depth, gen)) //This does NOT need to be asynchronously reset.
 | 
					  val mem = Reg(Vec(depth, gen)) //This does NOT need to be asynchronously reset.
 | 
				
			||||||
  val widx = GrayCounter(bits+1, io.enq.fire(), "widx_bin")
 | 
					  val widx = GrayCounter(bits+1, io.enq.fire(), !sink_reset_n, "widx_bin")
 | 
				
			||||||
  val ridx = AsyncGrayCounter(io.ridx, sync, "ridx_gray")
 | 
					  val ridx = UIntSyncChain(io.ridx, sync, "ridx_gray")
 | 
				
			||||||
  val ready = widx =/= (ridx ^ UInt(depth | depth >> 1))
 | 
					  val ready = widx =/= (ridx ^ UInt(depth | depth >> 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
 | 
					  val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
 | 
				
			||||||
  when (io.enq.fire()) { mem(index) := io.enq.bits }
 | 
					  when (io.enq.fire()) { mem(index) := io.enq.bits }
 | 
				
			||||||
  val ready_reg = AsyncResetReg(ready, "ready")
 | 
					
 | 
				
			||||||
  io.enq.ready := ready_reg
 | 
					  val ready_reg = AsyncResetReg(ready.asUInt, "ready_reg")(0)
 | 
				
			||||||
 | 
					  io.enq.ready := ready_reg && sink_reset_n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val widx_reg = AsyncResetReg(widx, "widx_gray")
 | 
					  val widx_reg = AsyncResetReg(widx, "widx_gray")
 | 
				
			||||||
  io.widx := widx_reg
 | 
					  io.widx := widx_reg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.mem := mem
 | 
					  io.mem := mem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // It is a fatal error to reset half a Queue while it still has data
 | 
				
			||||||
 | 
					  assert (sink_reset_n || widx === ridx)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
 | 
					class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
 | 
				
			||||||
@@ -63,10 +74,17 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
 | 
				
			|||||||
    val ridx = UInt(OUTPUT, width = bits+1)
 | 
					    val ridx = UInt(OUTPUT, width = bits+1)
 | 
				
			||||||
    val widx = UInt(INPUT,  width = bits+1)
 | 
					    val widx = UInt(INPUT,  width = bits+1)
 | 
				
			||||||
    val mem  = Vec(depth, gen).asInput
 | 
					    val mem  = Vec(depth, gen).asInput
 | 
				
			||||||
 | 
					    // Reset for the other side
 | 
				
			||||||
 | 
					    val source_reset_n = Bool().flip
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val ridx = GrayCounter(bits+1, io.deq.fire(), "ridx_bin")
 | 
					  // extend the source reset to a full cycle (assertion latency <= 1 cycle)
 | 
				
			||||||
  val widx = AsyncGrayCounter(io.widx, sync, "widx_gray")
 | 
					  val catch_source_reset_n = AsyncResetReg(Bool(true), clock, !io.source_reset_n, "catch_source_reset_n")
 | 
				
			||||||
 | 
					  // reset_n has a 1 cycle shorter path to valid than widx does
 | 
				
			||||||
 | 
					  val source_reset_n = UIntSyncChain(catch_source_reset_n.asUInt, sync, "source_reset_n")(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val ridx = GrayCounter(bits+1, io.deq.fire(), !source_reset_n, "ridx_bin")
 | 
				
			||||||
 | 
					  val widx = UIntSyncChain(io.widx, sync, "widx_gray")
 | 
				
			||||||
  val valid = ridx =/= widx
 | 
					  val valid = ridx =/= widx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // The mux is safe because timing analysis ensures ridx has reached the register
 | 
					  // The mux is safe because timing analysis ensures ridx has reached the register
 | 
				
			||||||
@@ -76,12 +94,18 @@ class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
 | 
				
			|||||||
  val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
 | 
					  val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
 | 
				
			||||||
  // This register does not NEED to be reset, as its contents will not
 | 
					  // This register does not NEED to be reset, as its contents will not
 | 
				
			||||||
  // be considered unless the asynchronously reset deq valid register is set.
 | 
					  // be considered unless the asynchronously reset deq valid register is set.
 | 
				
			||||||
  val data = RegEnable(io.mem(index), valid)
 | 
					  // It is possible that bits latches when the source domain is reset / has power cut
 | 
				
			||||||
  io.deq.bits := data
 | 
					  // This is safe, because isolation gates brought mem low before the zeroed widx reached us
 | 
				
			||||||
 | 
					  io.deq.bits  := RegEnable(io.mem(index), valid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.deq.valid := AsyncResetReg(valid, "valid_reg")
 | 
					  val valid_reg = AsyncResetReg(valid.asUInt, "valid_reg")(0)
 | 
				
			||||||
 | 
					  io.deq.valid := valid_reg && source_reset_n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.ridx := AsyncResetReg(ridx, "ridx_gray")
 | 
					  val ridx_reg = AsyncResetReg(ridx, "ridx_gray")
 | 
				
			||||||
 | 
					  io.ridx := ridx_reg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // It is a fatal error to reset half a Queue while it still has data
 | 
				
			||||||
 | 
					  assert (source_reset_n || widx === ridx)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Crossing[T] {
 | 
					class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Crossing[T] {
 | 
				
			||||||
@@ -97,6 +121,9 @@ class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Cross
 | 
				
			|||||||
  sink.clock := io.deq_clock
 | 
					  sink.clock := io.deq_clock
 | 
				
			||||||
  sink.reset := io.deq_reset
 | 
					  sink.reset := io.deq_reset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  source.io.sink_reset_n := !io.deq_reset
 | 
				
			||||||
 | 
					  sink.io.source_reset_n := !io.enq_reset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  source.io.enq <> io.enq
 | 
					  source.io.enq <> io.enq
 | 
				
			||||||
  io.deq <> sink.io.deq
 | 
					  io.deq <> sink.io.deq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ class CrossingIO[T <: Data](gen: T) extends Bundle {
 | 
				
			|||||||
  // Enqueue clock domain
 | 
					  // Enqueue clock domain
 | 
				
			||||||
  val enq_clock = Clock(INPUT)
 | 
					  val enq_clock = Clock(INPUT)
 | 
				
			||||||
  val enq_reset = Bool(INPUT) // synchronously deasserted wrt. enq_clock
 | 
					  val enq_reset = Bool(INPUT) // synchronously deasserted wrt. enq_clock
 | 
				
			||||||
  val enq = Decoupled(gen).flip()
 | 
					  val enq = Decoupled(gen).flip
 | 
				
			||||||
  // Dequeue clock domain
 | 
					  // Dequeue clock domain
 | 
				
			||||||
  val deq_clock = Clock(INPUT)
 | 
					  val deq_clock = Clock(INPUT)
 | 
				
			||||||
  val deq_reset = Bool(INPUT) // synchronously deasserted wrt. deq_clock
 | 
					  val deq_reset = Bool(INPUT) // synchronously deasserted wrt. deq_clock
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user