2015-08-06 12:48:35 -07:00
|
|
|
/// See LICENSE for license details.
|
2015-07-29 18:02:58 -07:00
|
|
|
|
|
|
|
package junctions
|
|
|
|
import Chisel._
|
|
|
|
import scala.math.max
|
2015-08-06 12:48:35 -07:00
|
|
|
import scala.collection.mutable.ArraySeq
|
|
|
|
import scala.collection.mutable.HashMap
|
2015-07-29 18:02:58 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
case object NastiBitWidths extends Field[NastiParameters]
|
|
|
|
case object NastiAddrMap extends Field[AddrMap]
|
2015-08-06 12:48:35 -07:00
|
|
|
case object MMIOBase extends Field[BigInt]
|
2015-07-29 18:02:58 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
case class NastiParameters(dataBits: Int, addrBits: Int, idBits: Int)
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
trait HasNastiParameters {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val external = p(NastiBitWidths)
|
|
|
|
val nastiXDataBits = external.dataBits
|
2015-07-29 18:02:58 -07:00
|
|
|
val nastiWStrobeBits = nastiXDataBits / 8
|
2015-10-02 14:19:51 -07:00
|
|
|
val nastiXAddrBits = external.addrBits
|
|
|
|
val nastiWIdBits = external.idBits
|
|
|
|
val nastiRIdBits = external.idBits
|
2015-07-29 18:02:58 -07:00
|
|
|
val nastiXIdBits = max(nastiWIdBits, nastiRIdBits)
|
|
|
|
val nastiXUserBits = 1
|
|
|
|
val nastiAWUserBits = nastiXUserBits
|
|
|
|
val nastiWUserBits = nastiXUserBits
|
|
|
|
val nastiBUserBits = nastiXUserBits
|
|
|
|
val nastiARUserBits = nastiXUserBits
|
|
|
|
val nastiRUserBits = nastiXUserBits
|
|
|
|
val nastiXLenBits = 8
|
|
|
|
val nastiXSizeBits = 3
|
|
|
|
val nastiXBurstBits = 2
|
|
|
|
val nastiXCacheBits = 4
|
|
|
|
val nastiXProtBits = 3
|
|
|
|
val nastiXQosBits = 4
|
|
|
|
val nastiXRegionBits = 4
|
|
|
|
val nastiXRespBits = 2
|
|
|
|
|
|
|
|
def bytesToXSize(bytes: UInt) = MuxLookup(bytes, UInt("b111"), Array(
|
|
|
|
UInt(1) -> UInt(0),
|
|
|
|
UInt(2) -> UInt(1),
|
|
|
|
UInt(4) -> UInt(2),
|
|
|
|
UInt(8) -> UInt(3),
|
|
|
|
UInt(16) -> UInt(4),
|
|
|
|
UInt(32) -> UInt(5),
|
|
|
|
UInt(64) -> UInt(6),
|
|
|
|
UInt(128) -> UInt(7)))
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
abstract class NastiModule extends Module with HasNastiParameters
|
|
|
|
abstract class NastiBundle(implicit val p: Parameters) extends Bundle with HasNastiParameters {
|
|
|
|
override def cloneType = this.getClass.getConstructors.head.newInstance(p).asInstanceOf[this.type]
|
2015-07-29 18:02:58 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
abstract class NastiChannel(implicit p: Parameters) extends NastiBundle()(p)
|
|
|
|
abstract class NastiMasterToSlaveChannel(implicit p: Parameters) extends NastiChannel()(p)
|
|
|
|
abstract class NastiSlaveToMasterChannel(implicit p: Parameters) extends NastiChannel()(p)
|
|
|
|
|
|
|
|
trait HasNastiMetadata extends HasNastiParameters {
|
2015-07-29 18:02:58 -07:00
|
|
|
val addr = UInt(width = nastiXAddrBits)
|
|
|
|
val len = UInt(width = nastiXLenBits)
|
|
|
|
val size = UInt(width = nastiXSizeBits)
|
|
|
|
val burst = UInt(width = nastiXBurstBits)
|
|
|
|
val lock = Bool()
|
|
|
|
val cache = UInt(width = nastiXCacheBits)
|
|
|
|
val prot = UInt(width = nastiXProtBits)
|
|
|
|
val qos = UInt(width = nastiXQosBits)
|
|
|
|
val region = UInt(width = nastiXRegionBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
trait HasNastiData extends HasNastiParameters {
|
2015-07-29 18:02:58 -07:00
|
|
|
val data = UInt(width = nastiXDataBits)
|
|
|
|
val last = Bool()
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiIO(implicit p: Parameters) extends NastiBundle()(p) {
|
|
|
|
val aw = Decoupled(new NastiWriteAddressChannel)
|
|
|
|
val w = Decoupled(new NastiWriteDataChannel)
|
|
|
|
val b = Decoupled(new NastiWriteResponseChannel).flip
|
|
|
|
val ar = Decoupled(new NastiReadAddressChannel)
|
|
|
|
val r = Decoupled(new NastiReadDataChannel).flip
|
|
|
|
}
|
|
|
|
|
|
|
|
class NastiAddressChannel(implicit p: Parameters) extends NastiMasterToSlaveChannel()(p)
|
|
|
|
with HasNastiMetadata
|
2015-07-29 18:02:58 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiResponseChannel(implicit p: Parameters) extends NastiSlaveToMasterChannel()(p) {
|
2015-07-29 18:02:58 -07:00
|
|
|
val resp = UInt(width = nastiXRespBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiWriteAddressChannel(implicit p: Parameters) extends NastiAddressChannel()(p) {
|
2015-07-29 18:02:58 -07:00
|
|
|
val id = UInt(width = nastiWIdBits)
|
|
|
|
val user = UInt(width = nastiAWUserBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiWriteDataChannel(implicit p: Parameters) extends NastiMasterToSlaveChannel()(p)
|
|
|
|
with HasNastiData {
|
2015-07-29 18:02:58 -07:00
|
|
|
val strb = UInt(width = nastiWStrobeBits)
|
|
|
|
val user = UInt(width = nastiWUserBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiWriteResponseChannel(implicit p: Parameters) extends NastiResponseChannel()(p) {
|
2015-07-29 18:02:58 -07:00
|
|
|
val id = UInt(width = nastiWIdBits)
|
|
|
|
val user = UInt(width = nastiBUserBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiReadAddressChannel(implicit p: Parameters) extends NastiAddressChannel()(p) {
|
2015-07-29 18:02:58 -07:00
|
|
|
val id = UInt(width = nastiRIdBits)
|
|
|
|
val user = UInt(width = nastiARUserBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiReadDataChannel(implicit p: Parameters) extends NastiResponseChannel()(p)
|
|
|
|
with HasNastiData {
|
2015-07-29 18:02:58 -07:00
|
|
|
val id = UInt(width = nastiRIdBits)
|
|
|
|
val user = UInt(width = nastiRUserBits)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object NastiWriteAddressChannel {
|
|
|
|
def apply(id: UInt, addr: UInt, size: UInt, len: UInt = UInt(0))(implicit p: Parameters) = {
|
|
|
|
val aw = Wire(new NastiWriteAddressChannel)
|
2015-09-10 17:32:40 -07:00
|
|
|
aw.id := id
|
|
|
|
aw.addr := addr
|
|
|
|
aw.len := len
|
|
|
|
aw.size := size
|
|
|
|
aw.burst := UInt("b01")
|
|
|
|
aw.lock := Bool(false)
|
|
|
|
aw.cache := UInt("b0000")
|
|
|
|
aw.prot := UInt("b000")
|
|
|
|
aw.qos := UInt("b0000")
|
|
|
|
aw.region := UInt("b0000")
|
|
|
|
aw.user := UInt(0)
|
|
|
|
aw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object NastiReadAddressChannel {
|
|
|
|
def apply(id: UInt, addr: UInt, size: UInt, len: UInt = UInt(0))(implicit p: Parameters) = {
|
|
|
|
val ar = Wire(new NastiReadAddressChannel)
|
2015-09-10 17:32:40 -07:00
|
|
|
ar.id := id
|
|
|
|
ar.addr := addr
|
|
|
|
ar.len := len
|
|
|
|
ar.size := size
|
|
|
|
ar.burst := UInt("b01")
|
|
|
|
ar.lock := Bool(false)
|
|
|
|
ar.cache := UInt(0)
|
|
|
|
ar.prot := UInt(0)
|
|
|
|
ar.qos := UInt(0)
|
|
|
|
ar.region := UInt(0)
|
|
|
|
ar.user := UInt(0)
|
|
|
|
ar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object NastiWriteDataChannel {
|
|
|
|
def apply(data: UInt, last: Bool = Bool(true))(implicit p: Parameters): NastiWriteDataChannel = {
|
|
|
|
val w = Wire(new NastiWriteDataChannel)
|
|
|
|
w.strb := Fill(w.nastiWStrobeBits, UInt(1, 1))
|
2015-09-10 17:32:40 -07:00
|
|
|
w.data := data
|
|
|
|
w.last := last
|
|
|
|
w.user := UInt(0)
|
|
|
|
w
|
|
|
|
}
|
2015-10-02 14:19:51 -07:00
|
|
|
def apply(data: UInt, strb: UInt, last: Bool)
|
|
|
|
(implicit p: Parameters): NastiWriteDataChannel = {
|
|
|
|
val w = apply(data, last)
|
|
|
|
w.strb := strb
|
|
|
|
w
|
|
|
|
}
|
2015-09-10 17:32:40 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object NastiReadDataChannel {
|
|
|
|
def apply(id: UInt, data: UInt, last: Bool = Bool(true), resp: UInt = UInt(0))(
|
|
|
|
implicit p: Parameters) = {
|
|
|
|
val r = Wire(new NastiReadDataChannel)
|
2015-09-10 17:32:40 -07:00
|
|
|
r.id := id
|
|
|
|
r.data := data
|
|
|
|
r.last := last
|
|
|
|
r.resp := resp
|
|
|
|
r.user := UInt(0)
|
|
|
|
r
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object NastiWriteResponseChannel {
|
|
|
|
def apply(id: UInt, resp: UInt = UInt(0))(implicit p: Parameters) = {
|
|
|
|
val b = Wire(new NastiWriteResponseChannel)
|
2015-09-10 17:32:40 -07:00
|
|
|
b.id := id
|
|
|
|
b.resp := resp
|
|
|
|
b.user := UInt(0)
|
|
|
|
b
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class MemIONastiIOConverter(cacheBlockOffsetBits: Int)(implicit val p: Parameters) extends MIFModule
|
|
|
|
with HasNastiParameters {
|
2015-07-29 18:02:58 -07:00
|
|
|
val io = new Bundle {
|
2015-10-02 14:19:51 -07:00
|
|
|
val nasti = (new NastiIO).flip
|
2015-07-29 18:02:58 -07:00
|
|
|
val mem = new MemIO
|
|
|
|
}
|
|
|
|
|
|
|
|
require(mifDataBits == nastiXDataBits, "Data sizes between LLC and MC don't agree")
|
|
|
|
val (mif_cnt_out, mif_wrap_out) = Counter(io.mem.resp.fire(), mifDataBeats)
|
2015-08-06 12:46:32 -07:00
|
|
|
|
2015-09-10 17:55:10 -07:00
|
|
|
assert(!io.nasti.aw.valid || io.nasti.aw.bits.size === UInt(log2Up(mifDataBits/8)),
|
2015-10-02 14:19:51 -07:00
|
|
|
"Nasti data size does not match MemIO data size")
|
2015-09-10 17:55:10 -07:00
|
|
|
assert(!io.nasti.ar.valid || io.nasti.ar.bits.size === UInt(log2Up(mifDataBits/8)),
|
2015-10-02 14:19:51 -07:00
|
|
|
"Nasti data size does not match MemIO data size")
|
2015-09-10 17:55:10 -07:00
|
|
|
assert(!io.nasti.aw.valid || io.nasti.aw.bits.len === UInt(mifDataBeats - 1),
|
2015-10-02 14:19:51 -07:00
|
|
|
"Nasti length does not match number of MemIO beats")
|
2015-09-10 17:55:10 -07:00
|
|
|
assert(!io.nasti.ar.valid || io.nasti.ar.bits.len === UInt(mifDataBeats - 1),
|
2015-10-02 14:19:51 -07:00
|
|
|
"Nasti length does not match number of MemIO beats")
|
2015-09-10 17:55:10 -07:00
|
|
|
|
2015-08-06 12:46:32 -07:00
|
|
|
// according to the spec, we can't send b until the last transfer on w
|
|
|
|
val b_ok = Reg(init = Bool(true))
|
|
|
|
when (io.nasti.aw.fire()) { b_ok := Bool(false) }
|
|
|
|
when (io.nasti.w.fire() && io.nasti.w.bits.last) { b_ok := Bool(true) }
|
|
|
|
|
|
|
|
val id_q = Module(new Queue(UInt(width = nastiWIdBits), 2))
|
|
|
|
id_q.io.enq.valid := io.nasti.aw.valid
|
|
|
|
id_q.io.enq.bits := io.nasti.aw.bits.id
|
|
|
|
id_q.io.deq.ready := io.nasti.b.ready && b_ok
|
|
|
|
|
2015-07-29 18:02:58 -07:00
|
|
|
io.mem.req_cmd.bits.addr := Mux(io.nasti.aw.valid, io.nasti.aw.bits.addr, io.nasti.ar.bits.addr) >>
|
|
|
|
UInt(cacheBlockOffsetBits)
|
|
|
|
io.mem.req_cmd.bits.tag := Mux(io.nasti.aw.valid, io.nasti.aw.bits.id, io.nasti.ar.bits.id)
|
|
|
|
io.mem.req_cmd.bits.rw := io.nasti.aw.valid
|
2015-08-06 12:46:32 -07:00
|
|
|
io.mem.req_cmd.valid := (io.nasti.aw.valid && id_q.io.enq.ready) || io.nasti.ar.valid
|
2015-07-29 18:02:58 -07:00
|
|
|
io.nasti.ar.ready := io.mem.req_cmd.ready && !io.nasti.aw.valid
|
2015-08-06 12:46:32 -07:00
|
|
|
io.nasti.aw.ready := io.mem.req_cmd.ready && id_q.io.enq.ready
|
2015-07-29 18:02:58 -07:00
|
|
|
|
2015-08-06 12:46:32 -07:00
|
|
|
io.nasti.b.valid := id_q.io.deq.valid && b_ok
|
|
|
|
io.nasti.b.bits.id := id_q.io.deq.bits
|
2015-07-29 18:02:58 -07:00
|
|
|
io.nasti.b.bits.resp := UInt(0)
|
|
|
|
|
|
|
|
io.nasti.w.ready := io.mem.req_data.ready
|
|
|
|
io.mem.req_data.valid := io.nasti.w.valid
|
|
|
|
io.mem.req_data.bits.data := io.nasti.w.bits.data
|
|
|
|
assert(!io.nasti.w.valid || io.nasti.w.bits.strb.andR, "MemIO must write full cache line")
|
|
|
|
|
|
|
|
io.nasti.r.valid := io.mem.resp.valid
|
|
|
|
io.nasti.r.bits.data := io.mem.resp.bits.data
|
|
|
|
io.nasti.r.bits.last := mif_wrap_out
|
|
|
|
io.nasti.r.bits.id := io.mem.resp.bits.tag
|
|
|
|
io.nasti.r.bits.resp := UInt(0)
|
|
|
|
io.mem.resp.ready := io.nasti.r.ready
|
|
|
|
}
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-09-10 17:33:48 -07:00
|
|
|
/** Arbitrate among arbN masters requesting to a single slave */
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiArbiter(val arbN: Int)(implicit val p: Parameters) extends NastiModule {
|
2015-08-06 12:48:35 -07:00
|
|
|
val io = new Bundle {
|
2015-10-02 14:19:51 -07:00
|
|
|
val master = Vec(new NastiIO, arbN).flip
|
|
|
|
val slave = new NastiIO
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (arbN > 1) {
|
|
|
|
val arbIdBits = log2Up(arbN)
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
val ar_arb = Module(new RRArbiter(new NastiReadAddressChannel, arbN))
|
|
|
|
val aw_arb = Module(new RRArbiter(new NastiWriteAddressChannel, arbN))
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
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
|
2015-09-25 11:03:24 -07:00
|
|
|
|
|
|
|
io.slave.aw.bits <> aw_arb.io.out.bits
|
|
|
|
io.slave.aw.valid := aw_arb.io.out.valid && w_done
|
2015-08-06 12:48:35 -07:00
|
|
|
aw_arb.io.out.ready := io.slave.aw.ready && w_done
|
|
|
|
|
|
|
|
} else { io.slave <> io.master.head }
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
/** Locking RR arbiter for Nasti read data channel
|
2015-09-10 17:33:48 -07:00
|
|
|
* Arbiter locks until last message in channel is sent */
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiReadDataArbiter(arbN: Int)(implicit val p: Parameters) extends NastiModule {
|
2015-08-06 12:48:35 -07:00
|
|
|
val io = new Bundle {
|
2015-10-02 14:19:51 -07:00
|
|
|
val in = Vec(Decoupled(new NastiReadDataChannel), arbN).flip
|
|
|
|
val out = Decoupled(new NastiReadDataChannel)
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiErrorSlave(implicit val p: Parameters) extends NastiModule {
|
|
|
|
val io = (new NastiIO).flip
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-09-18 09:42:41 -07:00
|
|
|
when (io.ar.fire()) { printf("Invalid read address %x\n", io.ar.bits.addr) }
|
|
|
|
when (io.aw.fire()) { printf("Invalid write address %x\n", io.aw.bits.addr) }
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
val r_queue = Module(new Queue(new NastiReadAddressChannel, 2))
|
2015-09-22 09:42:57 -07:00
|
|
|
r_queue.io.enq <> io.ar
|
|
|
|
|
|
|
|
val responding = Reg(init = Bool(false))
|
|
|
|
val beats_left = Reg(init = UInt(0, nastiXLenBits))
|
|
|
|
|
|
|
|
when (!responding && r_queue.io.deq.valid) {
|
|
|
|
responding := Bool(true)
|
|
|
|
beats_left := r_queue.io.deq.bits.len
|
|
|
|
}
|
|
|
|
|
|
|
|
io.r.valid := r_queue.io.deq.valid && responding
|
|
|
|
io.r.bits.id := r_queue.io.deq.bits.id
|
|
|
|
io.r.bits.data := UInt(0)
|
2015-08-06 12:48:35 -07:00
|
|
|
io.r.bits.resp := Bits("b11")
|
2015-09-22 09:42:57 -07:00
|
|
|
io.r.bits.last := beats_left === UInt(0)
|
|
|
|
|
|
|
|
r_queue.io.deq.ready := io.r.fire() && io.r.bits.last
|
|
|
|
|
|
|
|
when (io.r.fire()) {
|
|
|
|
when (beats_left === UInt(0)) {
|
|
|
|
responding := Bool(false)
|
|
|
|
} .otherwise {
|
|
|
|
beats_left := beats_left - UInt(0)
|
|
|
|
}
|
|
|
|
}
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
/** Take a single Nasti master and route its requests to various slaves
|
2015-09-10 17:33:48 -07:00
|
|
|
* @param addrmap a sequence of base address + memory size pairs,
|
|
|
|
* on for each slave interface */
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiRouter(addrmap: Seq[(BigInt, BigInt)])(implicit val p: Parameters) extends NastiModule {
|
2015-08-06 12:48:35 -07:00
|
|
|
val nSlaves = addrmap.size
|
|
|
|
|
|
|
|
val io = new Bundle {
|
2015-10-02 14:19:51 -07:00
|
|
|
val master = (new NastiIO).flip
|
|
|
|
val slave = Vec(new NastiIO, nSlaves)
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
val err_slave = Module(new NastiErrorSlave)
|
2015-08-06 12:48:35 -07:00
|
|
|
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
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
val b_arb = Module(new RRArbiter(new NastiWriteResponseChannel, nSlaves + 1))
|
|
|
|
val r_arb = Module(new NastiReadDataArbiter(nSlaves + 1))
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
/** Crossbar between multiple Nasti masters and slaves
|
|
|
|
* @param nMasters the number of Nasti masters
|
|
|
|
* @param nSlaves the number of Nasti slaves
|
2015-09-10 17:33:48 -07:00
|
|
|
* @param addrmap a sequence of base - size pairs;
|
|
|
|
* size of addrmap should be nSlaves */
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiCrossbar(nMasters: Int, nSlaves: Int, addrmap: Seq[(BigInt, BigInt)])
|
|
|
|
(implicit val p: Parameters) extends NastiModule {
|
2015-08-06 12:48:35 -07:00
|
|
|
val io = new Bundle {
|
2015-10-02 14:19:51 -07:00
|
|
|
val masters = Vec(new NastiIO, nMasters).flip
|
|
|
|
val slaves = Vec(new NastiIO, nSlaves)
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
val routers = Vec.fill(nMasters) { Module(new NastiRouter(addrmap)).io }
|
|
|
|
val arbiters = Vec.fill(nSlaves) { Module(new NastiArbiter(nMasters)).io }
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
object AddrMapConsts {
|
2015-09-22 09:43:22 -07:00
|
|
|
val R = 0x4
|
|
|
|
val W = 0x2
|
|
|
|
val X = 0x1
|
|
|
|
val RW = R | W
|
|
|
|
val RX = R | X
|
|
|
|
val RWX = R | W | X
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
2015-10-02 14:19:51 -07:00
|
|
|
|
|
|
|
class AddrMapProt extends Bundle {
|
|
|
|
val r = Bool()
|
|
|
|
val w = Bool()
|
|
|
|
val x = Bool()
|
|
|
|
}
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
abstract class MemRegion { def size: BigInt }
|
|
|
|
|
2015-09-22 09:43:22 -07:00
|
|
|
case class MemSize(size: BigInt, prot: Int) extends MemRegion
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
case class MemSubmap(size: BigInt, entries: AddrMap) extends MemRegion
|
|
|
|
|
|
|
|
//object Submap {
|
|
|
|
// def apply(size: BigInt, entries: AddrMapEntry*) =
|
|
|
|
// new MemSubmap(size, entries)
|
|
|
|
//}
|
|
|
|
|
|
|
|
case class AddrMapEntry(name: String, start: Option[BigInt], region: MemRegion)
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-09-22 09:43:22 -07:00
|
|
|
case class AddrHashMapEntry(port: Int, start: BigInt, size: BigInt, prot: Int)
|
2015-08-06 12:48:35 -07:00
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class AddrMap(entries: Seq[AddrMapEntry]) extends scala.collection.IndexedSeq[AddrMapEntry] {
|
|
|
|
|
|
|
|
def apply(index: Int): AddrMapEntry = entries(index)
|
|
|
|
|
|
|
|
def length: Int = entries.size
|
|
|
|
|
|
|
|
def countSlaves: Int = {
|
|
|
|
this map { entry: AddrMapEntry => entry.region match {
|
|
|
|
case MemSize(_, _) => 1
|
|
|
|
case MemSubmap(_, submap) => submap.countSlaves
|
|
|
|
}} reduceLeft(_ + _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object AddrMap {
|
|
|
|
def apply(elems: AddrMapEntry*): AddrMap = new AddrMap(elems)
|
2015-09-22 09:43:22 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class AddrHashMap(addrmap: AddrMap) {
|
2015-08-06 12:48:35 -07:00
|
|
|
val mapping = new HashMap[String, AddrHashMapEntry]
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
private def genPairs(am: AddrMap): Seq[(String, AddrHashMapEntry)] = {
|
2015-08-06 12:48:35 -07:00
|
|
|
var ind = 0
|
|
|
|
var base = BigInt(0)
|
|
|
|
var pairs = Seq[(String, AddrHashMapEntry)]()
|
2015-10-02 14:19:51 -07:00
|
|
|
am.foreach { case AddrMapEntry(name, startOpt, region) =>
|
2015-08-06 12:48:35 -07:00
|
|
|
region match {
|
2015-09-22 09:43:22 -07:00
|
|
|
case MemSize(size, prot) => {
|
2015-08-06 12:48:35 -07:00
|
|
|
if (!startOpt.isEmpty) base = startOpt.get
|
2015-09-22 09:43:22 -07:00
|
|
|
pairs = (name, AddrHashMapEntry(ind, base, size, prot)) +: pairs
|
2015-08-06 12:48:35 -07:00
|
|
|
base += size
|
|
|
|
ind += 1
|
|
|
|
}
|
|
|
|
case MemSubmap(size, submap) => {
|
|
|
|
if (!startOpt.isEmpty) base = startOpt.get
|
|
|
|
val subpairs = genPairs(submap).map {
|
2015-09-22 09:43:22 -07:00
|
|
|
case (subname, AddrHashMapEntry(subind, subbase, subsize, prot)) =>
|
2015-08-06 12:48:35 -07:00
|
|
|
(name + ":" + subname,
|
2015-09-22 09:43:22 -07:00
|
|
|
AddrHashMapEntry(ind + subind, base + subbase, subsize, prot))
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
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)
|
2015-09-22 09:43:22 -07:00
|
|
|
def sortedEntries(): Seq[(String, BigInt, BigInt, Int)] = {
|
|
|
|
val arr = new Array[(String, BigInt, BigInt, Int)](mapping.size)
|
|
|
|
mapping.foreach { case (name, AddrHashMapEntry(port, base, size, prot)) =>
|
|
|
|
arr(port) = (name, base, size, prot)
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
arr.toSeq
|
|
|
|
}
|
2015-09-22 09:43:22 -07:00
|
|
|
|
|
|
|
def isValid(addr: UInt): Bool = {
|
|
|
|
sortedEntries().map { case (_, base, size, _) =>
|
|
|
|
addr >= UInt(base) && addr < UInt(base + size)
|
|
|
|
}.reduceLeft(_ || _)
|
|
|
|
}
|
|
|
|
|
|
|
|
def getProt(addr: UInt): AddrMapProt = {
|
|
|
|
Mux1H(sortedEntries().map { case (_, base, size, prot) =>
|
|
|
|
(addr >= UInt(base) && addr < UInt(base + size),
|
|
|
|
new AddrMapProt().fromBits(Bits(prot, 3)))
|
|
|
|
})
|
|
|
|
}
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiInterconnectIO(val nMasters: Int, val nSlaves: Int)
|
|
|
|
(implicit p: Parameters) extends Bundle {
|
2015-08-06 12:48:35 -07:00
|
|
|
/* 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. */
|
2015-10-02 14:19:51 -07:00
|
|
|
val masters = Vec(new NastiIO, nMasters).flip
|
|
|
|
val slaves = Vec(new NastiIO, nSlaves)
|
2015-08-06 12:48:35 -07:00
|
|
|
override def cloneType =
|
2015-10-02 14:19:51 -07:00
|
|
|
new NastiInterconnectIO(nMasters, nSlaves).asInstanceOf[this.type]
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
abstract class NastiInterconnect extends NastiModule {
|
2015-08-06 12:48:35 -07:00
|
|
|
val nMasters: Int
|
|
|
|
val nSlaves: Int
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
lazy val io = new NastiInterconnectIO(nMasters, nSlaves)
|
2015-08-06 12:48:35 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiRecursiveInterconnect(
|
|
|
|
val nMasters: Int,
|
|
|
|
val nSlaves: Int,
|
|
|
|
addrmap: AddrMap,
|
|
|
|
base: BigInt = 0)
|
|
|
|
(implicit val p: Parameters) extends NastiInterconnect {
|
2015-08-06 12:48:35 -07:00
|
|
|
var lastEnd = base
|
|
|
|
var slaveInd = 0
|
|
|
|
val levelSize = addrmap.size
|
|
|
|
val realAddrMap = new ArraySeq[(BigInt, BigInt)](addrmap.size)
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
addrmap.zipWithIndex.foreach { case (AddrMapEntry(_, startOpt, region), i) =>
|
2015-08-06 12:48:35 -07:00
|
|
|
val start = startOpt.getOrElse(lastEnd)
|
|
|
|
val size = region.size
|
|
|
|
realAddrMap(i) = (start, size)
|
|
|
|
lastEnd = start + size
|
|
|
|
}
|
|
|
|
|
|
|
|
val flatSlaves = if (nMasters > 1) {
|
2015-10-02 14:19:51 -07:00
|
|
|
val xbar = Module(new NastiCrossbar(nMasters, levelSize, realAddrMap))
|
2015-08-06 12:48:35 -07:00
|
|
|
xbar.io.masters <> io.masters
|
|
|
|
xbar.io.slaves
|
|
|
|
} else {
|
2015-10-02 14:19:51 -07:00
|
|
|
val router = Module(new NastiRouter(realAddrMap))
|
2015-08-06 12:48:35 -07:00
|
|
|
router.io.master <> io.masters.head
|
|
|
|
router.io.slave
|
|
|
|
}
|
|
|
|
|
|
|
|
addrmap.zip(realAddrMap).zipWithIndex.foreach {
|
2015-10-02 14:19:51 -07:00
|
|
|
case ((entry, (start, size)), i) => {
|
|
|
|
entry.region match {
|
2015-09-22 09:43:22 -07:00
|
|
|
case MemSize(_, _) =>
|
2015-08-06 12:48:35 -07:00
|
|
|
io.slaves(slaveInd) <> flatSlaves(i)
|
|
|
|
slaveInd += 1
|
|
|
|
case MemSubmap(_, submap) =>
|
2015-10-02 14:19:51 -07:00
|
|
|
val subSlaves = submap.countSlaves
|
|
|
|
val ic = Module(new NastiRecursiveInterconnect(1, subSlaves, submap, start))
|
2015-08-06 12:48:35 -07:00
|
|
|
ic.io.masters.head <> flatSlaves(i)
|
|
|
|
io.slaves.drop(slaveInd).take(subSlaves).zip(ic.io.slaves).foreach {
|
|
|
|
case (s, m) => s <> m
|
|
|
|
}
|
|
|
|
slaveInd += subSlaves
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 14:19:51 -07:00
|
|
|
class NastiTopInterconnect(val nMasters: Int, val nSlaves: Int)
|
|
|
|
(implicit val p: Parameters) extends NastiInterconnect {
|
|
|
|
val temp = Module(new NastiRecursiveInterconnect(nMasters, nSlaves, p(NastiAddrMap)))
|
2015-08-06 12:48:35 -07:00
|
|
|
|
|
|
|
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
|
2015-10-02 14:19:51 -07:00
|
|
|
// introduced by the TileLink -> Nasti converter
|
2015-08-06 12:48:35 -07:00
|
|
|
t.w <> Queue(i.w)
|
|
|
|
i.b <> t.b
|
|
|
|
i.r <> t.r
|
|
|
|
}
|
|
|
|
//temp.io.masters <> io.masters
|
|
|
|
io.slaves <> temp.io.slaves
|
|
|
|
}
|