[tl2] convert NBDcache to TL2 (WIP; compiles but untested)

This commit is contained in:
Henry Cook committed 2016-11-18 19:04:06 -08:00
1 parent 5f1cc19d71
commit 8b908465e0
8 files changed
+623 -593

No files matched your search

+167
View File
@@ -0,0 +1,167 @@
// See LICENSE for license details.
package rocket
import Chisel._
import cde.{Parameters, Field}
import diplomacy._
import uncore.tilelink2._
import uncore.agents._
import uncore.constants._
import uncore.tilelink.{TLKey, TLId}
import util.ParameterizedBundle
case class DCacheConfig(
nMSHRs: Int = 1,
nSDQ: Int = 17,
nRPQ: Int = 16,
nMMIOs: Int = 1)
case object DCacheKey extends Field[DCacheConfig]
trait HasL1HellaCacheParameters extends HasCacheParameters with HasCoreParameters {
val outerDataBeats = p(TLKey(p(TLId))).dataBeats
val outerDataBits = p(TLKey(p(TLId))).dataBitsPerBeat
val refillCyclesPerBeat = outerDataBits/rowBits
require(refillCyclesPerBeat == 1)
val refillCycles = refillCyclesPerBeat*outerDataBeats
val cacheBlockBytes = p(CacheBlockBytes)
val lgCacheBlockBytes = log2Up(cacheBlockBytes)
val wordBits = xLen // really, xLen max
val wordBytes = wordBits/8
val wordOffBits = log2Up(wordBytes)
val beatBytes = cacheBlockBytes / outerDataBeats
val beatWords = beatBytes / wordBytes
val beatOffBits = log2Up(beatBytes)
val idxMSB = untagBits-1
val idxLSB = blockOffBits
val offsetmsb = idxLSB-1
val offsetlsb = wordOffBits
val rowWords = rowBits/wordBits
val doNarrowRead = coreDataBits * nWays % rowBits == 0
val encDataBits = code.width(coreDataBits)
val encRowBits = encDataBits*rowWords
val nIOMSHRs = 1
val lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
require(isPow2(nSets))
require(rowBits >= coreDataBits)
require(rowBits <= outerDataBits)
require(xLen <= outerDataBits) // would need offset addr for puts if data width < xlen
require(!usingVM || untagBits <= pgIdxBits)
}
abstract class L1HellaCacheModule(implicit val p: Parameters) extends Module
with HasL1HellaCacheParameters
abstract class L1HellaCacheBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
with HasL1HellaCacheParameters
class L1Metadata(implicit p: Parameters) extends Metadata()(p) with HasL1HellaCacheParameters {
val coh = new ClientMetadata
}
object L1Metadata {
def apply(tag: Bits, coh: ClientMetadata)(implicit p: Parameters) = {
val meta = Wire(new L1Metadata)
meta.tag := tag
meta.coh := coh
meta
}
}
class L1MetaReadReq(implicit p: Parameters) extends MetaReadReq {
val tag = Bits(width = tagBits)
override def cloneType = new L1MetaReadReq()(p).asInstanceOf[this.type] //TODO remove
}
class L1MetaWriteReq(implicit p: Parameters) extends
MetaWriteReq[L1Metadata](new L1Metadata)
trait HasCoreMemOp extends HasCoreParameters {
val addr = UInt(width = coreMaxAddrBits)
val tag = Bits(width = dcacheReqTagBits)
val cmd = Bits(width = M_SZ)
val typ = Bits(width = MT_SZ)
}
trait HasCoreData extends HasCoreParameters {
val data = Bits(width = coreDataBits)
}
class HellaCacheReq(implicit p: Parameters) extends HellaCacheReqInternal()(p) with HasCoreData
class HellaCacheResp(implicit p: Parameters) extends CoreBundle()(p)
with HasCoreMemOp
with HasCoreData {
val replay = Bool()
val has_data = Bool()
val data_word_bypass = Bits(width = coreDataBits)
val store_data = Bits(width = coreDataBits)
}
class AlignmentExceptions extends Bundle {
val ld = Bool()
val st = Bool()
}
class HellaCacheExceptions extends Bundle {
val ma = new AlignmentExceptions
val pf = new AlignmentExceptions
}
// interface between D$ and processor/DTLB
class HellaCacheIO(implicit p: Parameters) extends CoreBundle()(p) {
val req = Decoupled(new HellaCacheReq)
val s1_kill = Bool(OUTPUT) // kill previous cycle's req
val s1_data = Bits(OUTPUT, coreDataBits) // data for previous cycle's req
val s2_nack = Bool(INPUT) // req from two cycles ago is rejected
val resp = Valid(new HellaCacheResp).flip
val replay_next = Bool(INPUT)
val xcpt = (new HellaCacheExceptions).asInput
val invalidate_lr = Bool(OUTPUT)
val ordered = Bool(INPUT)
}
abstract class HellaCache(val cfg: DCacheConfig)(implicit val p: Parameters) extends LazyModule {
val node = TLClientNode(TLClientParameters(
sourceId = IdRange(0, cfg.nMSHRs + cfg.nMMIOs),
supportsProbe = TransferSizes(p(CacheBlockBytes))))
val module: HellaCacheModule
}
class HellaCacheBundle(outer: HellaCache)(implicit p: Parameters) extends Bundle {
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val mem = outer.node.bundleOut
}
class HellaCacheModule(outer: HellaCache)(implicit val p: Parameters) extends LazyModuleImp(outer)
with HasL1HellaCacheParameters {
implicit val cfg = outer.cfg
val io = new HellaCacheBundle(outer)
val edge = outer.node.edgesOut(0)
val tl_out = io.mem(0)
/* TODO
edge.manager.managers.foreach { m =>
if (m.supportsGet) {
require (m.supportsGet.contains(TransferSizes(1, tlDataBytes)))
....etc
}
}
*/
}
object HellaCache {
def apply(cfg: DCacheConfig)(implicit p: Parameters) = {
if (cfg.nMSHRs == 0) LazyModule(new DCache(cfg))
else LazyModule(new NonBlockingDCache(cfg))
}
}
@@ -0,0 +1,107 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Chisel.ImplicitConversions._
import cde.Parameters
import junctions._
import diplomacy._
import uncore.constants._
import uncore.tilelink2._
import uncore.util._
class ScratchpadSlavePort(implicit val p: Parameters) extends LazyModule with HasCoreParameters {
val node = TLManagerNode(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(AddressSet(0x80000000L, BigInt(p(DataScratchpadSize)-1))),
regionType = RegionType.UNCACHED,
executable = true,
supportsArithmetic = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsLogical = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsPutPartial = TransferSizes(1, coreDataBytes),
supportsPutFull = TransferSizes(1, coreDataBytes),
supportsGet = TransferSizes(1, coreDataBytes),
fifoId = Some(0))), // requests handled in FIFO order
beatBytes = coreDataBytes,
minLatency = 1))
// Make sure this ends up with the same name as before
override def name = "dmem0"
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl_in = node.bundleIn
val dmem = new HellaCacheIO
}
val tl_in = io.tl_in(0)
val edge = node.edgesIn(0)
require(usingDataScratchpad)
val s_ready :: s_wait :: s_replay :: s_grant :: Nil = Enum(UInt(), 4)
val state = Reg(init = s_ready)
when (io.dmem.resp.valid) { state := s_grant }
when (tl_in.d.fire()) { state := s_ready }
when (io.dmem.s2_nack) { state := s_replay }
when (io.dmem.req.fire()) { state := s_wait }
val acq = Reg(tl_in.a.bits)
when (io.dmem.resp.valid) { acq.data := io.dmem.resp.bits.data }
when (tl_in.a.fire()) { acq := tl_in.a.bits }
val isWrite = acq.opcode === TLMessages.PutFullData || acq.opcode === TLMessages.PutPartialData
val isRead = !edge.hasData(acq)
def formCacheReq(acq: TLBundleA) = {
val req = Wire(new HellaCacheReq)
req.cmd := MuxLookup(acq.opcode, Wire(M_XRD), Array(
TLMessages.PutFullData -> M_XWR,
TLMessages.PutPartialData -> M_XWR,
TLMessages.ArithmeticData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.MIN -> M_XA_MIN,
TLAtomics.MAX -> M_XA_MAX,
TLAtomics.MINU -> M_XA_MINU,
TLAtomics.MAXU -> M_XA_MAXU,
TLAtomics.ADD -> M_XA_ADD)),
TLMessages.LogicalData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.XOR -> M_XA_XOR,
TLAtomics.OR -> M_XA_OR,
TLAtomics.AND -> M_XA_AND,
TLAtomics.SWAP -> M_XA_SWAP)),
TLMessages.Get -> M_XRD))
// treat all loads as full words, so bytes appear in correct lane
req.typ := Mux(isRead, log2Ceil(coreDataBytes), acq.size)
req.addr := Mux(isRead, ~(~acq.address | (coreDataBytes-1)), acq.address)
req.tag := UInt(0)
req
}
val ready = state === s_ready || tl_in.d.fire()
io.dmem.req.valid := (tl_in.a.valid && ready) || state === s_replay
tl_in.a.ready := io.dmem.req.ready && ready
io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, tl_in.a.bits))
// the TL data is already in the correct byte lane, but the D$
// expects right-justified store data, so that it can steer the bytes.
io.dmem.s1_data := new LoadGen(acq.size, Bool(false), acq.address(log2Ceil(coreDataBytes)-1,0), acq.data, Bool(false), coreDataBytes).data
io.dmem.s1_kill := false
io.dmem.invalidate_lr := false
// place AMO data in correct word lane
val minAMOBytes = 4
val grantData = Mux(io.dmem.resp.valid, io.dmem.resp.bits.data, acq.data)
val alignedGrantData = Mux(acq.size <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData)
tl_in.d.valid := io.dmem.resp.valid || state === s_grant
tl_in.d.bits := Mux(isWrite,
edge.AccessAck(acq, UInt(0)),
edge.AccessAck(acq, UInt(0), UInt(0)))
tl_in.d.bits.data := alignedGrantData
// Tie off unused channels
tl_in.b.valid := Bool(false)
tl_in.c.ready := Bool(true)
tl_in.e.ready := Bool(true)
}
}
@@ -0,0 +1,136 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Chisel.ImplicitConversions._
import cde.Parameters
import util._
/**
* This module buffers requests made by the SimpleHellaCacheIF in case they
* are nacked. Nacked requests must be replayed in order, and no other requests
* must be allowed to go through until the replayed requests are successfully
* completed.
*/
class SimpleHellaCacheIFReplayQueue(depth: Int)
(implicit val p: Parameters) extends Module
with HasL1HellaCacheParameters {
val io = new Bundle {
val req = Decoupled(new HellaCacheReq).flip
val nack = Valid(Bits(width = coreDCacheReqTagBits)).flip
val resp = Valid(new HellaCacheResp).flip
val replay = Decoupled(new HellaCacheReq)
}
// Registers to store the sent request
// When a request is sent the first time,
// it is stored in one of the reqs registers
// and the corresponding inflight bit is set.
// The reqs register will be deallocated once the request is
// successfully completed.
val inflight = Reg(init = UInt(0, depth))
val reqs = Reg(Vec(depth, new HellaCacheReq))
// The nack queue stores the index of nacked requests (in the reqs vector)
// in the order that they were nacked. A request is enqueued onto nackq
// when it is newly nacked (i.e. not a nack for a previous replay).
// The head of the nack queue will be replayed until it is
// successfully completed, at which time the request is dequeued.
// No new requests will be made or other replays attempted until the head
// of the nackq is successfully completed.
val nackq = Module(new Queue(UInt(width = log2Up(depth)), depth))
val replaying = Reg(init = Bool(false))
val next_inflight_onehot = PriorityEncoderOH(~inflight)
val next_inflight = OHToUInt(next_inflight_onehot)
val next_replay = nackq.io.deq.bits
val next_replay_onehot = UIntToOH(next_replay)
val next_replay_req = reqs(next_replay)
// Keep sending the head of the nack queue until it succeeds
io.replay.valid := nackq.io.deq.valid && !replaying
io.replay.bits := next_replay_req
// Don't allow new requests if there is are replays waiting
// or something being nacked.
io.req.ready := !inflight.andR && !nackq.io.deq.valid && !io.nack.valid
// Match on the tags to determine the index of nacks or responses
val nack_onehot = Cat(reqs.map(_.tag === io.nack.bits).reverse) & inflight
val resp_onehot = Cat(reqs.map(_.tag === io.resp.bits.tag).reverse) & inflight
val replay_complete = io.resp.valid && replaying && io.resp.bits.tag === next_replay_req.tag
val nack_head = io.nack.valid && nackq.io.deq.valid && io.nack.bits === next_replay_req.tag
// Enqueue to the nack queue if there is a nack that is not in response to
// the previous replay
nackq.io.enq.valid := io.nack.valid && !nack_head
nackq.io.enq.bits := OHToUInt(nack_onehot)
assert(!nackq.io.enq.valid || nackq.io.enq.ready,
"SimpleHellaCacheIF: ReplayQueue nack queue overflow")
// Dequeue from the nack queue if the last replay was successfully completed
nackq.io.deq.ready := replay_complete
assert(!nackq.io.deq.ready || nackq.io.deq.valid,
"SimpleHellaCacheIF: ReplayQueue nack queue underflow")
// Set inflight bit when a request is made
// Clear it when it is successfully completed
inflight := (inflight | Mux(io.req.fire(), next_inflight_onehot, UInt(0))) &
~Mux(io.resp.valid, resp_onehot, UInt(0))
when (io.req.fire()) {
reqs(next_inflight) := io.req.bits
}
// Only one replay outstanding at a time
when (io.replay.fire()) { replaying := Bool(true) }
when (nack_head || replay_complete) { replaying := Bool(false) }
}
// exposes a sane decoupled request interface
class SimpleHellaCacheIF(implicit p: Parameters) extends Module
{
val io = new Bundle {
val requestor = new HellaCacheIO().flip
val cache = new HellaCacheIO
}
val replayq = Module(new SimpleHellaCacheIFReplayQueue(2))
val req_arb = Module(new Arbiter(new HellaCacheReq, 2))
val req_helper = DecoupledHelper(
req_arb.io.in(1).ready,
replayq.io.req.ready,
io.requestor.req.valid)
req_arb.io.in(0) <> replayq.io.replay
req_arb.io.in(1).valid := req_helper.fire(req_arb.io.in(1).ready)
req_arb.io.in(1).bits := io.requestor.req.bits
io.requestor.req.ready := req_helper.fire(io.requestor.req.valid)
replayq.io.req.valid := req_helper.fire(replayq.io.req.ready)
replayq.io.req.bits := io.requestor.req.bits
val s0_req_fire = io.cache.req.fire()
val s1_req_fire = Reg(next = s0_req_fire)
val s2_req_fire = Reg(next = s1_req_fire)
val s1_req_tag = Reg(next = io.cache.req.bits.tag)
val s2_req_tag = Reg(next = s1_req_tag)
val s2_kill = Reg(next = io.cache.s1_kill)
io.cache.invalidate_lr := io.requestor.invalidate_lr
io.cache.req <> req_arb.io.out
io.cache.s1_kill := io.cache.s2_nack
io.cache.s1_data := RegEnable(req_arb.io.out.bits.data, s0_req_fire)
replayq.io.nack.valid := (io.cache.s2_nack || s2_kill) && s2_req_fire
replayq.io.nack.bits := s2_req_tag
replayq.io.resp := io.cache.resp
io.requestor.resp := io.cache.resp
assert(!Reg(next = io.cache.req.fire()) ||
!(io.cache.xcpt.ma.ld || io.cache.xcpt.ma.st ||
io.cache.xcpt.pf.ld || io.cache.xcpt.pf.st),
"SimpleHellaCacheIF exception")
}
+10 -135
View File
@@ -3,15 +3,15 @@
package rocket package rocket
import Chisel._ import Chisel._
import junctions._ import Chisel.ImplicitConversions._
import cde.Parameters
import diplomacy._ import diplomacy._
import uncore.tilelink2._
import uncore.constants._
import uncore.agents._ import uncore.agents._
import uncore.constants._
import uncore.tilelink2._
import uncore.util._ import uncore.util._
import util._ import util._
import TLMessages._ import TLMessages._
import Chisel.ImplicitConversions._
import config._ import config._
class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) { class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
@@ -40,46 +40,17 @@ class DCacheDataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
} }
} }
class DCache(maxUncachedInFlight: Int = 2)(implicit val p: Parameters) extends LazyModule with HasL1HellaCacheParameters { class DCache(cfg: DCacheConfig)(implicit p: Parameters) extends HellaCache(cfg)(p) {
override lazy val module = new DCacheModule(this)
val node = TLClientNode(TLClientParameters(
sourceId = IdRange(0, maxUncachedInFlight),
supportsProbe = TransferSizes(cacheBlockBytes)))
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val mem = node.bundleOut
} }
val edge = node.edgesOut(0) class DCacheModule(outer: DCache)(implicit p: Parameters) extends HellaCacheModule(outer)(p) {
val tl_out = io.mem(0)
val maxUncachedInFlight = cfg.nMMIOs
/* TODO
edge.manager.managers.foreach { m =>
// If a slave supports read at all, it must support all TL Legacy requires
if (m.supportsGet) {
require (m.supportsGet.contains(TransferSizes(1, tlDataBytes)))
require (m.supportsGet.contains(TransferSizes(tlDataBeats * tlDataBytes)))
}
// Likewise, any put support must mean full put support
if (m.supportsPutPartial) {
require (m.supportsPutPartial.contains(TransferSizes(1, tlDataBytes)))
require (m.supportsPutPartial.contains(TransferSizes(tlDataBeats * tlDataBytes)))
}
// Any atomic support => must support 32-bit size
if (m.supportsArithmetic) { require (m.supportsArithmetic.contains(TransferSizes(4))) }
if (m.supportsLogical) { require (m.supportsLogical .contains(TransferSizes(4))) }
// We straight-up require Acquire support, this is a cache afterall?
require (edge.manager.anySupportsAcquire)
}
*/
require(rowBits == encRowBits) // no ECC require(rowBits == encRowBits) // no ECC
require(refillCyclesPerBeat == 1)
require(rowBits >= coreDataBits)
val grantackq = Module(new Queue(tl_out.e.bits,1)) val grantackq = Module(new Queue(tl_out.e.bits,1)) // TODO don't need this in scratchpad mode
// tags // tags
val replacer = p(Replacer)() val replacer = p(Replacer)()
@@ -531,99 +502,3 @@ class DCache(maxUncachedInFlight: Int = 2)(implicit val p: Parameters) extends L
} }
} }
} }
}
class ScratchpadSlavePort(implicit val p: Parameters) extends LazyModule with HasCoreParameters {
val node = TLManagerNode(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(AddressSet(0x80000000L, BigInt(p(DataScratchpadSize)-1))),
regionType = RegionType.UNCACHED,
executable = true,
supportsArithmetic = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsLogical = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsPutPartial = TransferSizes(1, coreDataBytes),
supportsPutFull = TransferSizes(1, coreDataBytes),
supportsGet = TransferSizes(1, coreDataBytes),
fifoId = Some(0))), // requests handled in FIFO order
beatBytes = coreDataBytes,
minLatency = 1))
// Make sure this ends up with the same name as before
override def name = "dmem0"
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl_in = node.bundleIn
val dmem = new HellaCacheIO
}
val tl_in = io.tl_in(0)
val edge = node.edgesIn(0)
require(usingDataScratchpad)
val s_ready :: s_wait :: s_replay :: s_grant :: Nil = Enum(UInt(), 4)
val state = Reg(init = s_ready)
when (io.dmem.resp.valid) { state := s_grant }
when (tl_in.d.fire()) { state := s_ready }
when (io.dmem.s2_nack) { state := s_replay }
when (io.dmem.req.fire()) { state := s_wait }
val acq = Reg(tl_in.a.bits)
when (io.dmem.resp.valid) { acq.data := io.dmem.resp.bits.data }
when (tl_in.a.fire()) { acq := tl_in.a.bits }
val isWrite = acq.opcode === TLMessages.PutFullData || acq.opcode === TLMessages.PutPartialData
val isRead = !edge.hasData(acq)
def formCacheReq(acq: TLBundleA) = {
val req = Wire(new HellaCacheReq)
req.cmd := MuxLookup(acq.opcode, Wire(M_XRD), Array(
TLMessages.PutFullData -> M_XWR,
TLMessages.PutPartialData -> M_XWR,
TLMessages.ArithmeticData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.MIN -> M_XA_MIN,
TLAtomics.MAX -> M_XA_MAX,
TLAtomics.MINU -> M_XA_MINU,
TLAtomics.MAXU -> M_XA_MAXU,
TLAtomics.ADD -> M_XA_ADD)),
TLMessages.LogicalData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.XOR -> M_XA_XOR,
TLAtomics.OR -> M_XA_OR,
TLAtomics.AND -> M_XA_AND,
TLAtomics.SWAP -> M_XA_SWAP)),
TLMessages.Get -> M_XRD))
// treat all loads as full words, so bytes appear in correct lane
req.typ := Mux(isRead, log2Ceil(coreDataBytes), acq.size)
req.addr := Mux(isRead, ~(~acq.address | (coreDataBytes-1)), acq.address)
req.tag := UInt(0)
req
}
val ready = state === s_ready || tl_in.d.fire()
io.dmem.req.valid := (tl_in.a.valid && ready) || state === s_replay
tl_in.a.ready := io.dmem.req.ready && ready
io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, tl_in.a.bits))
// the TL data is already in the correct byte lane, but the D$
// expects right-justified store data, so that it can steer the bytes.
io.dmem.s1_data := new LoadGen(acq.size, Bool(false), acq.address(log2Ceil(coreDataBytes)-1,0), acq.data, Bool(false), coreDataBytes).data
io.dmem.s1_kill := false
io.dmem.invalidate_lr := false
// place AMO data in correct word lane
val minAMOBytes = 4
val grantData = Mux(io.dmem.resp.valid, io.dmem.resp.bits.data, acq.data)
val alignedGrantData = Mux(acq.size <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData)
tl_in.d.valid := io.dmem.resp.valid || state === s_grant
tl_in.d.bits := Mux(isWrite,
edge.AccessAck(acq, UInt(0)),
edge.AccessAck(acq, UInt(0), UInt(0)))
tl_in.d.bits.data := alignedGrantData
// Tie off unused channels
tl_in.b.valid := Bool(false)
tl_in.c.ready := Bool(true)
tl_in.e.ready := Bool(true)
}
}
+188 -454
View File
@@ -3,71 +3,17 @@
package rocket package rocket
import Chisel._ import Chisel._
import uncore.tilelink._ import Chisel.ImplicitConversions._
import uncore.tilelink2._ import cde.Parameters
import diplomacy._
import uncore.agents._ import uncore.agents._
import uncore.constants._ import uncore.constants._
import uncore.tilelink._
import uncore.tilelink2._
import uncore.util._ import uncore.util._
import diplomacy._
import util._ import util._
import Chisel.ImplicitConversions._
import config._ import config._
case class DCacheConfig(
nMSHRs: Int = 1,
nSDQ: Int = 17,
nRPQ: Int = 16)
case object DCacheKey extends Field[DCacheConfig]
trait HasL1HellaCacheParameters extends HasCacheParameters with HasCoreParameters {
val outerDataBeats = p(TLKey(p(TLId))).dataBeats
val outerDataBits = p(TLKey(p(TLId))).dataBitsPerBeat
val refillCyclesPerBeat = outerDataBits/rowBits
val refillCycles = refillCyclesPerBeat*outerDataBeats
val cacheBlockBytes = p(CacheBlockBytes)
val lgCacheBlockBytes = log2Up(cacheBlockBytes)
val wordBits = xLen // really, xLen max
val wordBytes = wordBits/8
val wordOffBits = log2Up(wordBytes)
val beatBytes = cacheBlockBytes / outerDataBeats
val beatWords = beatBytes / wordBytes
val beatOffBits = log2Up(beatBytes)
val idxMSB = untagBits-1
val idxLSB = blockOffBits
val offsetmsb = idxLSB-1
val offsetlsb = wordOffBits
val rowWords = rowBits/wordBits
val doNarrowRead = coreDataBits * nWays % rowBits == 0
val encDataBits = code.width(coreDataBits)
val encRowBits = encDataBits*rowWords
val nIOMSHRs = 1
val lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
require(isPow2(nSets))
require(rowBits <= outerDataBits)
require(xLen <= outerDataBits) // TODO need offset addr for puts if data width < xlen
require(!usingVM || untagBits <= pgIdxBits)
}
abstract class L1HellaCacheModule(implicit val p: Parameters) extends Module
with HasL1HellaCacheParameters
abstract class L1HellaCacheBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
with HasL1HellaCacheParameters
trait HasCoreMemOp extends HasCoreParameters {
val addr = UInt(width = coreMaxAddrBits)
val tag = Bits(width = dcacheReqTagBits)
val cmd = Bits(width = M_SZ)
val typ = Bits(width = MT_SZ)
}
trait HasCoreData extends HasCoreParameters {
val data = Bits(width = coreDataBits)
}
trait HasMissInfo extends HasL1HellaCacheParameters { trait HasMissInfo extends HasL1HellaCacheParameters {
val tag_match = Bool() val tag_match = Bool()
val old_meta = new L1Metadata val old_meta = new L1Metadata
@@ -79,41 +25,6 @@ class HellaCacheReqInternal(implicit p: Parameters) extends CoreBundle()(p)
val phys = Bool() val phys = Bool()
} }
class HellaCacheReq(implicit p: Parameters) extends HellaCacheReqInternal()(p) with HasCoreData
class HellaCacheResp(implicit p: Parameters) extends CoreBundle()(p)
with HasCoreMemOp
with HasCoreData {
val replay = Bool()
val has_data = Bool()
val data_word_bypass = Bits(width = coreDataBits)
val store_data = Bits(width = coreDataBits)
}
class AlignmentExceptions extends Bundle {
val ld = Bool()
val st = Bool()
}
class HellaCacheExceptions extends Bundle {
val ma = new AlignmentExceptions
val pf = new AlignmentExceptions
}
// interface between D$ and processor/DTLB
class HellaCacheIO(implicit p: Parameters) extends CoreBundle()(p) {
val req = Decoupled(new HellaCacheReq)
val s1_kill = Bool(OUTPUT) // kill previous cycle's req
val s1_data = Bits(OUTPUT, coreDataBits) // data for previous cycle's req
val s2_nack = Bool(INPUT) // req from two cycles ago is rejected
val resp = Valid(new HellaCacheResp).flip
val replay_next = Bool(INPUT)
val xcpt = (new HellaCacheExceptions).asInput
val invalidate_lr = Bool(OUTPUT)
val ordered = Bool(INPUT)
}
class L1DataReadReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) { class L1DataReadReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val way_en = Bits(width = nWays) val way_en = Bits(width = nWays)
val addr = Bits(width = untagBits) val addr = Bits(width = untagBits)
@@ -126,27 +37,8 @@ class L1DataWriteReq(implicit p: Parameters) extends L1DataReadReq()(p) {
class L1RefillReq(implicit p: Parameters) extends L1DataReadReq()(p) class L1RefillReq(implicit p: Parameters) extends L1DataReadReq()(p)
class L1MetaReadReq(implicit p: Parameters) extends MetaReadReq {
val tag = Bits(width = tagBits)
override def cloneType = new L1MetaReadReq()(p).asInstanceOf[this.type] //TODO remove
}
class L1MetaWriteReq(implicit p: Parameters) extends
MetaWriteReq[L1Metadata](new L1Metadata)
object L1Metadata {
def apply(tag: Bits, coh: ClientMetadata)(implicit p: Parameters) = {
val meta = Wire(new L1Metadata)
meta.tag := tag
meta.coh := coh
meta
}
}
class L1Metadata(implicit p: Parameters) extends Metadata()(p) with HasL1HellaCacheParameters {
val coh = new ClientMetadata
}
class Replay(implicit p: Parameters) extends HellaCacheReqInternal()(p) with HasCoreData class Replay(implicit p: Parameters) extends HellaCacheReqInternal()(p) with HasCoreData
class ReplayInternal(cfg: DCacheConfig)(implicit p: Parameters) extends HellaCacheReqInternal()(p) { class ReplayInternal(cfg: DCacheConfig)(implicit p: Parameters) extends HellaCacheReqInternal()(p) {
val sdq_id = UInt(width = log2Up(cfg.nSDQ)) val sdq_id = UInt(width = log2Up(cfg.nSDQ))
@@ -154,24 +46,27 @@ class ReplayInternal(cfg: DCacheConfig)(implicit p: Parameters) extends HellaCac
} }
class MSHRReq(implicit p: Parameters) extends Replay()(p) with HasMissInfo class MSHRReq(implicit p: Parameters) extends Replay()(p) with HasMissInfo
class MSHRReqInternal(cfg: DCacheConfig)(implicit p: Parameters) class MSHRReqInternal(cfg: DCacheConfig)(implicit p: Parameters)
extends ReplayInternal(cfg)(p) with HasMissInfo { extends ReplayInternal(cfg)(p) with HasMissInfo {
override def cloneType = new MSHRReqInternal(cfg)(p).asInstanceOf[this.type] override def cloneType = new MSHRReqInternal(cfg)(p).asInstanceOf[this.type]
} }
class ProbeInternal(implicit p: Parameters) extends Probe()(p) with HasClientTransactionId class WritebackReq(params: TLBundleParameters)(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val tag = Bits(width = tagBits)
class WritebackReq(implicit p: Parameters) extends Release()(p) with HasCacheParameters { val idx = Bits(width = idxBits)
val source = UInt(width = params.sourceBits)
val param = UInt(width = TLPermissions.cWidth)
val way_en = Bits(width = nWays) val way_en = Bits(width = nWays)
val voluntary = Bool()
} }
class IOMSHR(id: Int)(implicit p: Parameters) extends L1HellaCacheModule()(p) { class IOMSHR(id: Int, edge: TLEdgeOut)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle { val io = new Bundle {
val req = Decoupled(new HellaCacheReq).flip val req = Decoupled(new HellaCacheReq).flip
val acquire = Decoupled(new Acquire)
val grant = Valid(new GrantFromSrc).flip
val finish = Decoupled(new FinishToDst)
val resp = Decoupled(new HellaCacheResp) val resp = Decoupled(new HellaCacheResp)
val mem_access = Decoupled(new TLBundleA(edge.bundle))
val mem_ack = Valid(new TLBundleD(edge.bundle)).flip
val replay_next = Bool(OUTPUT) val replay_next = Bool(OUTPUT)
} }
@@ -185,57 +80,42 @@ class IOMSHR(id: Int)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val req = Reg(new HellaCacheReq) val req = Reg(new HellaCacheReq)
val req_cmd_sc = req.cmd === M_XSC val req_cmd_sc = req.cmd === M_XSC
val grant_word = Reg(UInt(width = wordBits)) val grant_word = Reg(UInt(width = wordBits))
val fq = Module(new FinishQueue(1))
val s_idle :: s_acquire :: s_grant :: s_resp :: s_finish :: Nil = Enum(Bits(), 5) val s_idle :: s_mem_access :: s_mem_ack :: s_resp :: Nil = Enum(Bits(), 5)
val state = Reg(init = s_idle) val state = Reg(init = s_idle)
io.req.ready := (state === s_idle) io.req.ready := (state === s_idle)
fq.io.enq.valid := io.grant.valid && io.grant.bits.requiresAck()
fq.io.enq.bits := io.grant.bits.makeFinish()
io.finish.valid := fq.io.deq.valid && (state === s_finish)
io.finish.bits := fq.io.deq.bits
fq.io.deq.ready := io.finish.ready && (state === s_finish)
val storegen = new StoreGen(req.typ, req.addr, req.data, wordBytes) val storegen = new StoreGen(req.typ, req.addr, req.data, wordBytes)
val loadgen = new LoadGen(req.typ, mtSigned(req.typ), req.addr, grant_word, req_cmd_sc, wordBytes) val loadgen = new LoadGen(req.typ, mtSigned(req.typ), req.addr, grant_word, req_cmd_sc, wordBytes)
val beat_mask = (storegen.mask << Cat(beatOffset(req.addr), UInt(0, wordOffBits))) val a_source = UInt(id)
val beat_data = Fill(beatWords, storegen.data) val a_address = req.addr
val a_size = req.typ
val a_data = Fill(beatWords, storegen.data)
val addr_block = req.addr(paddrBits - 1, blockOffBits) val get = edge.Get(a_source, a_address, a_size)._2
val addr_beat = req.addr(blockOffBits - 1, beatOffBits) val put = edge.Put(a_source, a_address, a_size, a_data)._2
val addr_byte = req.addr(beatOffBits - 1, 0) val atomics = if (edge.manager.anySupportLogical) {
MuxLookup(req.cmd, Wire(new TLBundleA(edge.bundle)), Array(
M_XA_SWAP -> edge.Logical(a_source, a_address, a_size, a_data, TLAtomics.SWAP)._2,
M_XA_XOR -> edge.Logical(a_source, a_address, a_size, a_data, TLAtomics.XOR) ._2,
M_XA_OR -> edge.Logical(a_source, a_address, a_size, a_data, TLAtomics.OR) ._2,
M_XA_AND -> edge.Logical(a_source, a_address, a_size, a_data, TLAtomics.AND) ._2,
M_XA_ADD -> edge.Arithmetic(a_source, a_address, a_size, a_data, TLAtomics.ADD)._2,
M_XA_MIN -> edge.Arithmetic(a_source, a_address, a_size, a_data, TLAtomics.MIN)._2,
M_XA_MAX -> edge.Arithmetic(a_source, a_address, a_size, a_data, TLAtomics.MAX)._2,
M_XA_MINU -> edge.Arithmetic(a_source, a_address, a_size, a_data, TLAtomics.MINU)._2,
M_XA_MAXU -> edge.Arithmetic(a_source, a_address, a_size, a_data, TLAtomics.MAXU)._2))
} else {
// If no managers support atomics, assert fail if processor asks for them
assert (!isAMO(req.cmd))
Wire(new TLBundleA(edge.bundle))
}
val get_acquire = Get( io.mem_access.valid := (state === s_mem_access)
client_xact_id = UInt(id), io.mem_access.bits := Mux(isAMO(req.cmd), atomics, Mux(isRead(req.cmd), get, put))
addr_block = addr_block,
addr_beat = addr_beat,
addr_byte = addr_byte,
operand_size = req.typ,
alloc = Bool(false))
val put_acquire = Put( io.replay_next := (state === s_mem_ack) || io.resp.valid && !io.resp.ready
client_xact_id = UInt(id),
addr_block = addr_block,
addr_beat = addr_beat,
data = beat_data,
wmask = Some(beat_mask),
alloc = Bool(false))
val putAtomic_acquire = PutAtomic(
client_xact_id = UInt(id),
addr_block = addr_block,
addr_beat = addr_beat,
addr_byte = addr_byte,
atomic_opcode = req.cmd,
operand_size = req.typ,
data = beat_data)
io.acquire.valid := (state === s_acquire)
io.acquire.bits := Mux(isAMO(req.cmd), putAtomic_acquire, Mux(isRead(req.cmd), get_acquire, put_acquire))
io.replay_next := (state === s_grant) || io.resp.valid && !io.resp.ready
io.resp.valid := (state === s_resp) io.resp.valid := (state === s_resp)
io.resp.bits := req io.resp.bits := req
io.resp.bits.has_data := isRead(req.cmd) io.resp.bits.has_data := isRead(req.cmd)
@@ -245,30 +125,26 @@ class IOMSHR(id: Int)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
when (io.req.fire()) { when (io.req.fire()) {
req := io.req.bits req := io.req.bits
state := s_acquire state := s_mem_access
} }
when (io.acquire.fire()) { when (io.mem_access.fire()) {
state := s_grant state := s_mem_ack
} }
when (state === s_grant && io.grant.valid) { when (state === s_mem_ack && io.mem_ack.valid) {
state := s_resp state := s_resp
when (isRead(req.cmd)) { when (isRead(req.cmd)) {
grant_word := wordFromBeat(req.addr, io.grant.bits.data) grant_word := wordFromBeat(req.addr, io.mem_ack.bits.data)
} }
} }
when (io.resp.fire()) { when (io.resp.fire()) {
state := s_finish
}
when (io.finish.fire()) {
state := s_idle state := s_idle
} }
} }
class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheModule()(p) { class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle { val io = new Bundle {
val req_pri_val = Bool(INPUT) val req_pri_val = Bool(INPUT)
val req_pri_rdy = Bool(OUTPUT) val req_pri_rdy = Bool(OUTPUT)
@@ -279,14 +155,15 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
val idx_match = Bool(OUTPUT) val idx_match = Bool(OUTPUT)
val tag = Bits(OUTPUT, tagBits) val tag = Bits(OUTPUT, tagBits)
val mem_req = Decoupled(new Acquire) val mem_acquire = Decoupled(new TLBundleA(edge.bundle))
val mem_grant = Valid(new TLBundleD(edge.bundle)).flip
val mem_finish = Decoupled(new TLBundleE(edge.bundle))
val refill = new L1RefillReq().asOutput // Data is bypassed val refill = new L1RefillReq().asOutput // Data is bypassed
val meta_read = Decoupled(new L1MetaReadReq) val meta_read = Decoupled(new L1MetaReadReq)
val meta_write = Decoupled(new L1MetaWriteReq) val meta_write = Decoupled(new L1MetaWriteReq)
val replay = Decoupled(new ReplayInternal(cfg)) val replay = Decoupled(new ReplayInternal(cfg))
val mem_grant = Valid(new GrantFromSrc).flip val wb_req = Decoupled(new WritebackReq(edge.bundle))
val mem_finish = Decoupled(new FinishToDst)
val wb_req = Decoupled(new WritebackReq)
val probe_rdy = Bool(OUTPUT) val probe_rdy = Bool(OUTPUT)
} }
@@ -296,6 +173,8 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
val new_coh_state = Reg(init=ClientMetadata.onReset) val new_coh_state = Reg(init=ClientMetadata.onReset)
val req = Reg(new MSHRReqInternal(cfg)) val req = Reg(new MSHRReqInternal(cfg))
val req_idx = req.addr(untagBits-1,blockOffBits) val req_idx = req.addr(untagBits-1,blockOffBits)
val req_tag = req.addr >> untagBits
val req_block_addr = (req.addr >> blockOffBits) << blockOffBits
val idx_match = req_idx === io.req_bits.addr(untagBits-1,blockOffBits) val idx_match = req_idx === io.req_bits.addr(untagBits-1,blockOffBits)
// We only accept secondary misses if we haven't yet sent an Acquire to outer memory // We only accept secondary misses if we haven't yet sent an Acquire to outer memory
// or if the Acquire that was sent will obtain a Grant with sufficient permissions // or if the Acquire that was sent will obtain a Grant with sufficient permissions
@@ -307,9 +186,7 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
// to go from clean to dirty. // to go from clean to dirty.
val dirties_coh = Reg(Bool()) val dirties_coh = Reg(Bool())
val states_before_refill = Seq(s_wb_req, s_wb_resp, s_meta_clear) val states_before_refill = Seq(s_wb_req, s_wb_resp, s_meta_clear)
val gnt_multi_data = io.mem_grant.bits.hasMultibeatData() val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
val (refill_cnt, refill_count_done) = Counter(io.mem_grant.valid && gnt_multi_data, refillCycles)
val refill_done = io.mem_grant.valid && (!gnt_multi_data || refill_count_done)
val sec_rdy = idx_match && val sec_rdy = idx_match &&
(state.isOneOf(states_before_refill) || (state.isOneOf(states_before_refill) ||
(state.isOneOf(s_refill_req, s_refill_resp) && (state.isOneOf(s_refill_req, s_refill_resp) &&
@@ -320,10 +197,11 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
rpq.io.enq.bits := io.req_bits rpq.io.enq.bits := io.req_bits
rpq.io.deq.ready := (io.replay.ready && state === s_drain_rpq) || state === s_invalid rpq.io.deq.ready := (io.replay.ready && state === s_drain_rpq) || state === s_invalid
val coh_on_grant = req.old_meta.coh.onGrant(UInt(0), UInt(0)) val coh_on_grant = Mux(dirties_coh,
//incoming = io.mem_grant.bits, ClientMetadata.maximum,
//pending = Mux(dirties_coh, M_XWR, req.cmd)) req.old_meta.coh.onGrant(req.cmd, io.mem_grant.bits.param))
val coh_on_hit = coh_on_grant //io.req_bits.old_meta.coh.onHit(io.req_bits.cmd) val (is_hit, grow_param, coh_on_hit) = io.req_bits.old_meta.coh.onAccess(io.req_bits.cmd)
val (needs_wb, shrink_param, coh_on_wb) = io.req_bits.old_meta.coh.onCacheControl(M_FLUSH)
when (state === s_drain_rpq && !rpq.io.deq.valid) { when (state === s_drain_rpq && !rpq.io.deq.valid) {
state := s_invalid state := s_invalid
@@ -339,7 +217,7 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
state := s_meta_write_req state := s_meta_write_req
new_coh_state := coh_on_grant new_coh_state := coh_on_grant
} }
when (io.mem_req.fire()) { // s_refill_req when (io.mem_acquire.fire()) { // s_refill_req
state := s_refill_resp state := s_refill_resp
} }
when (state === s_meta_clear && io.meta_write.ready) { when (state === s_meta_clear && io.meta_write.ready) {
@@ -349,7 +227,7 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
state := s_meta_clear state := s_meta_clear
} }
when (io.wb_req.fire()) { // s_wb_req when (io.wb_req.fire()) { // s_wb_req
state := Mux(io.wb_req.bits.requiresAck(), s_wb_resp, s_meta_clear) state := s_wb_resp
} }
when (io.req_sec_val && io.req_sec_rdy) { // s_wb_req, s_wb_resp, s_refill_req when (io.req_sec_val && io.req_sec_rdy) { // s_wb_req, s_wb_resp, s_refill_req
//If we get a secondary miss that needs more permissions before we've sent //If we get a secondary miss that needs more permissions before we've sent
@@ -361,34 +239,32 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
dirties_coh := dirties_coh || isWrite(io.req_bits.cmd) dirties_coh := dirties_coh || isWrite(io.req_bits.cmd)
} }
when (io.req_pri_val && io.req_pri_rdy) { when (io.req_pri_val && io.req_pri_rdy) {
val coh = io.req_bits.old_meta.coh
req := io.req_bits req := io.req_bits
dirties_coh := isWrite(io.req_bits.cmd) dirties_coh := isWrite(io.req_bits.cmd)
when (io.req_bits.tag_match) { when (io.req_bits.tag_match) {
when(Bool(false)) { // TODO coh.isHit(io.req_bits.cmd)) { // set dirty bit when (is_hit) { // set dirty bit
state := s_meta_write_req state := s_meta_write_req
new_coh_state := coh_on_hit new_coh_state := coh_on_hit
}.otherwise { // upgrade permissions }.otherwise { // upgrade permissions
state := s_refill_req state := s_refill_req
} }
}.otherwise { // writback if necessary and refill }.otherwise { // writback if necessary and refill
//TODO state := Mux(coh.requiresVoluntaryWriteback(), s_wb_req, s_meta_clear) state := Mux(needs_wb, s_wb_req, s_meta_clear)
} }
} }
val fq = Module(new FinishQueue(1)) val grantackq = Module(new Queue(io.mem_finish.bits, 1))
val g = io.mem_grant.bits
val can_finish = state.isOneOf(s_invalid, s_refill_req) val can_finish = state.isOneOf(s_invalid, s_refill_req)
fq.io.enq.valid := io.mem_grant.valid && g.requiresAck() && refill_done grantackq.io.enq.valid := refill_done && edge.hasFollowUp(io.mem_grant.bits)
fq.io.enq.bits := g.makeFinish() grantackq.io.enq.bits := edge.GrantAck(io.mem_grant.bits)
io.mem_finish.valid := fq.io.deq.valid && can_finish io.mem_finish.valid := grantackq.io.deq.valid && can_finish
fq.io.deq.ready := io.mem_finish.ready && can_finish io.mem_finish.bits := grantackq.io.deq.bits
io.mem_finish.bits := fq.io.deq.bits grantackq.io.deq.ready := io.mem_finish.ready && can_finish
io.idx_match := (state =/= s_invalid) && idx_match io.idx_match := (state =/= s_invalid) && idx_match
io.refill.way_en := req.way_en io.refill.way_en := req.way_en
io.refill.addr := ((req_idx << log2Ceil(refillCycles)) | refill_cnt) << rowOffBits io.refill.addr := req_block_addr | refill_address_inc
io.tag := req.addr >> untagBits io.tag := req_tag
io.req_pri_rdy := state === s_invalid io.req_pri_rdy := state === s_invalid
io.req_sec_rdy := sec_rdy && rpq.io.enq.ready io.req_sec_rdy := sec_rdy && rpq.io.enq.ready
@@ -406,16 +282,19 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
io.meta_write.bits.way_en := req.way_en io.meta_write.bits.way_en := req.way_en
io.wb_req.valid := state === s_wb_req io.wb_req.valid := state === s_wb_req
//TODO io.wb_req.bits := req.old_meta.coh.makeVoluntaryWriteback( io.wb_req.bits.source := UInt(id)
// client_xact_id = UInt(id), io.wb_req.bits.tag := req.old_meta.tag
// addr_block = Cat(req.old_meta.tag, req_idx)) io.wb_req.bits.idx := req_idx
io.wb_req.bits.param := shrink_param
io.wb_req.bits.way_en := req.way_en io.wb_req.bits.way_en := req.way_en
io.wb_req.bits.voluntary := Bool(true)
io.mem_req.valid := state === s_refill_req && fq.io.enq.ready io.mem_acquire.valid := state === s_refill_req && grantackq.io.enq.ready
//TODO io.mem_req.bits := req.old_meta.coh.makeAcquire( io.mem_acquire.bits := edge.Acquire(
// addr_block = Cat(io.tag, req_idx), fromSource = UInt(id),
// client_xact_id = Bits(id), toAddress = Cat(io.tag, req_idx) << blockOffBits,
// op_code = req.cmd) lgSize = lgCacheBlockBytes,
growPermissions = grow_param)._2
io.meta_read.valid := state === s_drain_rpq io.meta_read.valid := state === s_drain_rpq
io.meta_read.bits.idx := req_idx io.meta_read.bits.idx := req_idx
@@ -432,20 +311,21 @@ class MSHR(id: Int)(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCa
} }
} }
class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheModule()(p) { class MSHRFile(edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle { val io = new Bundle {
val req = Decoupled(new MSHRReq).flip val req = Decoupled(new MSHRReq).flip
val resp = Decoupled(new HellaCacheResp) val resp = Decoupled(new HellaCacheResp)
val secondary_miss = Bool(OUTPUT) val secondary_miss = Bool(OUTPUT)
val mem_req = Decoupled(new Acquire) val mem_acquire = Decoupled(new TLBundleA(edge.bundle))
val mem_grant = Valid(new TLBundleD(edge.bundle)).flip
val mem_finish = Decoupled(new TLBundleE(edge.bundle))
val refill = new L1RefillReq().asOutput val refill = new L1RefillReq().asOutput
val meta_read = Decoupled(new L1MetaReadReq) val meta_read = Decoupled(new L1MetaReadReq)
val meta_write = Decoupled(new L1MetaWriteReq) val meta_write = Decoupled(new L1MetaWriteReq)
val replay = Decoupled(new Replay) val replay = Decoupled(new Replay)
val mem_grant = Valid(new GrantFromSrc).flip val wb_req = Decoupled(new WritebackReq(edge.bundle))
val mem_finish = Decoupled(new FinishToDst)
val wb_req = Decoupled(new WritebackReq)
val probe_rdy = Bool(OUTPUT) val probe_rdy = Bool(OUTPUT)
val fence_rdy = Bool(OUTPUT) val fence_rdy = Bool(OUTPUT)
@@ -453,7 +333,7 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
} }
// determine if the request is cacheable or not // determine if the request is cacheable or not
val cacheable = addrMap.isCacheable(io.req.bits.addr) val cacheable = edge.manager.supportsAcquireFast(io.req.bits.addr, lgCacheBlockBytes)
val sdq_val = Reg(init=Bits(0, cfg.nSDQ)) val sdq_val = Reg(init=Bits(0, cfg.nSDQ))
val sdq_alloc_id = PriorityEncoder(~sdq_val(cfg.nSDQ-1,0)) val sdq_alloc_id = PriorityEncoder(~sdq_val(cfg.nSDQ-1,0))
@@ -470,13 +350,7 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
val refillMux = Wire(Vec(cfg.nMSHRs, new L1RefillReq)) val refillMux = Wire(Vec(cfg.nMSHRs, new L1RefillReq))
val meta_read_arb = Module(new Arbiter(new L1MetaReadReq, cfg.nMSHRs)) val meta_read_arb = Module(new Arbiter(new L1MetaReadReq, cfg.nMSHRs))
val meta_write_arb = Module(new Arbiter(new L1MetaWriteReq, cfg.nMSHRs)) val meta_write_arb = Module(new Arbiter(new L1MetaWriteReq, cfg.nMSHRs))
val mem_req_arb = Module(new LockingArbiter( val wb_req_arb = Module(new Arbiter(new WritebackReq(edge.bundle), cfg.nMSHRs))
new Acquire,
cfg.nMSHRs + nIOMSHRs,
outerDataBeats,
Some((a: Acquire) => a.hasMultibeatData())))
val mem_finish_arb = Module(new Arbiter(new FinishToDst, cfg.nMSHRs + nIOMSHRs))
val wb_req_arb = Module(new Arbiter(new WritebackReq, cfg.nMSHRs))
val replay_arb = Module(new Arbiter(new ReplayInternal(cfg), cfg.nMSHRs)) val replay_arb = Module(new Arbiter(new ReplayInternal(cfg), cfg.nMSHRs))
val alloc_arb = Module(new Arbiter(Bool(), cfg.nMSHRs)) val alloc_arb = Module(new Arbiter(Bool(), cfg.nMSHRs))
@@ -487,12 +361,12 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
io.fence_rdy := true io.fence_rdy := true
io.probe_rdy := true io.probe_rdy := true
for (i <- 0 until cfg.nMSHRs) { val mshrs = (0 until cfg.nMSHRs) map { i =>
val mshr = Module(new MSHR(i)(cfg)) val mshr = Module(new MSHR(i,edge)(cfg,p))
idxMatch(i) := mshr.io.idx_match idxMatch(i) := mshr.io.idx_match
tagList(i) := mshr.io.tag tagList(i) := mshr.io.tag
wbTagList(i) := mshr.io.wb_req.bits.addr_block >> idxBits wbTagList(i) := mshr.io.wb_req.bits.tag
alloc_arb.io.in(i).valid := mshr.io.req_pri_rdy alloc_arb.io.in(i).valid := mshr.io.req_pri_rdy
mshr.io.req_pri_val := alloc_arb.io.in(i).ready mshr.io.req_pri_val := alloc_arb.io.in(i).ready
@@ -503,13 +377,10 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
meta_read_arb.io.in(i) <> mshr.io.meta_read meta_read_arb.io.in(i) <> mshr.io.meta_read
meta_write_arb.io.in(i) <> mshr.io.meta_write meta_write_arb.io.in(i) <> mshr.io.meta_write
mem_req_arb.io.in(i) <> mshr.io.mem_req
mem_finish_arb.io.in(i) <> mshr.io.mem_finish
wb_req_arb.io.in(i) <> mshr.io.wb_req wb_req_arb.io.in(i) <> mshr.io.wb_req
replay_arb.io.in(i) <> mshr.io.replay replay_arb.io.in(i) <> mshr.io.replay
mshr.io.mem_grant.valid := io.mem_grant.valid && mshr.io.mem_grant.valid := io.mem_grant.valid && io.mem_grant.bits.source === UInt(i)
io.mem_grant.bits.client_xact_id === UInt(i)
mshr.io.mem_grant.bits := io.mem_grant.bits mshr.io.mem_grant.bits := io.mem_grant.bits
refillMux(i) := mshr.io.refill refillMux(i) := mshr.io.refill
@@ -519,14 +390,15 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
when (!mshr.io.req_pri_rdy) { io.fence_rdy := false } when (!mshr.io.req_pri_rdy) { io.fence_rdy := false }
when (!mshr.io.probe_rdy) { io.probe_rdy := false } when (!mshr.io.probe_rdy) { io.probe_rdy := false }
mshr
} }
alloc_arb.io.out.ready := io.req.valid && sdq_rdy && cacheable && !idx_match alloc_arb.io.out.ready := io.req.valid && sdq_rdy && cacheable && !idx_match
io.meta_read <> meta_read_arb.io.out io.meta_read <> meta_read_arb.io.out
io.meta_write <> meta_write_arb.io.out io.meta_write <> meta_write_arb.io.out
io.mem_req <> mem_req_arb.io.out
io.mem_finish <> mem_finish_arb.io.out
io.wb_req <> wb_req_arb.io.out io.wb_req <> wb_req_arb.io.out
val mmio_alloc_arb = Module(new Arbiter(Bool(), nIOMSHRs)) val mmio_alloc_arb = Module(new Arbiter(Bool(), nIOMSHRs))
@@ -535,9 +407,9 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
var mmio_rdy = Bool(false) var mmio_rdy = Bool(false)
io.replay_next := Bool(false) io.replay_next := Bool(false)
for (i <- 0 until nIOMSHRs) { val mmios = (0 until nIOMSHRs) map { i =>
val id = cfg.nMSHRs + i val id = cfg.nMSHRs + i
val mshr = Module(new IOMSHR(id)) val mshr = Module(new IOMSHR(id, edge))
mmio_alloc_arb.io.in(i).valid := mshr.io.req.ready mmio_alloc_arb.io.in(i).valid := mshr.io.req.ready
mshr.io.req.valid := mmio_alloc_arb.io.in(i).ready mshr.io.req.valid := mmio_alloc_arb.io.in(i).ready
@@ -545,26 +417,28 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
mmio_rdy = mmio_rdy || mshr.io.req.ready mmio_rdy = mmio_rdy || mshr.io.req.ready
mem_req_arb.io.in(id) <> mshr.io.acquire mshr.io.mem_ack.bits := io.mem_grant.bits
mem_finish_arb.io.in(id) <> mshr.io.finish mshr.io.mem_ack.valid := io.mem_grant.valid && io.mem_grant.bits.source === UInt(id)
mshr.io.grant.bits := io.mem_grant.bits
mshr.io.grant.valid := io.mem_grant.valid &&
io.mem_grant.bits.client_xact_id === UInt(id)
resp_arb.io.in(i) <> mshr.io.resp resp_arb.io.in(i) <> mshr.io.resp
when (!mshr.io.req.ready) { io.fence_rdy := Bool(false) } when (!mshr.io.req.ready) { io.fence_rdy := Bool(false) }
when (mshr.io.replay_next) { io.replay_next := Bool(true) } when (mshr.io.replay_next) { io.replay_next := Bool(true) }
mshr
} }
mmio_alloc_arb.io.out.ready := io.req.valid && !cacheable mmio_alloc_arb.io.out.ready := io.req.valid && !cacheable
TLArbiter.lowestFromSeq(edge, io.mem_acquire, mshrs.map(_.io.mem_acquire) ++ mmios.map(_.io.mem_access))
TLArbiter.lowestFromSeq(edge, io.mem_finish, mshrs.map(_.io.mem_finish))
io.resp <> resp_arb.io.out io.resp <> resp_arb.io.out
io.req.ready := Mux(!cacheable, mmio_rdy, io.req.ready := Mux(!cacheable,
Mux(idx_match, tag_match && sec_rdy, pri_rdy) && sdq_rdy) mmio_rdy,
sdq_rdy && Mux(idx_match, tag_match && sec_rdy, pri_rdy))
io.secondary_miss := idx_match io.secondary_miss := idx_match
io.refill := refillMux(io.mem_grant.bits.client_xact_id) io.refill := refillMux(io.mem_grant.bits.source)
val free_sdq = io.replay.fire() && isWrite(io.replay.bits.cmd) val free_sdq = io.replay.fire() && isWrite(io.replay.bits.cmd)
io.replay.bits.data := sdq(RegEnable(replay_arb.io.out.bits.sdq_id, free_sdq)) io.replay.bits.data := sdq(RegEnable(replay_arb.io.out.bits.sdq_id, free_sdq))
@@ -576,23 +450,21 @@ class MSHRFile(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheMo
} }
} }
class WritebackUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) { class WritebackUnit(edge: TLEdgeOut)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle { val io = new Bundle {
val req = Decoupled(new WritebackReq).flip val req = Decoupled(new WritebackReq(edge.bundle)).flip
val meta_read = Decoupled(new L1MetaReadReq) val meta_read = Decoupled(new L1MetaReadReq)
val data_req = Decoupled(new L1DataReadReq) val data_req = Decoupled(new L1DataReadReq)
val data_resp = Bits(INPUT, encRowBits) val data_resp = Bits(INPUT, encRowBits)
val release = Decoupled(new Release) val release = Decoupled(new TLBundleC(edge.bundle))
} }
val req = Reg(new WritebackReq(edge.bundle))
val active = Reg(init=Bool(false)) val active = Reg(init=Bool(false))
val r1_data_req_fired = Reg(init=Bool(false)) val r1_data_req_fired = Reg(init=Bool(false))
val r2_data_req_fired = Reg(init=Bool(false)) val r2_data_req_fired = Reg(init=Bool(false))
val data_req_cnt = Reg(init = UInt(0, width = log2Up(refillCycles+1))) //TODO Zero width val data_req_cnt = Reg(init = UInt(0, width = log2Up(refillCycles+1))) //TODO Zero width
val buf_v = (if(refillCyclesPerBeat > 1) Reg(init=Bits(0, width = refillCyclesPerBeat-1)) else Bits(1)) val (_, last_beat, all_beats_done, beat_count) = edge.count(io.release)
val beat_done = buf_v.andR
val (beat_cnt, all_beats_done) = Counter(io.release.fire(), outerDataBeats)
val req = Reg(new WritebackReq)
io.release.valid := false io.release.valid := false
when (active) { when (active) {
@@ -603,13 +475,11 @@ class WritebackUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) {
data_req_cnt := data_req_cnt + 1 data_req_cnt := data_req_cnt + 1
} }
when (r2_data_req_fired) { when (r2_data_req_fired) {
io.release.valid := beat_done io.release.valid := true
when(beat_done) {
when(!io.release.ready) { when(!io.release.ready) {
r1_data_req_fired := false r1_data_req_fired := false
r2_data_req_fired := false r2_data_req_fired := false
data_req_cnt := data_req_cnt - Mux[UInt](Bool(refillCycles > 1) && r1_data_req_fired, 2, 1) data_req_cnt := data_req_cnt - Mux[UInt](Bool(refillCycles > 1) && r1_data_req_fired, 2, 1)
} .otherwise { if(refillCyclesPerBeat > 1) buf_v := 0 }
} }
when(!r1_data_req_fired) { when(!r1_data_req_fired) {
// We're done if this is the final data request and the Release can be sent // We're done if this is the final data request and the Release can be sent
@@ -620,49 +490,49 @@ class WritebackUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) {
when (io.req.fire()) { when (io.req.fire()) {
active := true active := true
data_req_cnt := 0 data_req_cnt := 0
if(refillCyclesPerBeat > 1) buf_v := 0
req := io.req.bits req := io.req.bits
} }
io.req.ready := !active io.req.ready := !active
val req_idx = req.addr_block(idxBits-1, 0)
val fire = active && data_req_cnt < UInt(refillCycles) val fire = active && data_req_cnt < UInt(refillCycles)
// We reissue the meta read as it sets up the mux ctrl for s2_data_muxed // We reissue the meta read as it sets up the mux ctrl for s2_data_muxed
io.meta_read.valid := fire io.meta_read.valid := fire
io.meta_read.bits.idx := req_idx io.meta_read.bits.idx := req.idx
io.meta_read.bits.tag := req.addr_block >> idxBits io.meta_read.bits.tag := req.tag
io.data_req.valid := fire io.data_req.valid := fire
io.data_req.bits.way_en := req.way_en io.data_req.bits.way_en := req.way_en
io.data_req.bits.addr := (if(refillCycles > 1) io.data_req.bits.addr := (if(refillCycles > 1)
Cat(req_idx, data_req_cnt(log2Up(refillCycles)-1,0)) Cat(req.idx, data_req_cnt(log2Up(refillCycles)-1,0))
else req_idx) << rowOffBits else req.idx) << rowOffBits
io.release.bits := req val r_address = Cat(req.tag, req.idx) << blockOffBits
io.release.bits.addr_beat := beat_cnt val probeResponse = edge.ProbeAck(
io.release.bits.data := (if(refillCyclesPerBeat > 1) { fromSource = req.source,
// If the cache rows are narrower than a TLDataBeat, toAddress = r_address,
// then buffer enough data_resps to make a whole beat lgSize = lgCacheBlockBytes,
val data_buf = Reg(Bits()) reportPermissions = req.param,
when(active && r2_data_req_fired && !beat_done) { data = io.data_resp)
data_buf := Cat(io.data_resp, data_buf((refillCyclesPerBeat)*encRowBits-1, encRowBits))
buf_v := (if(refillCyclesPerBeat > 2) val voluntaryRelease = edge.Release(
Cat(UInt(1), buf_v(refillCyclesPerBeat-2,1)) fromSource = req.source,
else UInt(1)) toAddress = r_address,
} lgSize = lgCacheBlockBytes,
Cat(io.data_resp, data_buf) shrinkPermissions = req.param,
} else { io.data_resp }) data = io.data_resp)._2
io.release.bits := Mux(req.voluntary, voluntaryRelease, probeResponse)
} }
class ProbeUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) { class ProbeUnit(edge: TLEdgeOut)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle { val io = new Bundle {
val req = Decoupled(new ProbeInternal).flip val req = Decoupled(new TLBundleB(edge.bundle)).flip
val rep = Decoupled(new Release) val rep = Decoupled(new TLBundleC(edge.bundle))
val meta_read = Decoupled(new L1MetaReadReq) val meta_read = Decoupled(new L1MetaReadReq)
val meta_write = Decoupled(new L1MetaWriteReq) val meta_write = Decoupled(new L1MetaWriteReq)
val wb_req = Decoupled(new WritebackReq) val wb_req = Decoupled(new WritebackReq(edge.bundle))
val way_en = Bits(INPUT, nWays) val way_en = Bits(INPUT, nWays)
val mshr_rdy = Bool(INPUT) val mshr_rdy = Bool(INPUT)
val block_state = new ClientMetadata().asInput val block_state = new ClientMetadata().asInput
@@ -672,34 +542,42 @@ class ProbeUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) {
s_mshr_resp :: s_release :: s_writeback_req :: s_writeback_resp :: s_mshr_resp :: s_release :: s_writeback_req :: s_writeback_resp ::
s_meta_write :: Nil) = Enum(UInt(), 9) s_meta_write :: Nil) = Enum(UInt(), 9)
val state = Reg(init=s_invalid) val state = Reg(init=s_invalid)
val old_coh = Reg(new ClientMetadata)
val way_en = Reg(Bits())
val req = Reg(new ProbeInternal)
val tag_matches = way_en.orR
val req = Reg(new TLBundleB(edge.bundle))
val req_idx = req.address(idxMSB, idxLSB)
val req_tag = req.address >> untagBits
val way_en = Reg(Bits())
val tag_matches = way_en.orR
val old_coh = Reg(new ClientMetadata)
val miss_coh = ClientMetadata.onReset val miss_coh = ClientMetadata.onReset
val reply_coh = Mux(tag_matches, old_coh, miss_coh) val reply_coh = Mux(tag_matches, old_coh, miss_coh)
//TODO val reply = reply_coh.makeRelease(req) val (is_dirty, report_param, new_coh) = reply_coh.onProbe(req.param)
io.req.ready := state === s_invalid io.req.ready := state === s_invalid
io.rep.valid := state === s_release io.rep.valid := state === s_release
//TODO io.rep.bits := reply io.rep.bits := edge.ProbeAck(req, report_param)
assert(!io.rep.valid || !io.rep.bits.hasData(), assert(!io.rep.valid || !edge.hasData(io.rep.bits),
"ProbeUnit should not send releases with data") "ProbeUnit should not send ProbeAcks with data, WritebackUnit should handle it")
io.meta_read.valid := state === s_meta_read io.meta_read.valid := state === s_meta_read
io.meta_read.bits.idx := req.addr_block io.meta_read.bits.idx := req_idx
io.meta_read.bits.tag := req.addr_block >> idxBits io.meta_read.bits.tag := req_tag
io.meta_write.valid := state === s_meta_write io.meta_write.valid := state === s_meta_write
io.meta_write.bits.way_en := way_en io.meta_write.bits.way_en := way_en
io.meta_write.bits.idx := req.addr_block io.meta_write.bits.idx := req_idx
io.meta_write.bits.data.tag := req.addr_block >> idxBits io.meta_write.bits.data.tag := req_tag
//TODO io.meta_write.bits.data.coh := old_coh.onProbe(req) io.meta_write.bits.data.coh := new_coh
io.wb_req.valid := state === s_writeback_req io.wb_req.valid := state === s_writeback_req
//TODO io.wb_req.bits := reply io.wb_req.bits.source := req.source
io.wb_req.bits.idx := req_idx
io.wb_req.bits.tag := req_tag
io.wb_req.bits.param := report_param
io.wb_req.bits.way_en := way_en io.wb_req.bits.way_en := way_en
io.wb_req.bits.voluntary := Bool(false)
// state === s_invalid // state === s_invalid
when (io.req.fire()) { when (io.req.fire()) {
@@ -718,16 +596,14 @@ class ProbeUnit(implicit p: Parameters) extends L1HellaCacheModule()(p) {
} }
when (state === s_mshr_req) { when (state === s_mshr_req) {
state := s_mshr_resp
old_coh := io.block_state old_coh := io.block_state
way_en := io.way_en way_en := io.way_en
// if the read didn't go through, we need to retry // if the read didn't go through, we need to retry
when (!io.mshr_rdy) { state := s_meta_read } state := Mux(io.mshr_rdy, s_mshr_resp, s_meta_read)
} }
when (state === s_mshr_resp) { when (state === s_mshr_resp) {
val needs_writeback = tag_matches // TODO && old_coh.requiresVoluntaryWriteback() state := Mux(tag_matches && is_dirty, s_writeback_req, s_release)
state := Mux(needs_writeback, s_writeback_req, s_release)
} }
when (state === s_release && io.rep.ready) { when (state === s_release && io.rep.ready) {
@@ -796,18 +672,17 @@ class DataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
io.write.ready := Bool(true) io.write.ready := Bool(true)
} }
class HellaCache(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCacheModule()(p) { class NonBlockingDCache(cfg: DCacheConfig)(implicit p: Parameters) extends HellaCache(cfg)(p) {
val io = new Bundle { override lazy val module = new NonBlockingDCacheModule(this)
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val mem = new ClientTileLinkIO
} }
class NonBlockingDCacheModule(outer: NonBlockingDCache)(implicit p: Parameters) extends HellaCacheModule(outer)(p) {
require(isPow2(nWays)) // TODO: relax this require(isPow2(nWays)) // TODO: relax this
val wb = Module(new WritebackUnit) val wb = Module(new WritebackUnit(edge))
val prober = Module(new ProbeUnit) val prober = Module(new ProbeUnit(edge))
val mshrs = Module(new MSHRFile(cfg)) val mshrs = Module(new MSHRFile(edge))
io.cpu.req.ready := Bool(true) io.cpu.req.ready := Bool(true)
val s1_valid = Reg(next=io.cpu.req.fire(), init=Bool(false)) val s1_valid = Reg(next=io.cpu.req.fire(), init=Bool(false))
@@ -990,7 +865,7 @@ class HellaCache(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCache
mshrs.io.req.bits.way_en := Mux(s2_tag_match, s2_tag_match_way, s2_replaced_way_en) mshrs.io.req.bits.way_en := Mux(s2_tag_match, s2_tag_match_way, s2_replaced_way_en)
mshrs.io.req.bits.data := s2_req.data mshrs.io.req.bits.data := s2_req.data
when (mshrs.io.req.fire()) { replacer.miss } when (mshrs.io.req.fire()) { replacer.miss }
io.mem.acquire <> mshrs.io.mem_req tl_out.a <> mshrs.io.mem_acquire
// replays // replays
readArb.io.in(1).valid := mshrs.io.replay.valid readArb.io.in(1).valid := mshrs.io.replay.valid
@@ -1002,15 +877,9 @@ class HellaCache(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCache
metaWriteArb.io.in(0) <> mshrs.io.meta_write metaWriteArb.io.in(0) <> mshrs.io.meta_write
// probes and releases // probes and releases
val releaseArb = Module(new LockingArbiter( prober.io.req.valid := tl_out.b.valid && !lrsc_valid
new Release, 2, outerDataBeats, tl_out.b.ready := prober.io.req.ready && !lrsc_valid
Some((r: Release) => r.hasMultibeatData()))) prober.io.req.bits := tl_out.b.bits
io.mem.release <> releaseArb.io.out
prober.io.req.valid := io.mem.probe.valid && !lrsc_valid
io.mem.probe.ready := prober.io.req.ready && !lrsc_valid
prober.io.req.bits := io.mem.probe.bits
releaseArb.io.in(1) <> prober.io.rep
prober.io.way_en := s2_tag_match_way prober.io.way_en := s2_tag_match_way
prober.io.block_state := s2_hit_state prober.io.block_state := s2_hit_state
metaReadArb.io.in(2) <> prober.io.meta_read metaReadArb.io.in(2) <> prober.io.meta_read
@@ -1018,32 +887,32 @@ class HellaCache(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCache
prober.io.mshr_rdy := mshrs.io.probe_rdy prober.io.mshr_rdy := mshrs.io.probe_rdy
// refills // refills
val narrow_grant = FlowThroughSerializer(io.mem.grant, refillCyclesPerBeat) val grant_has_data = edge.hasData(tl_out.d.bits)
mshrs.io.mem_grant.valid := narrow_grant.fire() mshrs.io.mem_grant.valid := tl_out.d.fire()
mshrs.io.mem_grant.bits := narrow_grant.bits mshrs.io.mem_grant.bits := tl_out.d.bits
narrow_grant.ready := writeArb.io.in(1).ready || !narrow_grant.bits.hasData() tl_out.d.ready := writeArb.io.in(1).ready || !grant_has_data
/* The last clause here is necessary in order to prevent the responses for /* The last clause here is necessary in order to prevent the responses for
* the IOMSHRs from being written into the data array. It works because the * the IOMSHRs from being written into the data array. It works because the
* IOMSHR ids start right the ones for the regular MSHRs. */ * IOMSHR ids start right the ones for the regular MSHRs. */
writeArb.io.in(1).valid := narrow_grant.valid && narrow_grant.bits.hasData() && writeArb.io.in(1).valid := tl_out.d.valid && grant_has_data &&
narrow_grant.bits.client_xact_id < UInt(cfg.nMSHRs) tl_out.d.bits.source < UInt(cfg.nMSHRs)
writeArb.io.in(1).bits.addr := mshrs.io.refill.addr writeArb.io.in(1).bits.addr := mshrs.io.refill.addr
writeArb.io.in(1).bits.way_en := mshrs.io.refill.way_en writeArb.io.in(1).bits.way_en := mshrs.io.refill.way_en
writeArb.io.in(1).bits.wmask := ~UInt(0, rowWords) writeArb.io.in(1).bits.wmask := ~UInt(0, rowWords)
writeArb.io.in(1).bits.data := narrow_grant.bits.data(encRowBits-1,0) writeArb.io.in(1).bits.data := tl_out.d.bits.data(encRowBits-1,0)
data.io.read <> readArb.io.out data.io.read <> readArb.io.out
readArb.io.out.ready := !narrow_grant.valid || narrow_grant.ready // insert bubble if refill gets blocked readArb.io.out.ready := !tl_out.d.valid || tl_out.d.ready // insert bubble if refill gets blocked
io.mem.finish <> mshrs.io.mem_finish tl_out.e <> mshrs.io.mem_finish
// writebacks // writebacks
val wbArb = Module(new Arbiter(new WritebackReq, 2)) val wbArb = Module(new Arbiter(new WritebackReq(edge.bundle), 2))
wbArb.io.in(0) <> prober.io.wb_req wbArb.io.in(0) <> prober.io.wb_req
wbArb.io.in(1) <> mshrs.io.wb_req wbArb.io.in(1) <> mshrs.io.wb_req
wb.io.req <> wbArb.io.out wb.io.req <> wbArb.io.out
metaReadArb.io.in(3) <> wb.io.meta_read metaReadArb.io.in(3) <> wb.io.meta_read
readArb.io.in(2) <> wb.io.data_req readArb.io.in(2) <> wb.io.data_req
wb.io.data_resp := s2_data_corrected wb.io.data_resp := s2_data_corrected
releaseArb.io.in(0) <> wb.io.release TLArbiter.lowest(edge, tl_out.c, wb.io.release, prober.io.rep)
// store->load bypassing // store->load bypassing
val s4_valid = Reg(next=s3_valid, init=Bool(false)) val s4_valid = Reg(next=s3_valid, init=Bool(false))
@@ -1115,138 +984,3 @@ class HellaCache(cfg: DCacheConfig)(implicit p: Parameters) extends L1HellaCache
io.cpu.ordered := mshrs.io.fence_rdy && !s1_valid && !s2_valid io.cpu.ordered := mshrs.io.fence_rdy && !s1_valid && !s2_valid
io.cpu.replay_next := (s1_replay && s1_read) || mshrs.io.replay_next io.cpu.replay_next := (s1_replay && s1_read) || mshrs.io.replay_next
} }
/**
* This module buffers requests made by the SimpleHellaCacheIF in case they
* are nacked. Nacked requests must be replayed in order, and no other requests
* must be allowed to go through until the replayed requests are successfully
* completed.
*/
class SimpleHellaCacheIFReplayQueue(depth: Int)
(implicit val p: Parameters) extends Module
with HasL1HellaCacheParameters {
val io = new Bundle {
val req = Decoupled(new HellaCacheReq).flip
val nack = Valid(Bits(width = coreDCacheReqTagBits)).flip
val resp = Valid(new HellaCacheResp).flip
val replay = Decoupled(new HellaCacheReq)
}
// Registers to store the sent request
// When a request is sent the first time,
// it is stored in one of the reqs registers
// and the corresponding inflight bit is set.
// The reqs register will be deallocated once the request is
// successfully completed.
val inflight = Reg(init = UInt(0, depth))
val reqs = Reg(Vec(depth, new HellaCacheReq))
// The nack queue stores the index of nacked requests (in the reqs vector)
// in the order that they were nacked. A request is enqueued onto nackq
// when it is newly nacked (i.e. not a nack for a previous replay).
// The head of the nack queue will be replayed until it is
// successfully completed, at which time the request is dequeued.
// No new requests will be made or other replays attempted until the head
// of the nackq is successfully completed.
val nackq = Module(new Queue(UInt(width = log2Up(depth)), depth))
val replaying = Reg(init = Bool(false))
val next_inflight_onehot = PriorityEncoderOH(~inflight)
val next_inflight = OHToUInt(next_inflight_onehot)
val next_replay = nackq.io.deq.bits
val next_replay_onehot = UIntToOH(next_replay)
val next_replay_req = reqs(next_replay)
// Keep sending the head of the nack queue until it succeeds
io.replay.valid := nackq.io.deq.valid && !replaying
io.replay.bits := next_replay_req
// Don't allow new requests if there is are replays waiting
// or something being nacked.
io.req.ready := !inflight.andR && !nackq.io.deq.valid && !io.nack.valid
// Match on the tags to determine the index of nacks or responses
val nack_onehot = Cat(reqs.map(_.tag === io.nack.bits).reverse) & inflight
val resp_onehot = Cat(reqs.map(_.tag === io.resp.bits.tag).reverse) & inflight
val replay_complete = io.resp.valid && replaying && io.resp.bits.tag === next_replay_req.tag
val nack_head = io.nack.valid && nackq.io.deq.valid && io.nack.bits === next_replay_req.tag
// Enqueue to the nack queue if there is a nack that is not in response to
// the previous replay
nackq.io.enq.valid := io.nack.valid && !nack_head
nackq.io.enq.bits := OHToUInt(nack_onehot)
assert(!nackq.io.enq.valid || nackq.io.enq.ready,
"SimpleHellaCacheIF: ReplayQueue nack queue overflow")
// Dequeue from the nack queue if the last replay was successfully completed
nackq.io.deq.ready := replay_complete
assert(!nackq.io.deq.ready || nackq.io.deq.valid,
"SimpleHellaCacheIF: ReplayQueue nack queue underflow")
// Set inflight bit when a request is made
// Clear it when it is successfully completed
inflight := (inflight | Mux(io.req.fire(), next_inflight_onehot, UInt(0))) &
~Mux(io.resp.valid, resp_onehot, UInt(0))
when (io.req.fire()) {
reqs(next_inflight) := io.req.bits
}
// Only one replay outstanding at a time
when (io.replay.fire()) { replaying := Bool(true) }
when (nack_head || replay_complete) { replaying := Bool(false) }
}
// exposes a sane decoupled request interface
class SimpleHellaCacheIF(implicit p: Parameters) extends Module
{
val io = new Bundle {
val requestor = new HellaCacheIO().flip
val cache = new HellaCacheIO
}
val replayq = Module(new SimpleHellaCacheIFReplayQueue(2))
val req_arb = Module(new Arbiter(new HellaCacheReq, 2))
val req_helper = DecoupledHelper(
req_arb.io.in(1).ready,
replayq.io.req.ready,
io.requestor.req.valid)
req_arb.io.in(0) <> replayq.io.replay
req_arb.io.in(1).valid := req_helper.fire(req_arb.io.in(1).ready)
req_arb.io.in(1).bits := io.requestor.req.bits
io.requestor.req.ready := req_helper.fire(io.requestor.req.valid)
replayq.io.req.valid := req_helper.fire(replayq.io.req.ready)
replayq.io.req.bits := io.requestor.req.bits
val s0_req_fire = io.cache.req.fire()
val s1_req_fire = Reg(next = s0_req_fire)
val s2_req_fire = Reg(next = s1_req_fire)
val s1_req_tag = Reg(next = io.cache.req.bits.tag)
val s2_req_tag = Reg(next = s1_req_tag)
val s2_kill = Reg(next = io.cache.s1_kill)
io.cache.invalidate_lr := io.requestor.invalidate_lr
io.cache.req <> req_arb.io.out
io.cache.s1_kill := io.cache.s2_nack
io.cache.s1_data := RegEnable(req_arb.io.out.bits.data, s0_req_fire)
replayq.io.nack.valid := (io.cache.s2_nack || s2_kill) && s2_req_fire
replayq.io.nack.bits := s2_req_tag
replayq.io.resp := io.cache.resp
io.requestor.resp := io.cache.resp
assert(!Reg(next = io.cache.req.fire()) ||
!(io.cache.xcpt.ma.ld || io.cache.xcpt.ma.st ||
io.cache.xcpt.pf.ld || io.cache.xcpt.pf.st),
"SimpleHellaCacheIF exception")
}
object HellaCache {
def apply(cfg: DCacheConfig)(implicit p: Parameters) = LazyModule(new DCache)
// TODO convert non-blocking cache
// if (cfg.nMSHRs == 0) Module(new DCache()).io
// else Module(new HellaCache(cfg)).io
}
@@ -13,6 +13,14 @@ object TLArbiter
val lowestIndexFirst: Policy = (valids, granted) => val lowestIndexFirst: Policy = (valids, granted) =>
valids.scanLeft(Bool(true))(_ && !_).init valids.scanLeft(Bool(true))(_ && !_).init
def lowestFromSeq[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: Seq[DecoupledIO[T]]) {
apply(lowestIndexFirst)(sink, sources.map(s => (edge.numBeats1(s.bits), s)):_*)
}
def lowest[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: DecoupledIO[T]*) {
apply(lowestIndexFirst)(sink, sources.toList.map(s => (edge.numBeats1(s.bits), s)):_*)
}
def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) { def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) {
if (sources.isEmpty) { if (sources.isEmpty) {
sink.valid := Bool(false) sink.valid := Bool(false)
@@ -136,11 +136,9 @@ class TLBroadcast(lineBytes: Int, numTrackers: Int = 4, bufferless: Boolean = fa
putfull.bits := edgeOut.Put(Cat(put_what, in.c.bits.source), in.c.bits.address, in.c.bits.size, in.c.bits.data)._2 putfull.bits := edgeOut.Put(Cat(put_what, in.c.bits.source), in.c.bits.address, in.c.bits.size, in.c.bits.data)._2
// Combine ReleaseAck or the modified D // Combine ReleaseAck or the modified D
TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (UInt(0), releaseack), (edgeOut.numBeats1(d_normal.bits), d_normal)) TLArbiter.lowest(edgeOut, in.d, releaseack, d_normal)
// Combine the PutFull with the trackers // Combine the PutFull with the trackers
TLArbiter(TLArbiter.lowestIndexFirst)(out.a, TLArbiter.lowestFromSeq(edgeOut, out.a, putfull +: trackers.map(_.out_a))
((edgeOut.numBeats1(putfull.bits), putfull) +:
trackers.map { t => (edgeOut.numBeats1(t.out_a.bits), t.out_a) }):_*)
// The Probe FSM walks all caches and probes them // The Probe FSM walks all caches and probes them
val probe_todo = RegInit(UInt(0, width = max(1, caches.size))) val probe_todo = RegInit(UInt(0, width = max(1, caches.size)))
@@ -191,27 +191,32 @@ class TLEdge(
def first(bits: TLChannel, fire: Bool): Bool = firstlastHelper(bits, fire)._1 def first(bits: TLChannel, fire: Bool): Bool = firstlastHelper(bits, fire)._1
def first(x: DecoupledIO[TLChannel]): Bool = first(x.bits, x.fire()) def first(x: DecoupledIO[TLChannel]): Bool = first(x.bits, x.fire())
def first(x: ValidIO[TLChannel]): Bool = first(x.bits, x.valid)
def last(bits: TLChannel, fire: Bool): Bool = firstlastHelper(bits, fire)._2 def last(bits: TLChannel, fire: Bool): Bool = firstlastHelper(bits, fire)._2
def last(x: DecoupledIO[TLChannel]): Bool = last(x.bits, x.fire()) def last(x: DecoupledIO[TLChannel]): Bool = last(x.bits, x.fire())
def last(x: ValidIO[TLChannel]): Bool = last(x.bits, x.valid)
def firstlast(bits: TLChannel, fire: Bool): (Bool, Bool, Bool) = { def firstlast(bits: TLChannel, fire: Bool): (Bool, Bool, Bool) = {
val r = firstlastHelper(bits, fire) val r = firstlastHelper(bits, fire)
(r._1, r._2, r._3) (r._1, r._2, r._3)
} }
def firstlast(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool) = firstlast(x.bits, x.fire()) def firstlast(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool) = firstlast(x.bits, x.fire())
def firstlast(x: ValidIO[TLChannel]): (Bool, Bool, Bool) = firstlast(x.bits, x.valid)
def count(bits: TLChannel, fire: Bool): (Bool, Bool, Bool, UInt) = { def count(bits: TLChannel, fire: Bool): (Bool, Bool, Bool, UInt) = {
val r = firstlastHelper(bits, fire) val r = firstlastHelper(bits, fire)
(r._1, r._2, r._3, r._4) (r._1, r._2, r._3, r._4)
} }
def count(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool, UInt) = count(x.bits, x.fire()) def count(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool, UInt) = count(x.bits, x.fire())
def count(x: ValidIO[TLChannel]): (Bool, Bool, Bool, UInt) = count(x.bits, x.valid)
def addr_inc(bits: TLChannel, fire: Bool): (Bool, Bool, Bool, UInt) = { def addr_inc(bits: TLChannel, fire: Bool): (Bool, Bool, Bool, UInt) = {
val r = firstlastHelper(bits, fire) val r = firstlastHelper(bits, fire)
(r._1, r._2, r._3, r._4 << log2Ceil(manager.beatBytes)) (r._1, r._2, r._3, r._4 << log2Ceil(manager.beatBytes))
} }
def addr_inc(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool, UInt) = addr_inc(x.bits, x.fire()) def addr_inc(x: DecoupledIO[TLChannel]): (Bool, Bool, Bool, UInt) = addr_inc(x.bits, x.fire())
def addr_inc(x: ValidIO[TLChannel]): (Bool, Bool, Bool, UInt) = addr_inc(x.bits, x.valid)
} }
class TLEdgeOut( class TLEdgeOut(