implement NASTI Interconnect generating from configuration address map
This commit is contained in:
		@@ -1,13 +1,20 @@
 | 
				
			|||||||
// See LICENSE for license details.
 | 
					/// See LICENSE for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package junctions
 | 
					package junctions
 | 
				
			||||||
import Chisel._
 | 
					import Chisel._
 | 
				
			||||||
import scala.math.max
 | 
					import scala.math.max
 | 
				
			||||||
 | 
					import scala.collection.mutable.ArraySeq
 | 
				
			||||||
 | 
					import scala.collection.mutable.HashMap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object MMIOBase extends Field[BigInt]
 | 
				
			||||||
case object NASTIDataBits extends Field[Int]
 | 
					case object NASTIDataBits extends Field[Int]
 | 
				
			||||||
case object NASTIAddrBits extends Field[Int]
 | 
					case object NASTIAddrBits extends Field[Int]
 | 
				
			||||||
case object NASTIIdBits extends Field[Int]
 | 
					case object NASTIIdBits extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object bigIntPow2 {
 | 
				
			||||||
 | 
					  def apply(in: BigInt): Boolean = in > 0 && ((in & (in-1)) == 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait NASTIParameters extends UsesParameters {
 | 
					trait NASTIParameters extends UsesParameters {
 | 
				
			||||||
  val nastiXDataBits = params(NASTIDataBits)
 | 
					  val nastiXDataBits = params(NASTIDataBits)
 | 
				
			||||||
  val nastiWStrobeBits = nastiXDataBits / 8
 | 
					  val nastiWStrobeBits = nastiXDataBits / 8
 | 
				
			||||||
@@ -149,3 +156,395 @@ class MemIONASTISlaveIOConverter(cacheBlockOffsetBits: Int) extends MIFModule wi
 | 
				
			|||||||
  io.nasti.r.bits.resp := UInt(0)
 | 
					  io.nasti.r.bits.resp := UInt(0)
 | 
				
			||||||
  io.mem.resp.ready := io.nasti.r.ready
 | 
					  io.mem.resp.ready := io.nasti.r.ready
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTIArbiter(val arbN: Int) extends NASTIModule {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val master = Vec.fill(arbN) { new NASTISlaveIO }
 | 
				
			||||||
 | 
					    val slave = new NASTIMasterIO
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (arbN > 1) {
 | 
				
			||||||
 | 
					    val arbIdBits = log2Up(arbN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val ar_arb = Module(new RRArbiter(new NASTIReadAddressChannel, arbN))
 | 
				
			||||||
 | 
					    val aw_arb = Module(new RRArbiter(new NASTIWriteAddressChannel, arbN))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val slave_r_arb_id = io.slave.r.bits.id(arbIdBits - 1, 0)
 | 
				
			||||||
 | 
					    val slave_b_arb_id = io.slave.b.bits.id(arbIdBits - 1, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val w_chosen = Reg(UInt(width = arbIdBits))
 | 
				
			||||||
 | 
					    val w_done = Reg(init = Bool(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (aw_arb.io.out.fire()) {
 | 
				
			||||||
 | 
					      w_chosen := aw_arb.io.chosen
 | 
				
			||||||
 | 
					      w_done := Bool(false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when (io.slave.w.fire() && io.slave.w.bits.last) {
 | 
				
			||||||
 | 
					      w_done := Bool(true)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i <- 0 until arbN) {
 | 
				
			||||||
 | 
					      val m_ar = io.master(i).ar
 | 
				
			||||||
 | 
					      val m_aw = io.master(i).aw
 | 
				
			||||||
 | 
					      val m_r = io.master(i).r
 | 
				
			||||||
 | 
					      val m_b = io.master(i).b
 | 
				
			||||||
 | 
					      val a_ar = ar_arb.io.in(i)
 | 
				
			||||||
 | 
					      val a_aw = aw_arb.io.in(i)
 | 
				
			||||||
 | 
					      val m_w = io.master(i).w
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      a_ar <> m_ar
 | 
				
			||||||
 | 
					      a_ar.bits.id := Cat(m_ar.bits.id, UInt(i, arbIdBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      a_aw <> m_aw
 | 
				
			||||||
 | 
					      a_aw.bits.id := Cat(m_aw.bits.id, UInt(i, arbIdBits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      m_r.valid := io.slave.r.valid && slave_r_arb_id === UInt(i)
 | 
				
			||||||
 | 
					      m_r.bits := io.slave.r.bits
 | 
				
			||||||
 | 
					      m_r.bits.id := io.slave.r.bits.id >> UInt(arbIdBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      m_b.valid := io.slave.b.valid && slave_b_arb_id === UInt(i)
 | 
				
			||||||
 | 
					      m_b.bits := io.slave.b.bits
 | 
				
			||||||
 | 
					      m_b.bits.id := io.slave.b.bits.id >> UInt(arbIdBits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      m_w.ready := io.slave.w.ready && w_chosen === UInt(i) && !w_done
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.slave.r.ready := io.master(slave_r_arb_id).r.ready
 | 
				
			||||||
 | 
					    io.slave.b.ready := io.master(slave_b_arb_id).b.ready
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.slave.w.bits := io.master(w_chosen).w.bits
 | 
				
			||||||
 | 
					    io.slave.w.valid := io.master(w_chosen).w.valid && !w_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.slave.ar <> ar_arb.io.out
 | 
				
			||||||
 | 
					    io.slave.aw <> aw_arb.io.out
 | 
				
			||||||
 | 
					    aw_arb.io.out.ready := io.slave.aw.ready && w_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  } else { io.slave <> io.master.head }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: More efficient implementation a/la Chisel Stdlib
 | 
				
			||||||
 | 
					class NASTIReadDataArbiter(arbN: Int) extends NASTIModule {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val in = Vec.fill(arbN) { Decoupled(new NASTIReadDataChannel) }.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 extends NASTIModule {
 | 
				
			||||||
 | 
					  val io = new NASTISlaveIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val r_queue = Module(new Queue(UInt(width = nastiRIdBits), 2))
 | 
				
			||||||
 | 
					  r_queue.io.enq.valid := io.ar.valid
 | 
				
			||||||
 | 
					  r_queue.io.enq.bits := io.ar.bits.id
 | 
				
			||||||
 | 
					  io.ar.ready := r_queue.io.enq.ready
 | 
				
			||||||
 | 
					  io.r.valid := r_queue.io.deq.valid
 | 
				
			||||||
 | 
					  io.r.bits.id := r_queue.io.deq.bits
 | 
				
			||||||
 | 
					  io.r.bits.resp := Bits("b11")
 | 
				
			||||||
 | 
					  io.r.bits.last := Bool(true)
 | 
				
			||||||
 | 
					  r_queue.io.deq.ready := io.r.ready
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val draining = Reg(init = Bool(false))
 | 
				
			||||||
 | 
					  io.w.ready := draining
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  when (io.aw.fire()) { draining := Bool(true) }
 | 
				
			||||||
 | 
					  when (io.w.fire() && io.w.bits.last) { draining := Bool(false) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val b_queue = Module(new Queue(UInt(width = nastiWIdBits), 2))
 | 
				
			||||||
 | 
					  b_queue.io.enq.valid := io.aw.valid && !draining
 | 
				
			||||||
 | 
					  b_queue.io.enq.bits := io.aw.bits.id
 | 
				
			||||||
 | 
					  io.aw.ready := b_queue.io.enq.ready && !draining
 | 
				
			||||||
 | 
					  io.b.valid := b_queue.io.deq.valid && !draining
 | 
				
			||||||
 | 
					  io.b.bits.id := b_queue.io.deq.bits
 | 
				
			||||||
 | 
					  io.b.bits.resp := Bits("b11")
 | 
				
			||||||
 | 
					  b_queue.io.deq.ready := io.b.ready && !draining
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTIRouter(addrmap: Seq[(BigInt, BigInt)]) extends NASTIModule {
 | 
				
			||||||
 | 
					  val nSlaves = addrmap.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val master = new NASTISlaveIO
 | 
				
			||||||
 | 
					    val slave = Vec.fill(nSlaves) { new NASTIMasterIO }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var ar_ready = Bool(false)
 | 
				
			||||||
 | 
					  var aw_ready = Bool(false)
 | 
				
			||||||
 | 
					  var w_ready = Bool(false)
 | 
				
			||||||
 | 
					  var r_valid_addr = Bool(false)
 | 
				
			||||||
 | 
					  var w_valid_addr = Bool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addrmap.zip(io.slave).zipWithIndex.foreach { case (((base, size), s), i) =>
 | 
				
			||||||
 | 
					    val bound = base + size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    require(bigIntPow2(size),
 | 
				
			||||||
 | 
					      s"Region size $size is not a power of 2")
 | 
				
			||||||
 | 
					    require(base % size == 0,
 | 
				
			||||||
 | 
					      f"Region base address $base%x not divisible by $size%d" )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val ar_addr = io.master.ar.bits.addr
 | 
				
			||||||
 | 
					    val ar_match = ar_addr >= UInt(base) && ar_addr < UInt(bound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s.ar.valid := io.master.ar.valid && ar_match
 | 
				
			||||||
 | 
					    s.ar.bits := io.master.ar.bits
 | 
				
			||||||
 | 
					    ar_ready = ar_ready || (s.ar.ready && ar_match)
 | 
				
			||||||
 | 
					    r_valid_addr = r_valid_addr || ar_match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val aw_addr = io.master.aw.bits.addr
 | 
				
			||||||
 | 
					    val aw_match = aw_addr >= UInt(base) && aw_addr < UInt(bound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s.aw.valid := io.master.aw.valid && aw_match
 | 
				
			||||||
 | 
					    s.aw.bits := io.master.aw.bits
 | 
				
			||||||
 | 
					    aw_ready = aw_ready || (s.aw.ready && aw_match)
 | 
				
			||||||
 | 
					    w_valid_addr = w_valid_addr || aw_match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val chosen = Reg(init = Bool(false))
 | 
				
			||||||
 | 
					    when (s.aw.fire()) { chosen := Bool(true) }
 | 
				
			||||||
 | 
					    when (s.w.fire() && s.w.bits.last) { chosen := Bool(false) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s.w.valid := io.master.w.valid && chosen
 | 
				
			||||||
 | 
					    s.w.bits := io.master.w.bits
 | 
				
			||||||
 | 
					    w_ready = w_ready || (s.w.ready && chosen)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val err_slave = Module(new NASTIErrorSlave)
 | 
				
			||||||
 | 
					  err_slave.io.ar.valid := !r_valid_addr && io.master.ar.valid
 | 
				
			||||||
 | 
					  err_slave.io.ar.bits := io.master.ar.bits
 | 
				
			||||||
 | 
					  err_slave.io.aw.valid := !w_valid_addr && io.master.aw.valid
 | 
				
			||||||
 | 
					  err_slave.io.aw.bits := io.master.aw.bits
 | 
				
			||||||
 | 
					  err_slave.io.w.valid := io.master.w.valid
 | 
				
			||||||
 | 
					  err_slave.io.w.bits := io.master.w.bits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.master.ar.ready := ar_ready || (!r_valid_addr && err_slave.io.ar.ready)
 | 
				
			||||||
 | 
					  io.master.aw.ready := aw_ready || (!w_valid_addr && err_slave.io.aw.ready)
 | 
				
			||||||
 | 
					  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))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nSlaves) {
 | 
				
			||||||
 | 
					    b_arb.io.in(i) <> io.slave(i).b
 | 
				
			||||||
 | 
					    r_arb.io.in(i) <> io.slave(i).r
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  b_arb.io.in(nSlaves) <> err_slave.io.b
 | 
				
			||||||
 | 
					  r_arb.io.in(nSlaves) <> err_slave.io.r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  io.master.b <> b_arb.io.out
 | 
				
			||||||
 | 
					  io.master.r <> r_arb.io.out
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTICrossbar(nMasters: Int, nSlaves: Int, addrmap: Seq[(BigInt, BigInt)])
 | 
				
			||||||
 | 
					    extends NASTIModule {
 | 
				
			||||||
 | 
					  val io = new Bundle {
 | 
				
			||||||
 | 
					    val masters = Vec.fill(nMasters) { new NASTISlaveIO }
 | 
				
			||||||
 | 
					    val slaves = Vec.fill(nSlaves) { new NASTIMasterIO }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val routers = Vec.fill(nMasters) { Module(new NASTIRouter(addrmap)).io }
 | 
				
			||||||
 | 
					  val arbiters = Vec.fill(nSlaves) { Module(new NASTIArbiter(nMasters)).io }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nMasters) {
 | 
				
			||||||
 | 
					    routers(i).master <> io.masters(i)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (i <- 0 until nSlaves) {
 | 
				
			||||||
 | 
					    arbiters(i).master <> Vec(routers.map(r => r.slave(i)))
 | 
				
			||||||
 | 
					    io.slaves(i) <> arbiters(i).slave
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object NASTINMasters extends Field[Int]
 | 
				
			||||||
 | 
					case object NASTINSlaves extends Field[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object AddrMapTypes {
 | 
				
			||||||
 | 
					  type AddrMapEntry = (String, Option[BigInt], MemRegion)
 | 
				
			||||||
 | 
					  type AddrMap = Seq[AddrMapEntry]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					import AddrMapTypes._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class MemRegion { def size: BigInt }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case class MemSize(size: BigInt) extends MemRegion
 | 
				
			||||||
 | 
					case class MemSubmap(size: BigInt, entries: AddrMap) extends MemRegion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object Submap {
 | 
				
			||||||
 | 
					  def apply(size: BigInt, entries: AddrMapEntry*) =
 | 
				
			||||||
 | 
					    new MemSubmap(size, entries)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case class AddrHashMapEntry(port: Int, start: BigInt, size: BigInt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddrHashMap(addrmap: AddrMap) {
 | 
				
			||||||
 | 
					  val mapping = new HashMap[String, AddrHashMapEntry]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def genPairs(addrmap: AddrMap): Seq[(String, AddrHashMapEntry)] = {
 | 
				
			||||||
 | 
					    var ind = 0
 | 
				
			||||||
 | 
					    var base = BigInt(0)
 | 
				
			||||||
 | 
					    var pairs = Seq[(String, AddrHashMapEntry)]()
 | 
				
			||||||
 | 
					    addrmap.foreach { case (name, startOpt, region) =>
 | 
				
			||||||
 | 
					      region match {
 | 
				
			||||||
 | 
					        case MemSize(size) => {
 | 
				
			||||||
 | 
					          if (!startOpt.isEmpty) base = startOpt.get
 | 
				
			||||||
 | 
					          pairs = (name, AddrHashMapEntry(ind, base, size)) +: pairs
 | 
				
			||||||
 | 
					          base += size
 | 
				
			||||||
 | 
					          ind += 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        case MemSubmap(size, submap) => {
 | 
				
			||||||
 | 
					          if (!startOpt.isEmpty) base = startOpt.get
 | 
				
			||||||
 | 
					          val subpairs = genPairs(submap).map {
 | 
				
			||||||
 | 
					            case (subname, AddrHashMapEntry(subind, subbase, subsize)) =>
 | 
				
			||||||
 | 
					              (name + ":" + subname,
 | 
				
			||||||
 | 
					                AddrHashMapEntry(ind + subind, base + subbase, subsize))
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          pairs = subpairs ++ pairs
 | 
				
			||||||
 | 
					          ind += subpairs.size
 | 
				
			||||||
 | 
					          base += size
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pairs
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for ((name, ind) <- genPairs(addrmap)) { mapping(name) = ind }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def nEntries: Int = mapping.size
 | 
				
			||||||
 | 
					  def apply(name: String): AddrHashMapEntry = mapping(name)
 | 
				
			||||||
 | 
					  def get(name: String): Option[AddrHashMapEntry] = mapping.get(name)
 | 
				
			||||||
 | 
					  def sortedEntries(): Seq[(String, BigInt, BigInt)] = {
 | 
				
			||||||
 | 
					    val arr = new Array[(String, BigInt, BigInt)](mapping.size)
 | 
				
			||||||
 | 
					    mapping.foreach { case (name, AddrHashMapEntry(port, base, size)) =>
 | 
				
			||||||
 | 
					      arr(port) = (name, base, size)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    arr.toSeq
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case object NASTIAddrMap extends Field[AddrMap]
 | 
				
			||||||
 | 
					case object NASTIAddrHashMap extends Field[AddrHashMap]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTIInterconnectIO(val nMasters: Int, val nSlaves: Int) extends Bundle {
 | 
				
			||||||
 | 
					  /* This is a bit confusing. The interconnect is a slave to the masters and
 | 
				
			||||||
 | 
					   * a master to the slaves. Hence why the declarations seem to be backwards. */
 | 
				
			||||||
 | 
					  val masters = Vec.fill(nMasters) { new NASTISlaveIO }
 | 
				
			||||||
 | 
					  val slaves = Vec.fill(nSlaves) { new NASTIMasterIO }
 | 
				
			||||||
 | 
					  override def cloneType =
 | 
				
			||||||
 | 
					    new NASTIInterconnectIO(nMasters, nSlaves).asInstanceOf[this.type]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class NASTIInterconnect extends NASTIModule {
 | 
				
			||||||
 | 
					  val nMasters: Int
 | 
				
			||||||
 | 
					  val nSlaves: Int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lazy val io = new NASTIInterconnectIO(nMasters, nSlaves)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTIRecursiveInterconnect(
 | 
				
			||||||
 | 
					    val nMasters: Int, val nSlaves: Int,
 | 
				
			||||||
 | 
					    addrmap: AddrMap, base: BigInt = 0) extends NASTIInterconnect {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private def mapCountSlaves(addrmap: AddrMap): Int = {
 | 
				
			||||||
 | 
					    addrmap.map {
 | 
				
			||||||
 | 
					      case (_, _, MemSize(_)) => 1
 | 
				
			||||||
 | 
					      case (_, _, MemSubmap(_, submap)) => mapCountSlaves(submap)
 | 
				
			||||||
 | 
					    }.reduceLeft(_ + _)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var lastEnd = base
 | 
				
			||||||
 | 
					  var slaveInd = 0
 | 
				
			||||||
 | 
					  val levelSize = addrmap.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val realAddrMap = new ArraySeq[(BigInt, BigInt)](addrmap.size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addrmap.zipWithIndex.foreach { case ((_, startOpt, region), i) =>
 | 
				
			||||||
 | 
					    val start = startOpt.getOrElse(lastEnd)
 | 
				
			||||||
 | 
					    val size = region.size
 | 
				
			||||||
 | 
					    realAddrMap(i) = (start, size)
 | 
				
			||||||
 | 
					    lastEnd = start + size
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val flatSlaves = if (nMasters > 1) {
 | 
				
			||||||
 | 
					    val xbar = Module(new NASTICrossbar(nMasters, levelSize, realAddrMap))
 | 
				
			||||||
 | 
					    xbar.io.masters <> io.masters
 | 
				
			||||||
 | 
					    xbar.io.slaves
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    val router = Module(new NASTIRouter(realAddrMap))
 | 
				
			||||||
 | 
					    router.io.master <> io.masters.head
 | 
				
			||||||
 | 
					    router.io.slave
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addrmap.zip(realAddrMap).zipWithIndex.foreach {
 | 
				
			||||||
 | 
					    case (((_, _, region), (start, size)), i) => {
 | 
				
			||||||
 | 
					      region match {
 | 
				
			||||||
 | 
					        case MemSize(_) =>
 | 
				
			||||||
 | 
					          io.slaves(slaveInd) <> flatSlaves(i)
 | 
				
			||||||
 | 
					          slaveInd += 1
 | 
				
			||||||
 | 
					        case MemSubmap(_, submap) =>
 | 
				
			||||||
 | 
					          val subSlaves = mapCountSlaves(submap)
 | 
				
			||||||
 | 
					          val ic = Module(new NASTIRecursiveInterconnect(
 | 
				
			||||||
 | 
					            1, subSlaves, submap, start))
 | 
				
			||||||
 | 
					          ic.io.masters.head <> flatSlaves(i)
 | 
				
			||||||
 | 
					          io.slaves.drop(slaveInd).take(subSlaves).zip(ic.io.slaves).foreach {
 | 
				
			||||||
 | 
					            case (s, m) => s <> m
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          slaveInd += subSlaves
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NASTITopInterconnect extends NASTIInterconnect {
 | 
				
			||||||
 | 
					  val nMasters = params(NASTINMasters)
 | 
				
			||||||
 | 
					  val nSlaves = params(NASTINSlaves)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bigIntPow2(params(MMIOBase))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  val temp = Module(new NASTIRecursiveInterconnect(
 | 
				
			||||||
 | 
					    nMasters, nSlaves, params(NASTIAddrMap)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  temp.io.masters.zip(io.masters).foreach { case (t, i) =>
 | 
				
			||||||
 | 
					    t.ar <> i.ar
 | 
				
			||||||
 | 
					    t.aw <> i.aw
 | 
				
			||||||
 | 
					    // this queue is necessary to break up the aw - w dependence
 | 
				
			||||||
 | 
					    // introduced by the TileLink -> NASTI converter
 | 
				
			||||||
 | 
					    t.w <> Queue(i.w)
 | 
				
			||||||
 | 
					    i.b <> t.b
 | 
				
			||||||
 | 
					    i.r <> t.r
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  //temp.io.masters <> io.masters
 | 
				
			||||||
 | 
					  io.slaves <> temp.io.slaves
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user