dual read port srams
This commit is contained in:
@@ -2,7 +2,7 @@ package radiance.memory
|
|||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
import freechips.rocketchip.diplomacy.{AddressSet, TransferSizes, IdRange}
|
import freechips.rocketchip.diplomacy.{AddressSet, TransferSizes, IdRange, BufferParams}
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util.BundleField
|
import freechips.rocketchip.util.BundleField
|
||||||
import org.chipsalliance.cde.config.Parameters
|
import org.chipsalliance.cde.config.Parameters
|
||||||
@@ -77,23 +77,29 @@ class DuplicatorNode(override val name: String = "dup")
|
|||||||
sourceEnq.bits := nodeIn.a.bits.source
|
sourceEnq.bits := nodeIn.a.bits.source
|
||||||
|
|
||||||
val idQueue = Queue(sourceEnq, entries = 4, pipe = false, flow = false)
|
val idQueue = Queue(sourceEnq, entries = 4, pipe = false, flow = false)
|
||||||
|
|
||||||
val srcMatch = nodeOuts.map(_.d.bits.source(inSourceWidth - 1, 0) === idQueue.bits)
|
val srcMatch = nodeOuts.map(_.d.bits.source(inSourceWidth - 1, 0) === idQueue.bits)
|
||||||
idQueue.ready := nodeIn.d.ready && srcMatch.reduce(_ || _)
|
idQueue.ready := nodeIn.d.fire
|
||||||
|
|
||||||
assert(sourceEnq.fire === nodeIn.a.fire)
|
assert(sourceEnq.fire === nodeIn.a.fire)
|
||||||
assert(idQueue.fire === nodeIn.d.fire)
|
assert(idQueue.fire === nodeIn.d.fire)
|
||||||
|
|
||||||
(nodeOuts zip srcMatch).foreach { case (o, m) =>
|
(nodeOuts lazyZip srcMatch lazyZip Seq(0, inSourceEnd)).foreach { case (o, m, p) =>
|
||||||
o.a.bits := nodeIn.a.bits
|
o.a.bits := nodeIn.a.bits
|
||||||
o.a.bits.source := nodeIn.a.bits.source | inSourceEnd.U
|
o.a.bits.source := nodeIn.a.bits.source | p.U
|
||||||
o.a.valid := nodeIn.a.valid
|
o.a.valid := nodeIn.a.valid
|
||||||
nodeIn.d.bits := o.d.bits
|
|
||||||
nodeIn.d.bits.source := o.d.bits.source(inSourceWidth - 1, 0)
|
|
||||||
nodeIn.d.valid := o.d.valid
|
|
||||||
o.d.ready := nodeIn.d.ready && m
|
o.d.ready := nodeIn.d.ready && m
|
||||||
}
|
}
|
||||||
assert(!(nodeOuts.head.a.ready && nodeOuts.last.a.ready) || !nodeIn.a.valid, "double output fire")
|
nodeIn.d.bits := MuxCase(DontCare, (nodeOuts zip srcMatch).map { case (o, m) =>
|
||||||
|
m -> o.d.bits
|
||||||
|
})
|
||||||
|
nodeIn.d.bits.source := MuxCase(DontCare, (nodeOuts zip srcMatch).map { case (o, m) =>
|
||||||
|
m -> o.d.bits.source(inSourceWidth - 1, 0)
|
||||||
|
})
|
||||||
|
nodeIn.d.valid := (nodeOuts zip srcMatch).map { case (o, m) => o.d.valid && m }.reduce(_ || _)
|
||||||
nodeIn.a.ready := nodeOuts.map(_.a.ready).reduce(_ || _) && sourceEnq.ready
|
nodeIn.a.ready := nodeOuts.map(_.a.ready).reduce(_ || _) && sourceEnq.ready
|
||||||
|
|
||||||
|
assert(!(nodeOuts.head.a.ready && nodeOuts.last.a.ready) || !nodeIn.a.valid, "double output fire")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,24 +111,30 @@ object DuplicatorNode {
|
|||||||
|
|
||||||
class DoubleOutXbar(clients: Seq[TLNode], override val name: String = "2o_xbar")
|
class DoubleOutXbar(clients: Seq[TLNode], override val name: String = "2o_xbar")
|
||||||
(implicit p: Parameters) extends LazyModule {
|
(implicit p: Parameters) extends LazyModule {
|
||||||
val xbar0 = TLXbar(TLArbiter.lowestIndexFirst)
|
val xbar0 = TLXbar(TLArbiter.lowestIndexFirst, Some("double_out_xbar0"))
|
||||||
val xbar1 = TLXbar(TLArbiter.lowestIndexFirst)
|
val xbar1 = TLXbar(TLArbiter.lowestIndexFirst, Some("double_out_xbar1"))
|
||||||
|
|
||||||
implicit val disableMonitors: Boolean = false
|
implicit val disableMonitors: Boolean = false
|
||||||
|
|
||||||
|
val bufGen = () => TLBuffer(ace = BufferParams(0), bd = BufferParams(2, flow = false, pipe = false))
|
||||||
val dupedIds = clients.map(connectOne(_, DuplicatorNode.apply)).map { c =>
|
val dupedIds = clients.map(connectOne(_, DuplicatorNode.apply)).map { c =>
|
||||||
val id0 = connectOne(c, TLIdentityNode.apply)
|
val id0 = connectOne(c, TLIdentityNode.apply)
|
||||||
val id1 = connectOne(c, TLIdentityNode.apply)
|
val id1 = connectOne(c, TLIdentityNode.apply)
|
||||||
xbar0 := id0
|
xbar0 := connectOne(id0, bufGen)
|
||||||
xbar1 := id1
|
xbar1 := connectOne(id1, bufGen)
|
||||||
Seq(id0, id1)
|
Seq(id0, id1)
|
||||||
}.transpose
|
}.transpose
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val id0InReadys = VecInit(dupedIds.head.map(_.in.head._1.a.ready)).asUInt
|
val id0InReadys = VecInit(dupedIds.head.map(_.in.head._1.a.ready)).asUInt
|
||||||
val id1InValids = VecInit(dupedIds.last.map(_.in.head._1.a.valid)).asUInt
|
val id1InValids = VecInit(dupedIds.last.map(_.in.head._1.a.valid)).asUInt
|
||||||
(dupedIds.last.map(_.out.head._1.a.valid) zip (id1InValids & (~id0InReadys).asUInt).asBools)
|
val id1OutValids = dupedIds.last.map(_.out.head._1.a.valid)
|
||||||
|
val id1InReadys = dupedIds.last.map(_.in.head._1.a.ready)
|
||||||
|
val id1OutReadys = VecInit(dupedIds.last.map(_.out.head._1.a.ready)).asUInt
|
||||||
|
(id1OutValids zip (id1InValids & (~id0InReadys).asUInt).asBools)
|
||||||
.foreach { case (o, i) => o := i }
|
.foreach { case (o, i) => o := i }
|
||||||
|
(id1InReadys zip (id1OutReadys & (~id0InReadys).asUInt).asBools)
|
||||||
|
.foreach { case (i, o) => i := o }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class RWSplitterNode(visibility: Option[AddressSet], override val name: String =
|
|||||||
// splits & arbitrates them into one client node per type of operation;
|
// splits & arbitrates them into one client node per type of operation;
|
||||||
// there will be N incoming edges, two outgoing edges, with two N:1 muxes;
|
// there will be N incoming edges, two outgoing edges, with two N:1 muxes;
|
||||||
// it keeps the read and write channels fully separate to allow parallel processing.
|
// it keeps the read and write channels fully separate to allow parallel processing.
|
||||||
|
suggestName(name)
|
||||||
val node = TLNexusNode(
|
val node = TLNexusNode(
|
||||||
clientFn = { seq =>
|
clientFn = { seq =>
|
||||||
val in_mapping = TLXbar.mapInputIds(seq)
|
val in_mapping = TLXbar.mapInputIds(seq)
|
||||||
@@ -155,6 +156,11 @@ object RWSplitterNode {
|
|||||||
LazyModule(new RWSplitterNode(None, name = valName.value)).node
|
LazyModule(new RWSplitterNode(None, name = valName.value)).node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def apply(name: String)
|
||||||
|
(implicit p: Parameters, valName: ValName, sourceInfo: SourceInfo): TLNexusNode = {
|
||||||
|
LazyModule(new RWSplitterNode(None, name = name)).node
|
||||||
|
}
|
||||||
|
|
||||||
def apply(visibility: AddressSet)
|
def apply(visibility: AddressSet)
|
||||||
(implicit p: Parameters, valName: ValName, sourceInfo: SourceInfo): TLNexusNode = {
|
(implicit p: Parameters, valName: ValName, sourceInfo: SourceInfo): TLNexusNode = {
|
||||||
apply(visibility, valName.value)
|
apply(visibility, valName.value)
|
||||||
|
|||||||
@@ -53,10 +53,12 @@ object XbarWithExtPolicy {
|
|||||||
|
|
||||||
object XbarWithExtPolicyNoFallback {
|
object XbarWithExtPolicyNoFallback {
|
||||||
def apply(nameSuffix: Option[String] = None)
|
def apply(nameSuffix: Option[String] = None)
|
||||||
(implicit p: Parameters): (XbarWithExtPolicy, TLIdentityNode) = {
|
(implicit p: Parameters): (XbarWithExtPolicy, TLIdentityNode, TLIdentityNode) = {
|
||||||
val inIdNode = TLIdentityNode()
|
val inIdNode = TLIdentityNode()
|
||||||
|
val outIdNode = TLIdentityNode()
|
||||||
val xbar = LazyModule(new XbarWithExtPolicy(nameSuffix, false))
|
val xbar = LazyModule(new XbarWithExtPolicy(nameSuffix, false))
|
||||||
xbar.node :=* inIdNode
|
xbar.node :=* inIdNode
|
||||||
(xbar, inIdNode)
|
outIdNode :=* xbar.node
|
||||||
|
(xbar, inIdNode, outIdNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ class VirgoSharedMemComponents(
|
|||||||
// tensor core read nodes
|
// tensor core read nodes
|
||||||
val tcDistNodes = Seq.fill(smemBanks)(tcNodeFanouts.map(connectOne(_, () => DistributorNode(smemWidth, wordSize))))
|
val tcDistNodes = Seq.fill(smemBanks)(tcNodeFanouts.map(connectOne(_, () => DistributorNode(smemWidth, wordSize))))
|
||||||
val tcNodes = tcDistNodes.map { tcBank =>
|
val tcNodes = tcDistNodes.map { tcBank =>
|
||||||
Seq.fill(smemSubbanks)(tcBank.map(connectOne(_, () => TLBuffer(BufferParams(2, false, false)))).map(connectXbarName(_, Some("tc_dist_fanout"))))
|
Seq.fill(smemSubbanks)(tcBank.map(connectOne(_,
|
||||||
|
() => TLBuffer(BufferParams(2, false, false)))).map(connectXbarName(_, Some("tc_dist_fanout"))))
|
||||||
} // (banks, subbanks, tc client)
|
} // (banks, subbanks, tc client)
|
||||||
|
|
||||||
val unalignedRWNodes: ArrayBuffer[ArrayBuffer[TLNexusNode]] = // mutable for readability
|
val unalignedRWNodes: ArrayBuffer[ArrayBuffer[TLNexusNode]] = // mutable for readability
|
||||||
@@ -195,7 +196,7 @@ class VirgoSharedMemComponents(
|
|||||||
val laneSerialXbar = laneSerialXbars.get(rw)(lid)
|
val laneSerialXbar = laneSerialXbars.get(rw)(lid)
|
||||||
laneSerialXbar._1.policySlaveNode := coreSerialPolicy.get(rw)(lid)
|
laneSerialXbar._1.policySlaveNode := coreSerialPolicy.get(rw)(lid)
|
||||||
coresRW.foreach(laneSerialXbar._2 := _)
|
coresRW.foreach(laneSerialXbar._2 := _)
|
||||||
connectXbarName(connectOne(laneSerialXbar._1.node, TLEphemeralNode.apply), Some(s"lane_${lid}_serial_out"))
|
connectXbarName(connectOne(laneSerialXbar._3, TLEphemeralNode.apply), Some(s"lane_${lid}_serial_out"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NotSerialized => Seq.fill(2)(unalignedRWNodes.toSeq.flatten.map(connectXbar.apply))
|
case NotSerialized => Seq.fill(2)(unalignedRWNodes.toSeq.flatten.map(connectXbar.apply))
|
||||||
@@ -216,7 +217,7 @@ class VirgoSharedMemComponents(
|
|||||||
|
|
||||||
(uniformRNodes, uniformWNodes, nonuniformRNodes, nonuniformWNodes)
|
(uniformRNodes, uniformWNodes, nonuniformRNodes, nonuniformWNodes)
|
||||||
} else {
|
} else {
|
||||||
val splitterNodes = radianceSmemFanout.map { connectOne(_, RWSplitterNode.apply) }
|
val splitterNodes = radianceSmemFanout.map { connectOne(_, () => RWSplitterNode("rad_fanout_splitter")) }
|
||||||
// these nodes access an entire line simultaneously
|
// these nodes access an entire line simultaneously
|
||||||
val uniformRNodes: Seq[Seq[Seq[TLNexusNode]]] = spadReadNodes
|
val uniformRNodes: Seq[Seq[Seq[TLNexusNode]]] = spadReadNodes
|
||||||
val uniformWNodes: Seq[Seq[Seq[TLNexusNode]]] = (spadWriteNodes zip spadSpWriteNodes).map { case (wb, wsb) =>
|
val uniformWNodes: Seq[Seq[Seq[TLNexusNode]]] = (spadWriteNodes zip spadSpWriteNodes).map { case (wb, wsb) =>
|
||||||
@@ -259,7 +260,7 @@ class VirgoSharedMemComponentsImp[T <: VirgoSharedMemComponents]
|
|||||||
(xbarsRW zip policiesRW).foreach { case (xbars, policies) =>
|
(xbarsRW zip policiesRW).foreach { case (xbars, policies) =>
|
||||||
// for each lane, if any core is valid
|
// for each lane, if any core is valid
|
||||||
val coreValids = xbars.map(_._2.in.map(_._1)).transpose.map { core => VecInit(core.map(_.a.valid)).asUInt.orR }
|
val coreValids = xbars.map(_._2.in.map(_._1)).transpose.map { core => VecInit(core.map(_.a.valid)).asUInt.orR }
|
||||||
val select = xbars.map(_._2.out.map(_._1)).transpose.map { core => VecInit(core.map(_.a.ready)).asUInt.orR }
|
val select = xbars.map(_._3.in.map(_._1)).transpose.map { core => VecInit(core.map(_.a.fire)).asUInt.orR }
|
||||||
val coreSelect = TLArbiter.roundRobin(outer.numCores, VecInit(coreValids).asUInt, VecInit(select).asUInt.orR)
|
val coreSelect = TLArbiter.roundRobin(outer.numCores, VecInit(coreValids).asUInt, VecInit(select).asUInt.orR)
|
||||||
// TODO: roll this into XbarWithExtPolicy
|
// TODO: roll this into XbarWithExtPolicy
|
||||||
xbars.foreach { lane =>
|
xbars.foreach { lane =>
|
||||||
|
|||||||
Reference in New Issue
Block a user