1
0
Fork 0
rocket-chip/src/main/scala/rocket/HellaCache.scala

272 lines
9.2 KiB
Scala

// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
package freechips.rocketchip.rocket
import Chisel._
import chisel3.experimental.dontTouch
import freechips.rocketchip.config.{Parameters, Field}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import scala.collection.mutable.ListBuffer
import scala.math.max
case class DCacheParams(
nSets: Int = 64,
nWays: Int = 4,
rowBits: Int = 64,
nTLBEntries: Int = 32,
tagECC: Code = new IdentityCode,
dataECC: Code = new IdentityCode,
dataECCBytes: Int = 1,
nMSHRs: Int = 1,
nSDQ: Int = 17,
nRPQ: Int = 16,
nMMIOs: Int = 1,
blockBytes: Int = 64,
acquireBeforeRelease: Boolean = false,
pipelineWayMux: Boolean = false,
scratch: Option[BigInt] = None) extends L1CacheParams {
def dataScratchpadBytes: Int = scratch.map(_ => nSets*blockBytes).getOrElse(0)
def replacement = new RandomReplacement(nWays)
require((!scratch.isDefined || nWays == 1),
"Scratchpad only allowed in direct-mapped cache.")
require((!scratch.isDefined || nMSHRs == 0),
"Scratchpad only allowed in blocking cache.")
require(isPow2(nSets), s"nSets($nSets) must be pow2")
}
trait HasL1HellaCacheParameters extends HasL1CacheParameters with HasCoreParameters {
val cacheParams = tileParams.dcache.get
val cfg = cacheParams
def wordBits = coreDataBits
def wordBytes = coreDataBytes
def wordOffBits = log2Up(wordBytes)
def beatBytes = cacheBlockBytes / cacheDataBeats
def beatWords = beatBytes / wordBytes
def beatOffBits = log2Up(beatBytes)
def idxMSB = untagBits-1
def idxLSB = blockOffBits
def offsetmsb = idxLSB-1
def offsetlsb = wordOffBits
def rowWords = rowBits/wordBits
def doNarrowRead = coreDataBits * nWays % rowBits == 0
def encDataBits = cacheParams.dataECC.width(coreDataBits)
def encRowBits = encDataBits*rowWords
def lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
def lrscBackoff = 3 // disallow LRSC reacquisition briefly
def blockProbeAfterGrantCycles = 8 // give the processor some time to issue a request after a grant
def nIOMSHRs = cacheParams.nMMIOs
def maxUncachedInFlight = cacheParams.nMMIOs
def dataScratchpadSize = cacheParams.dataScratchpadBytes
require(rowBits >= coreDataBits, s"rowBits($rowBits) < coreDataBits($coreDataBits)")
// TODO should rowBits even be seperably specifiable?
require(rowBits == cacheDataBits, s"rowBits($rowBits) != cacheDataBits($cacheDataBits)")
// would need offset addr for puts if data width < xlen
require(xLen <= cacheDataBits, s"xLen($xLen) > cacheDataBits($cacheDataBits)")
require(!usingVM || untagBits <= pgIdxBits, s"untagBits($untagBits) > pgIdxBits($pgIdxBits)")
}
abstract class L1HellaCacheModule(implicit val p: Parameters) extends Module
with HasL1HellaCacheParameters
abstract class L1HellaCacheBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
with HasL1HellaCacheParameters
/** Bundle definitions for HellaCache interfaces */
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 HellaCacheReqInternal(implicit p: Parameters) extends CoreBundle()(p) with HasCoreMemOp {
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 data_raw = 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
val ae = new AlignmentExceptions
}
class HellaCacheWriteData(implicit p: Parameters) extends CoreBundle()(p) {
val data = UInt(width = coreDataBits)
val mask = UInt(width = coreDataBytes)
}
class HellaCachePerfEvents extends Bundle {
val acquire = Bool()
val release = Bool()
val tlbMiss = Bool()
}
// 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 = new HellaCacheWriteData().asOutput // 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 s2_xcpt = (new HellaCacheExceptions).asInput
val invalidate_lr = Bool(OUTPUT)
val ordered = Bool(INPUT)
val perf = new HellaCachePerfEvents().asInput
}
/** Base classes for Diplomatic TL2 HellaCaches */
abstract class HellaCache(hartid: Int)(implicit p: Parameters) extends LazyModule {
private val cfg = p(TileKey).dcache.get
val firstMMIO = max(1, cfg.nMSHRs)
val node = TLClientNode(Seq(TLClientPortParameters(
clients = cfg.scratch.map { _ => Seq(
TLClientParameters(
name = s"Core ${hartid} DCache MMIO",
sourceId = IdRange(0, cfg.nMMIOs),
requestFifo = true))
} getOrElse { Seq(
TLClientParameters(
name = s"Core ${hartid} DCache",
sourceId = IdRange(0, firstMMIO),
supportsProbe = TransferSizes(cfg.blockBytes, cfg.blockBytes)),
TLClientParameters(
name = s"Core ${hartid} DCache MMIO",
sourceId = IdRange(firstMMIO, firstMMIO+cfg.nMMIOs),
requestFifo = true))
},
minLatency = 1)))
val module: HellaCacheModule
}
class HellaCacheBundle(val outer: HellaCache)(implicit p: Parameters) extends CoreBundle()(p) {
val hartid = UInt(INPUT, hartIdLen)
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val errors = new DCacheErrors
}
class HellaCacheModule(outer: HellaCache) extends LazyModuleImp(outer)
with HasL1HellaCacheParameters {
implicit val edge = outer.node.edges.out(0)
val (tl_out, _) = outer.node.out(0)
val io = IO(new HellaCacheBundle(outer))
dontTouch(io.cpu.resp) // Users like to monitor these fields even if the core ignores some signals
dontTouch(io.cpu.s1_data)
private val fifoManagers = edge.manager.managers.filter(TLFIFOFixer.allUncacheable)
fifoManagers.foreach { m =>
require (m.fifoId == fifoManagers.head.fifoId,
s"IOMSHRs must be FIFO for all regions with effects, but HellaCache sees ${m.nodePath.map(_.name)}")
}
}
/** Mix-ins for constructing tiles that have a HellaCache */
trait HasHellaCache { this: BaseTile =>
val module: HasHellaCacheModule
implicit val p: Parameters
def findScratchpadFromICache: Option[AddressSet]
var nDCachePorts = 0
val dcache: HellaCache = LazyModule(
if(tileParams.dcache.get.nMSHRs == 0) {
new DCache(hartId, findScratchpadFromICache _, p(RocketCrossingKey).head.knownRatio)
} else { new NonBlockingDCache(hartId) })
tlMasterXbar.node := dcache.node
}
trait HasHellaCacheModule {
val outer: HasHellaCache
val dcachePorts = ListBuffer[HellaCacheIO]()
val dcacheArb = Module(new HellaCacheArbiter(outer.nDCachePorts)(outer.p))
outer.dcache.module.io.cpu <> dcacheArb.io.mem
}
/** Metadata array used for all HellaCaches */
class L1Metadata(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val coh = new ClientMetadata
val tag = UInt(width = tagBits)
}
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 L1HellaCacheBundle()(p) {
val idx = UInt(width = idxBits)
val way_en = UInt(width = nWays)
val tag = UInt(width = tagBits)
}
class L1MetaWriteReq(implicit p: Parameters) extends L1MetaReadReq()(p) {
val data = new L1Metadata
}
class L1MetadataArray[T <: L1Metadata](onReset: () => T)(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val rstVal = onReset()
val io = new Bundle {
val read = Decoupled(new L1MetaReadReq).flip
val write = Decoupled(new L1MetaWriteReq).flip
val resp = Vec(nWays, rstVal.cloneType).asOutput
}
val rst_cnt = Reg(init=UInt(0, log2Up(nSets+1)))
val rst = rst_cnt < UInt(nSets)
val waddr = Mux(rst, rst_cnt, io.write.bits.idx)
val wdata = Mux(rst, rstVal, io.write.bits.data).asUInt
val wmask = Mux(rst || Bool(nWays == 1), SInt(-1), io.write.bits.way_en.asSInt).toBools
val rmask = Mux(rst || Bool(nWays == 1), SInt(-1), io.read.bits.way_en.asSInt).toBools
when (rst) { rst_cnt := rst_cnt+UInt(1) }
val metabits = rstVal.getWidth
val tag_array = SeqMem(nSets, Vec(nWays, UInt(width = metabits)))
val wen = rst || io.write.valid
when (wen) {
tag_array.write(waddr, Vec.fill(nWays)(wdata), wmask)
}
io.resp := tag_array.read(io.read.bits.idx, io.read.fire()).map(rstVal.fromBits(_))
io.read.ready := !wen // so really this could be a 6T RAM
io.write.ready := !rst
}