diff --git a/.travis.yml b/.travis.yml index 0ab1c95d..4e3c4905 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,8 @@ env: - SUITE=RocketSuiteA - SUITE=RocketSuiteB - SUITE=RocketSuiteC - - SUITE=GroundtestSuite + - SUITE=GroundtestSuiteA + - SUITE=GroundtestSuiteB - SUITE=UnittestSuite # blacklist private branches diff --git a/regression/Makefile b/regression/Makefile index a6322da2..45187027 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -53,10 +53,14 @@ PROJECT=rocketchip CONFIGS=DefaultL2Config TinyConfig endif -ifeq ($(SUITE),GroundtestSuite) +ifeq ($(SUITE),GroundtestSuiteA) PROJECT=groundtest -CONFIGS=MemtestConfig MemtestBufferlessConfig MemtestStatelessConfig FancyMemtestConfig \ - BroadcastRegressionTestConfig BufferlessRegressionTestConfig CacheRegressionTestConfig \ +CONFIGS=MemtestConfig MemtestBufferlessConfig MemtestStatelessConfig FancyMemtestConfig +endif + +ifeq ($(SUITE),GroundtestSuiteB) +PROJECT=groundtest +CONFIGS=BroadcastRegressionTestConfig BufferlessRegressionTestConfig CacheRegressionTestConfig \ ComparatorConfig ComparatorBufferlessConfig ComparatorL2Config ComparatorStatelessConfig endif diff --git a/scripts/tracegen.py b/scripts/tracegen.py index bc214e6c..10c3d1bb 100755 --- a/scripts/tracegen.py +++ b/scripts/tracegen.py @@ -52,6 +52,8 @@ def main(): numFinished = numFinished + 1 if numFinished == total: break + elif line[0:12] == "using random": + continue else: print line, diff --git a/src/main/scala/coreplex/Configs.scala b/src/main/scala/coreplex/Configs.scala index 13986aa0..01a34c53 100644 --- a/src/main/scala/coreplex/Configs.scala +++ b/src/main/scala/coreplex/Configs.scala @@ -11,6 +11,7 @@ import uncore.coherence._ import uncore.agents._ import uncore.devices._ import uncore.converters._ +import uncore.util._ import rocket._ import util._ import util.ConfigUtils._ diff --git a/src/main/scala/groundtest/CacheFillTest.scala b/src/main/scala/groundtest/CacheFillTest.scala index 685bc8bc..446db059 100644 --- a/src/main/scala/groundtest/CacheFillTest.scala +++ b/src/main/scala/groundtest/CacheFillTest.scala @@ -3,7 +3,7 @@ package groundtest import Chisel._ import uncore.tilelink._ import uncore.constants._ -import uncore.agents._ +import uncore.util._ import util._ import config._ diff --git a/src/main/scala/groundtest/Configs.scala b/src/main/scala/groundtest/Configs.scala index b0727f24..02dc603f 100644 --- a/src/main/scala/groundtest/Configs.scala +++ b/src/main/scala/groundtest/Configs.scala @@ -6,6 +6,7 @@ import diplomacy._ import uncore.tilelink._ import uncore.coherence._ import uncore.agents._ +import uncore.util._ import uncore.devices.NTiles import junctions._ import config._ diff --git a/src/main/scala/groundtest/Coreplex.scala b/src/main/scala/groundtest/Coreplex.scala index 23529037..1abb2a32 100644 --- a/src/main/scala/groundtest/Coreplex.scala +++ b/src/main/scala/groundtest/Coreplex.scala @@ -6,9 +6,10 @@ import diplomacy._ import coreplex._ import uncore.devices.NTiles import uncore.tilelink2._ -import rocket.TileId import uncore.tilelink.TLId +case object TileId extends Field[Int] + class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex { val tiles = List.tabulate(p(NTiles)) { i => LazyModule(new GroundTestTile()(p.alterPartial({ diff --git a/src/main/scala/groundtest/Regression.scala b/src/main/scala/groundtest/Regression.scala index 6652c583..3d89ad7b 100644 --- a/src/main/scala/groundtest/Regression.scala +++ b/src/main/scala/groundtest/Regression.scala @@ -3,7 +3,7 @@ package groundtest import Chisel._ import uncore.tilelink._ import uncore.constants._ -import uncore.agents._ +import uncore.util._ import util._ import rocket._ import rocketchip._ diff --git a/src/main/scala/groundtest/Tile.scala b/src/main/scala/groundtest/Tile.scala index 5f002844..255f531d 100644 --- a/src/main/scala/groundtest/Tile.scala +++ b/src/main/scala/groundtest/Tile.scala @@ -3,7 +3,7 @@ package groundtest import Chisel._ import rocket._ import uncore.tilelink._ -import uncore.agents.CacheName +import uncore.util.CacheName import uncore.tilelink2._ import rocketchip.ExtMem import diplomacy._ diff --git a/src/main/scala/rocket/Dcache.scala b/src/main/scala/rocket/Dcache.scala index 5027e8c4..8b999b0d 100644 --- a/src/main/scala/rocket/Dcache.scala +++ b/src/main/scala/rocket/Dcache.scala @@ -5,7 +5,6 @@ package rocket import Chisel._ import Chisel.ImplicitConversions._ import diplomacy._ -import uncore.agents._ import uncore.constants._ import uncore.tilelink2._ import uncore.util._ diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 6a783e80..90d10b57 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -6,7 +6,7 @@ import Chisel._ import config.{Parameters, Field} import diplomacy._ import uncore.tilelink2._ -import uncore.agents._ +import uncore.util._ import uncore.constants._ import uncore.tilelink.{TLKey, TLId} import util.ParameterizedBundle diff --git a/src/main/scala/rocket/NBDcache.scala b/src/main/scala/rocket/NBDcache.scala index 5c4ecc10..5a63f81c 100644 --- a/src/main/scala/rocket/NBDcache.scala +++ b/src/main/scala/rocket/NBDcache.scala @@ -5,7 +5,6 @@ package rocket import Chisel._ import Chisel.ImplicitConversions._ import diplomacy._ -import uncore.agents._ import uncore.constants._ import uncore.tilelink._ import uncore.tilelink2._ @@ -176,15 +175,18 @@ class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) 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 new_coh = Reg(init=ClientMetadata.onReset) + val (_, shrink_param, coh_on_clear) = req.old_meta.coh.onCacheControl(M_FLUSH) + val grow_param = new_coh.onAccess(req.cmd)._2 + val coh_on_grant = new_coh.onGrant(req.cmd, io.mem_grant.bits.param) // 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 // to let us replay this new request. I.e. we don't handle multiple outstanding // Acquires on the same block for now. - val cmd_requires_second_acquire = - req.old_meta.coh.requiresAcquireOnSecondaryMiss(req.cmd, io.req_bits.cmd) - // Track whether or not a secondary acquire will cause the coherence state - // to go from clean to dirty. - val dirties_coh = Reg(Bool()) + val (cmd_requires_second_acquire, is_hit_again, _, dirtier_coh, dirtier_cmd) = + new_coh.onSecondaryAccess(req.cmd, io.req_bits.cmd) + val states_before_refill = Seq(s_wb_req, s_wb_resp, s_meta_clear) val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant) val sec_rdy = idx_match && @@ -197,19 +199,6 @@ class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) rpq.io.enq.bits := io.req_bits rpq.io.deq.ready := (io.replay.ready && state === s_drain_rpq) || state === s_invalid - // TODO clean all this coh state business up - val new_coh_state = Reg(init=ClientMetadata.onReset) - val grow_param = Reg(init=UInt(0)) - val coh_on_grant = Mux(dirties_coh, - ClientMetadata.maximum, - req.old_meta.coh.onGrant(req.cmd, io.mem_grant.bits.param)) - val (is_hit, missed_param, coh_on_hit) = io.req_bits.old_meta.coh.onAccess(io.req_bits.cmd) - val (needs_wb, _, _) = io.req_bits.old_meta.coh.onCacheControl(M_FLUSH) - val (_, shrink_param, _) = req.old_meta.coh.onCacheControl(M_FLUSH) - val (hit_again, missed_again_param, _) = req.old_meta.coh.onCacheControl(io.req_bits.cmd) - val (_, _, clear_coh_state) = req.old_meta.coh.onCacheControl(M_FLUSH) - val (_, after_wb_param, _) = ClientMetadata.onReset.onAccess(req.cmd) - when (state === s_drain_rpq && !rpq.io.deq.valid) { state := s_invalid } @@ -221,14 +210,13 @@ class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) state := s_meta_write_resp } when (state === s_refill_resp && refill_done) { + new_coh := coh_on_grant state := s_meta_write_req - new_coh_state := coh_on_grant } when (io.mem_acquire.fire()) { // s_refill_req state := s_refill_resp } when (state === s_meta_clear && io.meta_write.ready) { - grow_param := after_wb_param state := s_refill_req } when (state === s_wb_resp && io.mem_grant.valid) { @@ -241,24 +229,26 @@ class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) //If we get a secondary miss that needs more permissions before we've sent // out the primary miss's Acquire, we can upgrade the permissions we're // going to ask for in s_refill_req - when(cmd_requires_second_acquire) { - req.cmd := io.req_bits.cmd - when(!hit_again) { grow_param := missed_again_param } + req.cmd := dirtier_cmd + when (is_hit_again) { + new_coh := dirtier_coh } - dirties_coh := dirties_coh || isWrite(io.req_bits.cmd) } when (io.req_pri_val && io.req_pri_rdy) { req := io.req_bits - dirties_coh := isWrite(io.req_bits.cmd) + val old_coh = io.req_bits.old_meta.coh + val needs_wb = old_coh.onCacheControl(M_FLUSH)._1 + val (is_hit, _, coh_on_hit) = old_coh.onAccess(io.req_bits.cmd) when (io.req_bits.tag_match) { when (is_hit) { // set dirty bit + new_coh := coh_on_hit state := s_meta_write_req - new_coh_state := coh_on_hit }.otherwise { // upgrade permissions + new_coh := old_coh state := s_refill_req - grow_param := missed_param } }.otherwise { // writback if necessary and refill + new_coh := ClientMetadata.onReset state := Mux(needs_wb, s_wb_req, s_meta_clear) } } @@ -285,7 +275,7 @@ class MSHR(id: Int, edge: TLEdgeOut)(implicit cfg: DCacheConfig, p: Parameters) io.meta_write.valid := state.isOneOf(s_meta_write_req, s_meta_clear) io.meta_write.bits.idx := req_idx - io.meta_write.bits.data.coh := Mux(state === s_meta_clear, clear_coh_state, new_coh_state) + io.meta_write.bits.data.coh := Mux(state === s_meta_clear, coh_on_clear, new_coh) io.meta_write.bits.data.tag := io.tag io.meta_write.bits.way_en := req.way_en diff --git a/src/main/scala/rocket/btb.scala b/src/main/scala/rocket/btb.scala index 98d06f04..5217478a 100644 --- a/src/main/scala/rocket/btb.scala +++ b/src/main/scala/rocket/btb.scala @@ -6,7 +6,7 @@ import Chisel._ import config._ import util._ import Chisel.ImplicitConversions._ -import uncore.agents.PseudoLRU +import uncore.util.PseudoLRU case object BtbKey extends Field[BtbParameters] diff --git a/src/main/scala/rocket/ptw.scala b/src/main/scala/rocket/ptw.scala index 60e8fa92..665a8a4e 100644 --- a/src/main/scala/rocket/ptw.scala +++ b/src/main/scala/rocket/ptw.scala @@ -3,7 +3,7 @@ package rocket import Chisel._ -import uncore.agents._ +import uncore.util.PseudoLRU import uncore.constants._ import util._ import Chisel.ImplicitConversions._ diff --git a/src/main/scala/rocket/rocc.scala b/src/main/scala/rocket/rocc.scala index 4503c984..2d2bc4ef 100644 --- a/src/main/scala/rocket/rocc.scala +++ b/src/main/scala/rocket/rocc.scala @@ -5,7 +5,7 @@ package rocket import Chisel._ import uncore.tilelink._ import uncore.constants._ -import uncore.agents.CacheName +import uncore.util.CacheName import util._ import Chisel.ImplicitConversions._ import config._ diff --git a/src/main/scala/rocket/rocket.scala b/src/main/scala/rocket/rocket.scala index 0c29cd36..e397fbed 100644 --- a/src/main/scala/rocket/rocket.scala +++ b/src/main/scala/rocket/rocket.scala @@ -4,7 +4,7 @@ package rocket import Chisel._ import uncore.devices._ -import uncore.agents.CacheName +import uncore.util.CacheName import uncore.constants._ import uncore.tilelink2._ import util._ diff --git a/src/main/scala/rocket/tile.scala b/src/main/scala/rocket/tile.scala index e0b7a585..c0845d66 100644 --- a/src/main/scala/rocket/tile.scala +++ b/src/main/scala/rocket/tile.scala @@ -6,7 +6,7 @@ import Chisel._ import diplomacy._ import uncore.tilelink._ import uncore.tilelink2._ -import uncore.agents._ +import uncore.util.{CacheName, CacheBlockBytes} import uncore.converters._ import uncore.devices._ import util._ @@ -14,7 +14,6 @@ import config._ import scala.collection.mutable.ListBuffer case object BuildRoCC extends Field[Seq[RoccParameters]] -case object TileId extends Field[Int] case class RoccParameters( opcodes: OpcodeSet, @@ -30,7 +29,6 @@ class RocketTile(tileId: Int)(implicit p: Parameters) extends LazyModule { val dcacheParams = coreParams.alterPartial({ case CacheName => CacheName("L1D") case TLId => "L1toL2" - case TileId => tileId // TODO using this messes with Heirarchical P&R: change to io.hartid? }) val icacheParams = coreParams.alterPartial({ case CacheName => CacheName("L1I") diff --git a/src/main/scala/rocket/tlb.scala b/src/main/scala/rocket/tlb.scala index 86020004..12da4628 100644 --- a/src/main/scala/rocket/tlb.scala +++ b/src/main/scala/rocket/tlb.scala @@ -8,8 +8,7 @@ import Chisel.ImplicitConversions._ import scala.math._ import config._ import diplomacy._ -import uncore.agents._ -import uncore.coherence._ +import uncore.util._ import uncore.tilelink2._ case object PgLevels extends Field[Int] diff --git a/src/main/scala/uncore/agents/Cache.scala b/src/main/scala/uncore/agents/L2Cache.scala similarity index 87% rename from src/main/scala/uncore/agents/Cache.scala rename to src/main/scala/uncore/agents/L2Cache.scala index 6f79a945..c22a1faf 100644 --- a/src/main/scala/uncore/agents/Cache.scala +++ b/src/main/scala/uncore/agents/L2Cache.scala @@ -5,186 +5,14 @@ package uncore.agents import Chisel._ import scala.reflect.ClassTag import junctions.PAddrBits -import util.ParameterizedBundle -import uncore.util.AMOALU import uncore.coherence._ import uncore.tilelink._ import uncore.constants._ import uncore.util._ import util._ -import config._ +import config.{Parameters, Field} -case class CacheConfig( - nSets: Int, - nWays: Int, - rowBits: Int, - nTLBEntries: Int, - cacheIdBits: Int, - splitMetadata: Boolean) -case class CacheName(id: String) extends Field[CacheConfig] -case object CacheName extends Field[CacheName] - -case object Replacer extends Field[() => ReplacementPolicy] -case object L2Replacer extends Field[() => SeqReplacementPolicy] -case object NPrimaryMisses extends Field[Int] -case object NSecondaryMisses extends Field[Int] -case object CacheBlockBytes extends Field[Int] -case object ECCCode extends Field[Option[Code]] case object CacheId extends Field[Int] - -trait HasCacheParameters { - implicit val p: Parameters - val cacheConfig = p(p(CacheName)) - val nSets = cacheConfig.nSets - val blockOffBits = p(CacheBlockOffsetBits) - val cacheIdBits = cacheConfig.cacheIdBits - val idxBits = log2Up(cacheConfig.nSets) - val untagBits = blockOffBits + cacheIdBits + idxBits - val tagBits = p(PAddrBits) - untagBits - val nWays = cacheConfig.nWays - val wayBits = log2Up(nWays) - val isDM = nWays == 1 - val rowBits = cacheConfig.rowBits - val rowBytes = rowBits/8 - val rowOffBits = log2Up(rowBytes) - val code = p(ECCCode).getOrElse(new IdentityCode) - val hasSplitMetadata = cacheConfig.splitMetadata -} - -abstract class CacheModule(implicit val p: Parameters) extends Module - with HasCacheParameters -abstract class CacheBundle(implicit val p: Parameters) extends ParameterizedBundle()(p) - with HasCacheParameters - -abstract class ReplacementPolicy { - def way: UInt - def miss: Unit - def hit: Unit -} - -class RandomReplacement(ways: Int) extends ReplacementPolicy { - private val replace = Wire(Bool()) - replace := Bool(false) - val lfsr = LFSR16(replace) - - def way = if(ways == 1) UInt(0) else lfsr(log2Up(ways)-1,0) - def miss = replace := Bool(true) - def hit = {} -} - -abstract class SeqReplacementPolicy { - def access(set: UInt): Unit - def update(valid: Bool, hit: Bool, set: UInt, way: UInt): Unit - def way: UInt -} - -class SeqRandom(n_ways: Int) extends SeqReplacementPolicy { - val logic = new RandomReplacement(n_ways) - def access(set: UInt) = { } - def update(valid: Bool, hit: Bool, set: UInt, way: UInt) = { - when (valid && !hit) { logic.miss } - } - def way = logic.way -} - -class PseudoLRU(n: Int) -{ - require(isPow2(n)) - val state_reg = Reg(Bits(width = n)) - def access(way: UInt) { - state_reg := get_next_state(state_reg,way) - } - def get_next_state(state: UInt, way: UInt) = { - var next_state = state - var idx = UInt(1,1) - for (i <- log2Up(n)-1 to 0 by -1) { - val bit = way(i) - next_state = next_state.bitSet(idx, !bit) - idx = Cat(idx, bit) - } - next_state - } - def replace = get_replace_way(state_reg) - def get_replace_way(state: Bits) = { - var idx = UInt(1,1) - for (i <- 0 until log2Up(n)) - idx = Cat(idx, state(idx)) - idx(log2Up(n)-1,0) - } -} - -class SeqPLRU(n_sets: Int, n_ways: Int) extends SeqReplacementPolicy { - val state = SeqMem(n_sets, Bits(width = n_ways-1)) - val logic = new PseudoLRU(n_ways) - val current_state = Wire(Bits()) - val plru_way = logic.get_replace_way(current_state) - val next_state = Wire(Bits()) - - def access(set: UInt) = { - current_state := Cat(state.read(set), Bits(0, width = 1)) - } - - def update(valid: Bool, hit: Bool, set: UInt, way: UInt) = { - val update_way = Mux(hit, way, plru_way) - next_state := logic.get_next_state(current_state, update_way) - when (valid) { state.write(set, next_state(n_ways-1,1)) } - } - - def way = plru_way -} - -abstract class Metadata(implicit p: Parameters) extends CacheBundle()(p) { - val tag = Bits(width = tagBits) -} - -class MetaReadReq(implicit p: Parameters) extends CacheBundle()(p) { - val idx = Bits(width = idxBits) - val way_en = Bits(width = nWays) -} - -class MetaWriteReq[T <: Metadata](gen: T)(implicit p: Parameters) extends MetaReadReq()(p) { - val data = gen.cloneType - override def cloneType = new MetaWriteReq(gen)(p).asInstanceOf[this.type] -} - -class MetadataArray[T <: Metadata](onReset: () => T)(implicit p: Parameters) extends CacheModule()(p) { - val rstVal = onReset() - val io = new Bundle { - val read = Decoupled(new MetaReadReq).flip - val write = Decoupled(new MetaWriteReq(rstVal)).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 - - if (hasSplitMetadata) { - val tag_arrs = List.fill(nWays){ SeqMem(nSets, UInt(width = metabits)) } - val tag_readout = Wire(Vec(nWays,rstVal.cloneType)) - (0 until nWays).foreach { (i) => - when (rst || (io.write.valid && wmask(i))) { - tag_arrs(i).write(waddr, wdata) - } - io.resp(i) := rstVal.fromBits(tag_arrs(i).read(io.read.bits.idx, io.read.valid && rmask(i))) - } - } else { - val tag_arr = SeqMem(nSets, Vec(nWays, UInt(width = metabits))) - when (rst || io.write.valid) { - tag_arr.write(waddr, Vec.fill(nWays)(wdata), wmask) - } - io.resp := tag_arr.read(io.read.bits.idx, io.read.valid).map(rstVal.fromBits(_)) - } - - io.read.ready := !rst && !io.write.valid // so really this could be a 6T RAM - io.write.ready := !rst -} - case object L2DirectoryRepresentation extends Field[DirectoryRepresentation] trait HasOuterCacheParameters extends HasCacheParameters with HasCoherenceAgentParameters { diff --git a/src/main/scala/uncore/tilelink2/Metadata.scala b/src/main/scala/uncore/tilelink2/Metadata.scala index 2e23ae7b..bee18753 100644 --- a/src/main/scala/uncore/tilelink2/Metadata.scala +++ b/src/main/scala/uncore/tilelink2/Metadata.scala @@ -88,12 +88,6 @@ class ClientMetadata extends Bundle { Cat(wr, toT) -> Dirty)) } - /** Does a secondary miss on the block require another Acquire message */ - def requiresAcquireOnSecondaryMiss(first_cmd: UInt, second_cmd: UInt): Bool = { - import MemoryOpCategories._ - isWriteIntent(second_cmd) && !isWriteIntent(first_cmd) - } - /** Does this cache have permissions on this block sufficient to perform op, * and what to do next (Acquire message param or updated metadata). */ def onAccess(cmd: UInt): (Bool, UInt, ClientMetadata) = { @@ -101,6 +95,20 @@ class ClientMetadata extends Bundle { (r._1, r._2, ClientMetadata(r._2)) } + /** Does a secondary miss on the block require another Acquire message */ + def onSecondaryAccess(first_cmd: UInt, second_cmd: UInt): (Bool, Bool, UInt, ClientMetadata, UInt) = { + import MemoryOpCategories._ + val r1 = growStarter(first_cmd) + val r2 = growStarter(second_cmd) + val needs_second_acq = isWriteIntent(second_cmd) && !isWriteIntent(first_cmd) + val hit_again = r1._1 && r2._1 + val dirties = categorize(second_cmd) === wr + val biggest_grow_param = Mux(dirties, r2._2, r1._2) + val dirtiest_state = ClientMetadata(biggest_grow_param) + val dirtiest_cmd = Mux(dirties, second_cmd, first_cmd) + (needs_second_acq, hit_again, biggest_grow_param, dirtiest_state, dirtiest_cmd) + } + /** Metadata change on a returned Grant */ def onGrant(cmd: UInt, param: UInt): ClientMetadata = ClientMetadata(growFinisher(cmd, param)) diff --git a/src/main/scala/uncore/util/Cache.scala b/src/main/scala/uncore/util/Cache.scala new file mode 100644 index 00000000..59401e23 --- /dev/null +++ b/src/main/scala/uncore/util/Cache.scala @@ -0,0 +1,180 @@ +// See LICENSE for license details. + +package uncore.util + +import Chisel._ +import config.{Parameters, Field} +import junctions.PAddrBits +import util.ParameterizedBundle +import uncore.constants._ + +case class CacheConfig( + nSets: Int, + nWays: Int, + rowBits: Int, + nTLBEntries: Int, + cacheIdBits: Int, + splitMetadata: Boolean) +case class CacheName(id: String) extends Field[CacheConfig] +case object CacheName extends Field[CacheName] + +case object Replacer extends Field[() => ReplacementPolicy] +case object L2Replacer extends Field[() => SeqReplacementPolicy] +case object NPrimaryMisses extends Field[Int] +case object NSecondaryMisses extends Field[Int] +case object CacheBlockBytes extends Field[Int] +case object ECCCode extends Field[Option[Code]] + +trait HasCacheParameters { + implicit val p: Parameters + val cacheConfig = p(p(CacheName)) + val nSets = cacheConfig.nSets + val blockOffBits = log2Up(p(CacheBlockBytes)) + val cacheIdBits = cacheConfig.cacheIdBits + val idxBits = log2Up(cacheConfig.nSets) + val untagBits = blockOffBits + cacheIdBits + idxBits + val tagBits = p(PAddrBits) - untagBits + val nWays = cacheConfig.nWays + val wayBits = log2Up(nWays) + val isDM = nWays == 1 + val rowBits = cacheConfig.rowBits + val rowBytes = rowBits/8 + val rowOffBits = log2Up(rowBytes) + val code = p(ECCCode).getOrElse(new IdentityCode) + val hasSplitMetadata = cacheConfig.splitMetadata +} + +abstract class CacheModule(implicit val p: Parameters) extends Module + with HasCacheParameters +abstract class CacheBundle(implicit val p: Parameters) extends ParameterizedBundle()(p) + with HasCacheParameters + +abstract class ReplacementPolicy { + def way: UInt + def miss: Unit + def hit: Unit +} + +class RandomReplacement(ways: Int) extends ReplacementPolicy { + private val replace = Wire(Bool()) + replace := Bool(false) + val lfsr = LFSR16(replace) + + def way = if(ways == 1) UInt(0) else lfsr(log2Up(ways)-1,0) + def miss = replace := Bool(true) + def hit = {} +} + +abstract class SeqReplacementPolicy { + def access(set: UInt): Unit + def update(valid: Bool, hit: Bool, set: UInt, way: UInt): Unit + def way: UInt +} + +class SeqRandom(n_ways: Int) extends SeqReplacementPolicy { + val logic = new RandomReplacement(n_ways) + def access(set: UInt) = { } + def update(valid: Bool, hit: Bool, set: UInt, way: UInt) = { + when (valid && !hit) { logic.miss } + } + def way = logic.way +} + +class PseudoLRU(n: Int) +{ + require(isPow2(n)) + val state_reg = Reg(Bits(width = n)) + def access(way: UInt) { + state_reg := get_next_state(state_reg,way) + } + def get_next_state(state: UInt, way: UInt) = { + var next_state = state + var idx = UInt(1,1) + for (i <- log2Up(n)-1 to 0 by -1) { + val bit = way(i) + next_state = next_state.bitSet(idx, !bit) + idx = Cat(idx, bit) + } + next_state + } + def replace = get_replace_way(state_reg) + def get_replace_way(state: Bits) = { + var idx = UInt(1,1) + for (i <- 0 until log2Up(n)) + idx = Cat(idx, state(idx)) + idx(log2Up(n)-1,0) + } +} + +class SeqPLRU(n_sets: Int, n_ways: Int) extends SeqReplacementPolicy { + val state = SeqMem(n_sets, Bits(width = n_ways-1)) + val logic = new PseudoLRU(n_ways) + val current_state = Wire(Bits()) + val plru_way = logic.get_replace_way(current_state) + val next_state = Wire(Bits()) + + def access(set: UInt) = { + current_state := Cat(state.read(set), Bits(0, width = 1)) + } + + def update(valid: Bool, hit: Bool, set: UInt, way: UInt) = { + val update_way = Mux(hit, way, plru_way) + next_state := logic.get_next_state(current_state, update_way) + when (valid) { state.write(set, next_state(n_ways-1,1)) } + } + + def way = plru_way +} + +abstract class Metadata(implicit p: Parameters) extends CacheBundle()(p) { + val tag = Bits(width = tagBits) +} + +class MetaReadReq(implicit p: Parameters) extends CacheBundle()(p) { + val idx = Bits(width = idxBits) + val way_en = Bits(width = nWays) +} + +class MetaWriteReq[T <: Metadata](gen: T)(implicit p: Parameters) extends MetaReadReq()(p) { + val data = gen.cloneType + override def cloneType = new MetaWriteReq(gen)(p).asInstanceOf[this.type] +} + +class MetadataArray[T <: Metadata](onReset: () => T)(implicit p: Parameters) extends CacheModule()(p) { + val rstVal = onReset() + val io = new Bundle { + val read = Decoupled(new MetaReadReq).flip + val write = Decoupled(new MetaWriteReq(rstVal)).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 + + if (hasSplitMetadata) { + val tag_arrs = List.fill(nWays){ SeqMem(nSets, UInt(width = metabits)) } + val tag_readout = Wire(Vec(nWays,rstVal.cloneType)) + (0 until nWays).foreach { (i) => + when (rst || (io.write.valid && wmask(i))) { + tag_arrs(i).write(waddr, wdata) + } + io.resp(i) := rstVal.fromBits(tag_arrs(i).read(io.read.bits.idx, io.read.valid && rmask(i))) + } + } else { + val tag_arr = SeqMem(nSets, Vec(nWays, UInt(width = metabits))) + when (rst || io.write.valid) { + tag_arr.write(waddr, Vec.fill(nWays)(wdata), wmask) + } + io.resp := tag_arr.read(io.read.bits.idx, io.read.valid).map(rstVal.fromBits(_)) + } + + io.read.ready := !rst && !io.write.valid // so really this could be a 6T RAM + io.write.ready := !rst +} + diff --git a/src/main/scala/uncore/agents/Ecc.scala b/src/main/scala/uncore/util/Ecc.scala similarity index 99% rename from src/main/scala/uncore/agents/Ecc.scala rename to src/main/scala/uncore/util/Ecc.scala index acb306b9..cfb6cd38 100644 --- a/src/main/scala/uncore/agents/Ecc.scala +++ b/src/main/scala/uncore/util/Ecc.scala @@ -1,6 +1,6 @@ // See LICENSE for license details. -package uncore.agents +package uncore.util import Chisel._ import util._