提交 39ac6601 编写于 作者: Z Zihao Yu

Merge branch 'merge-master' into dev-linux-tlb

......@@ -18,6 +18,7 @@ object SimpleBusCmd {
def writeBurst = "b0011".U // write | refill
def writeLast = "b0111".U // write | refill
def probe = "b1000".U // read | do nothing
def prefetch = "b0100".U // read | refill
// resp
def readLast = "b0110".U
......@@ -53,9 +54,11 @@ class SimpleBusReqBundle(val userBits: Int = 0) extends SimpleBusBundle {
def isRead() = !cmd(0) && !cmd(3)
def isWrite() = cmd(0)
def isBurst() = cmd(1)
def isReadBurst() = cmd === SimpleBusCmd.readBurst
def isWriteSingle() = cmd === SimpleBusCmd.write
def isWriteLast() = cmd === SimpleBusCmd.writeLast
def isProbe() = cmd === SimpleBusCmd.probe
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
class SimpleBusRespBundle(val userBits: Int = 0) extends SimpleBusBundle {
......@@ -69,6 +72,7 @@ class SimpleBusRespBundle(val userBits: Int = 0) extends SimpleBusBundle {
def isProbeHit() = cmd === SimpleBusCmd.probeHit
def isProbeMiss() = cmd === SimpleBusCmd.probeMiss
def isWriteResp() = cmd === SimpleBusCmd.writeResp
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
// Uncache
......@@ -91,4 +95,6 @@ class SimpleBusUC(val userBits: Int = 0) extends SimpleBusBundle {
class SimpleBusC(val userBits: Int = 0) extends SimpleBusBundle {
val mem = new SimpleBusUC(userBits)
val coh = Flipped(new SimpleBusUC(userBits))
def memtoAXI4() = this.mem.toAXI4
}
......@@ -12,6 +12,7 @@ case class CacheConfig (
ro: Boolean = false,
name: String = "cache",
userBits: Int = 0,
cacheLevel: Int = 1,
totalSize: Int = 32, // Kbytes
ways: Int = 4
......@@ -23,12 +24,15 @@ sealed trait HasCacheConst {
val AddrBits: Int
val XLEN: Int
val ro = cacheConfig.ro
val hasCoh = !ro
val hasCohInt = (if (hasCoh) 1 else 0)
val cacheName = cacheConfig.name
val userBits = cacheConfig.userBits
val ro = cacheConfig.ro
val hasCoh = !ro
val hasCohInt = (if (hasCoh) 1 else 0)
val hasPrefetch = cacheName == "l2cache"
val cacheLevel = cacheConfig.cacheLevel
val TotalSize = cacheConfig.totalSize
val Ways = cacheConfig.ways
val LineSize = XLEN // byte
......@@ -39,7 +43,7 @@ sealed trait HasCacheConst {
val WordIndexBits = log2Up(LineBeats)
val TagBits = AddrBits - OffsetBits - IndexBits
val debug = true && cacheName == "dcache"
val debug = false
def addrBundle = new Bundle {
val tag = UInt(TagBits.W)
......@@ -113,6 +117,11 @@ sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheMod
io.out.bits.req := io.in.bits
io.out.valid := io.in.valid && io.metaReadBus.req.ready && io.dataReadBus.req.ready
io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready
Debug(debug) {
printf("%d: [" + cacheName + " stage1]: in.ready = %d, in.valid = %d, out.valid = %d, out.ready = %d, addr = %x, cmd = %x, dataReadBus.req.valid = %d\n",
GTimer(), io.in.ready, io.in.valid, io.out.valid, io.out.ready, io.in.bits.addr, io.in.bits.cmd, io.dataReadBus.req.valid)
}
}
sealed class Stage2IO(implicit val cacheConfig: CacheConfig) extends CacheBundle {
......@@ -176,12 +185,8 @@ sealed class CacheStage2(implicit val cacheConfig: CacheConfig) extends CacheMod
io.out.valid := io.in.valid
io.in.ready := !io.in.valid || io.out.fire()
Debug() {
if(debug) {
when(true.B) {
printf("%d: [" + cacheName + " S2]: isFD:%d isFDreg:%d inFire:%d invalid:%d \n", GTimer(), isForwardData, isForwardDataReg, io.in.fire(), io.in.valid)
}
}
Debug(debug) {
printf("%d: [" + cacheName + " S2]: isFD:%d isFDreg:%d inFire:%d invalid:%d \n", GTimer(), isForwardData, isForwardDataReg, io.in.fire(), io.in.valid)
}
}
......@@ -199,6 +204,9 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
val mem = new SimpleBusUC
val mmio = new SimpleBusUC
val cohResp = Decoupled(new SimpleBusRespBundle)
// use to distinguish prefetch request and normal request
val dataReadRespToL1 = Output(Bool())
})
val metaWriteArb = Module(new Arbiter(CacheMetaArrayWriteBus().req.bits, 2))
......@@ -210,6 +218,7 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
val hit = io.in.valid && io.in.bits.hit
val miss = io.in.valid && !io.in.bits.hit
val probe = io.in.valid && hasCoh.B && req.isProbe()
val hitReadBurst = hit && req.isReadBurst()
val meta = Mux1H(io.in.bits.waymask, io.in.bits.metas)
assert(!(mmio && hit), "MMIO request should not hit in cache")
......@@ -218,10 +227,15 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
val dataRead = Mux(useForwardData, io.in.bits.forwardData.data.data, dataReadArray)
val wordMask = Mux(!ro.B && req.isWrite(), MaskExpand(req.wmask), 0.U(DataBits.W))
val writeL2BeatCnt = Counter(LineBeats)
when(io.out.fire() && (req.cmd === SimpleBusCmd.writeBurst || req.isWriteLast())) {
writeL2BeatCnt.inc()
}
val hitWrite = hit && req.isWrite()
val dataHitWriteBus = Wire(CacheDataArrayWriteBus()).apply(
data = Wire(new DataBundle).apply(MaskData(dataRead, req.wdata, wordMask)),
valid = hitWrite, setIdx = getDataIdx(req.addr), waymask = io.in.bits.waymask)
valid = hitWrite, setIdx = Cat(addr.index, Mux(req.cmd === SimpleBusCmd.writeBurst || req.isWriteLast(), writeL2BeatCnt.value, addr.wordIndex)), waymask = io.in.bits.waymask)
val metaHitWriteBus = Wire(CacheMetaArrayWriteBus()).apply(
valid = hitWrite && !meta.dirty, setIdx = getMetaIdx(req.addr), waymask = io.in.bits.waymask,
......@@ -249,7 +263,7 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
switch (state2) {
is (s2_idle) { when (io.dataReadBus.req.fire()) { state2 := s2_dataReadWait } }
is (s2_dataReadWait) { state2 := s2_dataOK }
is (s2_dataOK) { when (io.mem.req.fire() || io.cohResp.fire()) { state2 := s2_idle } }
is (s2_dataOK) { when (io.mem.req.fire() || io.cohResp.fire() || hitReadBurst && io.out.ready) { state2 := s2_idle } }
}
// critical word first read
......@@ -285,6 +299,9 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
io.cohResp.bits.cmd := Mux(state === s_release, Mux(releaseLast, SimpleBusCmd.readLast, 0.U),
Mux(hit, SimpleBusCmd.probeHit, SimpleBusCmd.probeMiss))
val respToL1Fire = hitReadBurst && io.out.ready && state2 === s2_dataOK
val respToL1Last = Counter((state === s_idle || state === s_release && state2 === s2_dataOK) && hitReadBurst && io.out.ready, LineBeats)._2
switch (state) {
is (s_idle) {
afterFirstRead := false.B
......@@ -295,6 +312,9 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
state := Mux(hit, s_release, s_idle)
readBeatCnt.value := addr.wordIndex
}
} .elsewhen (hitReadBurst && io.out.ready) {
state := s_release
readBeatCnt.value := Mux(addr.wordIndex === (LineBeats - 1).U, 0.U, (addr.wordIndex + 1.U))
} .elsewhen ((miss || mmio) && !io.flush) {
state := Mux(mmio, s_mmioReq, Mux(!ro.B && meta.dirty, s_memWriteReq, s_memReadReq))
}
......@@ -304,8 +324,8 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
is (s_mmioResp) { when (io.mmio.resp.fire()) { state := s_wait_resp } }
is (s_release) {
when (io.cohResp.fire()) { readBeatCnt.inc() }
when (io.cohResp.fire() && releaseLast) { state := s_idle }
when (io.cohResp.fire() || respToL1Fire) { readBeatCnt.inc() }
when (probe && io.cohResp.fire() && releaseLast || respToL1Fire && respToL1Last) { state := s_idle }
}
is (s_memReadReq) { when (io.mem.req.fire()) {
......@@ -317,6 +337,7 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
when (io.mem.resp.fire()) {
afterFirstRead := true.B
readBeatCnt.inc()
when (req.cmd === SimpleBusCmd.writeBurst) { writeL2BeatCnt.value := 0.U }
when (io.mem.resp.bits.isReadLast()) { state := s_wait_resp }
}
}
......@@ -349,10 +370,34 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
metaWriteArb.io.in(1) <> metaRefillWriteBus.req
io.metaWriteBus.req <> metaWriteArb.io.out
io.out.bits.rdata := Mux(hit, dataRead, inRdataRegDemand)
io.out.bits.cmd := Mux(io.in.bits.req.isRead(), SimpleBusCmd.readLast, Mux(io.in.bits.req.isWrite(), SimpleBusCmd.writeResp, DontCare))//DontCare, added by lemover
if (cacheLevel == 2) {
when ((state === s_memReadResp) && io.mem.resp.fire() && req.isReadBurst()) {
// readBurst request miss
io.out.bits.rdata := dataRefill
io.out.bits.cmd := Mux(io.mem.resp.bits.isReadLast(), SimpleBusCmd.readLast, SimpleBusCmd.readBurst)
}.elsewhen (req.isWriteLast() || req.cmd === SimpleBusCmd.writeBurst) {
// writeBurst/writeLast request, no matter hit or miss
io.out.bits.rdata := Mux(hit, dataRead, inRdataRegDemand)
io.out.bits.cmd := DontCare
}.elsewhen (hitReadBurst && state === s_release) {
// readBurst request hit
io.out.bits.rdata := dataHitWay
io.out.bits.cmd := Mux(respToL1Last, SimpleBusCmd.readLast, SimpleBusCmd.readBurst)
}.otherwise {
io.out.bits.rdata := Mux(hit, dataRead, inRdataRegDemand)
io.out.bits.cmd := req.cmd
}
} else {
io.out.bits.rdata := Mux(hit, dataRead, inRdataRegDemand)
io.out.bits.cmd := Mux(io.in.bits.req.isRead(), SimpleBusCmd.readLast, Mux(io.in.bits.req.isWrite(), SimpleBusCmd.writeResp, DontCare))//DontCare, added by lemover
}
io.out.bits.user.zip(req.user).map { case (o,i) => o := i }
io.out.valid := io.in.valid && Mux(probe, false.B, Mux(hit, true.B, Mux(req.isWrite() || mmio, state === s_wait_resp, afterFirstRead && !alreadyOutFire)))
io.out.valid := io.in.valid && Mux(req.isBurst() && (cacheLevel == 2).B,
Mux(req.isWrite() && (hit || !hit && state === s_wait_resp), true.B, (state === s_memReadResp && io.mem.resp.fire() && req.cmd === SimpleBusCmd.readBurst)) || (respToL1Fire && respToL1Last && state === s_release),
Mux(probe, false.B, Mux(hit, true.B, Mux(req.isWrite() || mmio, state === s_wait_resp, afterFirstRead && !alreadyOutFire)))
)
// With critical-word first, the pipeline registers between
// s2 and s3 can not be overwritten before a missing request
// is totally handled. We use io.isFinish to indicate when the
......@@ -362,20 +407,20 @@ sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheMod
)
io.in.ready := io.out.ready && (state === s_idle) && !miss && !probe
io.dataReadRespToL1 := hitReadBurst && (state === s_idle && io.out.ready || state === s_release && state2 === s2_dataOK)
assert(!(metaHitWriteBus.req.valid && metaRefillWriteBus.req.valid))
assert(!(dataHitWriteBus.req.valid && dataRefillWriteBus.req.valid))
assert(!(!ro.B && io.flush), "only allow to flush icache")
Debug() {
if(debug) {
when(true.B) {
when(io.in.valid) { printf("%d: [" + cacheName + " S3]: out.valid:%d rdata:%x cmd:%d user:%x \n",
GTimer(), io.out.valid, io.out.bits.rdata, io.out.bits.cmd, io.out.bits.user.getOrElse(0.U)) }
//printf("%d: [" + cacheName + " S3]: DHW: (%d, %d), data:%x MHW:(%d, %d)\n",
//GTimer(), dataHitWriteBus.req.valid, dataHitWriteBus.req.ready, dataHitWriteBus.req.bits.data.asUInt, metaHitWriteBus.req.valid, metaHitWriteBus.req.ready)
//printf("%d: [" + cacheName + " S3]: useFD:%d isFD:%d FD:%x DreadArray:%x dataRead:%x inwaymask:%x FDwaymask:%x \n",
//GTimer(), useForwardData, io.in.bits.isForwardData, io.in.bits.forwardData.data.data, dataReadArray, dataRead, io.in.bits.waymask, io.in.bits.forwardData.waymask.getOrElse("b1".U))
}}
Debug(debug) {
printf("%d: [" + cacheName + " S3]: in.ready = %d, in.valid = %d, hit = %x, state = %d, addr = %x cmd:%d probe:%d isFinish:%d\n",
GTimer(), io.in.ready, io.in.valid, hit, state, req.addr, req.cmd, probe, io.isFinish)
printf("%d: [" + cacheName + " S3]: out.valid:%d rdata:%x cmd:%d user:%x \n",
GTimer(), io.out.valid, io.out.bits.rdata, io.out.bits.cmd, io.out.bits.user.getOrElse(0.U))
printf("%d: [" + cacheName + " S3]: DHW: (%d, %d), data:%x MHW:(%d, %d)\n",
GTimer(), dataHitWriteBus.req.valid, dataHitWriteBus.req.ready, dataHitWriteBus.req.bits.data.asUInt, metaHitWriteBus.req.valid, metaHitWriteBus.req.ready)
printf("%d: [" + cacheName + " S3]: useFD:%d isFD:%d FD:%x DreadArray:%x dataRead:%x inwaymask:%x FDwaymask:%x \n",
GTimer(), useForwardData, io.in.bits.isForwardData, io.in.bits.forwardData.data.data, dataReadArray, dataRead, io.in.bits.waymask, io.in.bits.forwardData.waymask.getOrElse("b1".U))
}
}
......@@ -407,13 +452,15 @@ class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule {
s1.io.in <> arb.io.out
PipelineConnect(s1.io.out, s2.io.in, s2.io.out.fire(), io.flush(0))
PipelineConnect(s2.io.out, s3.io.in, s3.io.isFinish, io.flush(1))
PipelineConnect(s2.io.out, s3.io.in, s3.io.isFinish, io.flush(1) || s2.io.out.bits.mmio && s2.io.out.bits.req.isPrefetch())
io.in.resp <> s3.io.out
s3.io.flush := io.flush(1)
io.out.mem <> s3.io.mem
io.mmio <> s3.io.mmio
io.empty := !s2.io.in.valid && !s3.io.in.valid
io.in.resp.valid := Mux(s3.io.out.bits.isPrefetch(), false.B, s3.io.out.valid || s3.io.dataReadRespToL1)
if (hasCoh) {
val cohReq = io.out.coh.req.bits
// coh does not have user signal, any better code?
......
......@@ -44,6 +44,7 @@ class NOOP(implicit val p: NOOPConfig) extends NOOPModule {
val imem = new SimpleBusC
val dmem = new SimpleBusC
val mmio = new SimpleBusUC
val prefetchReq = Decoupled(new SimpleBusReqBundle)
})
val ifu = Module(new IFU)
......@@ -109,10 +110,5 @@ class NOOP(implicit val p: NOOPConfig) extends NOOPModule {
io.mmio <> mmioXbar.io.out
/* io.imem <> Cache(ifu.io.imem, mmioXbar.io.in(0), Fill(2, ifu.io.flushVec(0) | ifu.io.bpFlush))(
CacheConfig(ro = true, name = "icache", userBits = AddrBits*2 + 4)) // userBits = AddrBits + BrIdxBits
io.dmem <> Cache(exu.io.dmem, mmioXbar.io.in(1), "b00".U, enable = HasDcache)(CacheConfig(ro = false, name = "dcache"))
io.mmio <> mmioXbar.io.out
*/
io.prefetchReq := DontCare
}
......@@ -722,10 +722,10 @@ class CSR(implicit val p: NOOPConfig) extends NOOPModule with HasCSRConst{
"Custom5" -> (0xb1f, "Custom5" ),
"Custom6" -> (0xb20, "Custom6" ),
"Custom7" -> (0xb21, "Custom7" ),
"Custom8" -> (0xb22, "Custom8" )
"Custom8" -> (0xb22, "Custom8" ),
"Ml2cacheHit" -> (0xb23, "perfCntCondMl2cacheHit")
)
val perfCntCond = List.fill(0x80)(WireInit(false.B))
val perfCntCond = List.fill(0x80)(WireInit(false.B))
(perfCnts zip perfCntCond).map { case (c, e) => { when (e) { c := c + 1.U } } }
BoringUtils.addSource(WireInit(true.B), "perfCntCondMcycle")
......
package system
import noop.{NOOP, NOOPConfig, HasNOOPParameter, Cache, CacheConfig}
import bus.axi4.{AXI4, AXI4Lite}
import bus.simplebus._
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
trait HasPrefetcherParameter extends HasNOOPParameter {
val supportPrefetch = HasDcache
}
class Prefetcher extends Module with HasPrefetcherParameter {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new SimpleBusReqBundle))
val out = Decoupled(new SimpleBusReqBundle)
})
/*
io.in.ready := !io.in.valid || io.out.fire()
val lastReq = RegEnable(io.in.bits, io.in.fire())
val lastAddr = lastReq.addr
io.out.bits := lastReq
io.out.bits.cmd := SimpleBusCmd.prefetch
io.out.bits.addr := lastAddr + Cat(Cat(0.U((TagBits + IndexBits - 1).W), 1.U(1.W)), 0.U(OffsetBits.W))
io.out.valid := io.in.valid
*/
io.out.bits := io.in.bits
io.out.bits.cmd := SimpleBusCmd.prefetch
// io.out.bits.addr := io.in.bits.addr + Cat(Cat(0.U((TagBits + IndexBits - 1).W), 1.U(1.W)), 0.U(OffsetBits.W))
io.out.bits.addr := io.in.bits.addr + 64.U(32.W)
io.out.valid := io.in.valid
io.in.ready := !io.in.valid || io.out.fire()
}
package system
import noop.{NOOP, NOOPConfig}
import noop._
import bus.axi4.{AXI4, AXI4Lite}
import bus.simplebus._
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
trait HasILAParameter {
val enableILA = false
trait HasSoCParameter {
val EnableILA = false
val HasL2cache = true
val HasPrefetch = false
}
class ILABundle extends Bundle {
......@@ -20,13 +23,13 @@ class ILABundle extends Bundle {
val InstrCnt = UInt(64.W)
}
class NOOPSoC(implicit val p: NOOPConfig) extends Module with HasILAParameter {
class NOOPSoC(implicit val p: NOOPConfig) extends Module with HasSoCParameter {
val io = IO(new Bundle{
val mem = new AXI4
val mmio = (if (p.FPGAPlatform) { new AXI4Lite } else { new SimpleBusUC })
val mtip = Input(Bool())
val meip = Input(Bool())
val ila = if (p.FPGAPlatform && enableILA) Some(Output(new ILABundle)) else None
val ila = if (p.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
})
val noop = Module(new NOOP)
......@@ -36,7 +39,34 @@ class NOOPSoC(implicit val p: NOOPConfig) extends Module with HasILAParameter {
noop.io.dmem.coh <> cohMg.io.out.coh
xbar.io.in(0) <> cohMg.io.out.mem
xbar.io.in(1) <> noop.io.dmem.mem
io.mem <> xbar.io.out.toAXI4()
if (HasL2cache) {
val l2cacheOut = Wire(new SimpleBusC)
val l2cacheIn = if (HasPrefetch) {
val prefetcher = Module(new Prefetcher)
prefetcher.io.in <> noop.io.prefetchReq
val l2cacheIn = Wire(new SimpleBusUC)
val l2cacheInReqArb = Module(new Arbiter(chiselTypeOf(noop.io.prefetchReq.bits), 2))
l2cacheInReqArb.io.in(0) <> xbar.io.out.req
l2cacheInReqArb.io.in(1) <> prefetcher.io.out
l2cacheIn.req <> l2cacheInReqArb.io.out
xbar.io.out.resp <> l2cacheIn.resp
l2cacheIn
} else xbar.io.out
val l2Empty = Wire(Bool())
l2cacheOut <> Cache(in = l2cacheIn, mmio = 0.U.asTypeOf(new SimpleBusUC), flush = "b00".U, empty = l2Empty, enable = true)(
CacheConfig(name = "l2cache", totalSize = 128, cacheLevel = 2))
io.mem <> l2cacheOut.mem.toAXI4()
l2cacheOut.coh.resp.ready := true.B
l2cacheOut.coh.req.valid := false.B
l2cacheOut.coh.req.bits := DontCare
} else {
io.mem <> xbar.io.out.toAXI4()
}
if (!HasPrefetch) {
noop.io.prefetchReq.ready := true.B
}
noop.io.imem.coh.resp.ready := true.B
noop.io.imem.coh.req.valid := false.B
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册