187 lines
6.8 KiB
Scala
187 lines
6.8 KiB
Scala
import chisel3._
|
|
import chisel3.util._
|
|
|
|
class ICache(p: CoreParams = CoreParams()) extends Module {
|
|
private val lineInsts = p.fetchWidth
|
|
private val lineBytes = lineInsts * 4
|
|
private val sets = p.iCacheBytes / (p.iCacheWays * lineBytes)
|
|
private val setBits = log2Ceil(sets)
|
|
private val instBits = log2Ceil(lineInsts)
|
|
private val offsetBits = log2Ceil(lineBytes)
|
|
|
|
val io = IO(new Bundle {
|
|
val reqValid = Input(Bool())
|
|
val reqAddr = Input(UInt(p.xlen.W))
|
|
val reqPc = Input(UInt(p.xlen.W))
|
|
val flush = Input(Bool())
|
|
val invalidate = Input(Bool())
|
|
val respReady = Input(Bool())
|
|
val memReqValid = Output(Bool())
|
|
val memReqAddr = Output(UInt(p.xlen.W))
|
|
val memRespValid = Input(Bool())
|
|
val memRespBits = Input(Vec(p.fetchWidth, UInt(32.W)))
|
|
val respValid = Output(Bool())
|
|
val resp = Output(new FetchPacket(p))
|
|
val miss = Output(Bool())
|
|
})
|
|
|
|
def setIndex(addr: UInt): UInt = addr(offsetBits + setBits - 1, offsetBits)
|
|
def instIndex(addr: UInt): UInt = addr(offsetBits - 1, 2)
|
|
def tag(addr: UInt): UInt = addr(p.xlen - 1, offsetBits + setBits)
|
|
def alignedFetchAddr(addr: UInt): UInt = Cat(addr(p.xlen - 1, offsetBits), 0.U(offsetBits.W))
|
|
|
|
val valid = RegInit(VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.iCacheWays)(
|
|
VecInit(Seq.fill(lineInsts)(false.B)))))))
|
|
val tags = SyncReadMem(sets, Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
|
val data = SyncReadMem(sets, Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
|
val repl = RegInit(VecInit(Seq.fill(sets)(0.U(log2Ceil(p.iCacheWays).W))))
|
|
|
|
val sIdle :: sLookup :: sResp :: sMiss :: Nil = Enum(4)
|
|
val state = RegInit(sIdle)
|
|
|
|
val lookupAddr = Reg(UInt(p.xlen.W))
|
|
val lookupPc = Reg(UInt(p.xlen.W))
|
|
val lookupSet = Reg(UInt(setBits.W))
|
|
val lookupInst = Reg(UInt(instBits.W))
|
|
val lookupValidRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
|
|
|
val missAddr = Reg(UInt(p.xlen.W))
|
|
val missPc = Reg(UInt(p.xlen.W))
|
|
val missSet = Reg(UInt(setBits.W))
|
|
val missInst = Reg(UInt(instBits.W))
|
|
val missWay = Reg(UInt(log2Ceil(p.iCacheWays).W))
|
|
val missRefillExisting = Reg(Bool())
|
|
val missTagRow = Reg(Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
|
val missDataRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
|
val missValidRow = Reg(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
|
val missReqSent = RegInit(false.B)
|
|
|
|
val respReg = Reg(new FetchPacket(p))
|
|
|
|
val reqSet = setIndex(io.reqAddr)
|
|
val reqInst = instIndex(io.reqAddr)
|
|
val readFire = state === sIdle && io.reqValid && !io.flush
|
|
val readTags = tags.read(reqSet, readFire)
|
|
val readData = data.read(reqSet, readFire)
|
|
|
|
val tagHitVec = VecInit((0 until p.iCacheWays).map(w => lookupValidRow(w).asUInt.orR && readTags(w) === tag(lookupAddr)))
|
|
val hitVec = VecInit((0 until p.iCacheWays).map(w => tagHitVec(w) && lookupValidRow(w)(lookupInst)))
|
|
val hit = hitVec.asUInt.orR
|
|
val hitWay = OHToUInt(hitVec)
|
|
val tagHit = tagHitVec.asUInt.orR
|
|
val tagHitWay = OHToUInt(tagHitVec)
|
|
val lastInst = (lineInsts - 1).U(instBits.W)
|
|
val nextInst = lookupInst + 1.U
|
|
val lookupCanFetchPair = lookupInst =/= lastInst
|
|
val lookupLane1Valid = lookupCanFetchPair && lookupValidRow(hitWay)(nextInst)
|
|
|
|
val lookupResp = WireDefault(0.U.asTypeOf(new FetchPacket(p)))
|
|
lookupResp.pc := lookupPc
|
|
lookupResp.inst(0) := readData(hitWay)(lookupInst)
|
|
lookupResp.inst(1) := Mux(lookupLane1Valid, readData(hitWay)(nextInst), 0.U)
|
|
lookupResp.laneValid(0) := true.B
|
|
lookupResp.laneValid(1) := lookupLane1Valid
|
|
lookupResp.predictedTaken := false.B
|
|
lookupResp.predictedTarget := lookupPc + (4 * p.fetchWidth).U
|
|
|
|
val missCanFetchPair = missInst =/= lastInst
|
|
val missResp = WireDefault(0.U.asTypeOf(new FetchPacket(p)))
|
|
missResp.pc := missPc
|
|
missResp.inst(0) := io.memRespBits(0)
|
|
missResp.inst(1) := Mux(missCanFetchPair, io.memRespBits(1), 0.U)
|
|
missResp.laneValid(0) := true.B
|
|
missResp.laneValid(1) := missCanFetchPair
|
|
missResp.predictedTaken := false.B
|
|
missResp.predictedTarget := missPc + (4 * p.fetchWidth).U
|
|
|
|
io.memReqValid := state === sMiss && !missReqSent
|
|
io.memReqAddr := Mux(state === sMiss,
|
|
Mux(missCanFetchPair, alignedFetchAddr(missAddr), missAddr),
|
|
Mux(reqInst =/= lastInst, alignedFetchAddr(io.reqAddr), io.reqAddr))
|
|
io.respValid := (state === sLookup && hit) || state === sResp || (state === sMiss && io.memRespValid)
|
|
io.resp := Mux(state === sResp, respReg,
|
|
Mux(state === sMiss && io.memRespValid, missResp, lookupResp))
|
|
io.miss := state === sLookup && !hit || state === sMiss
|
|
|
|
when(io.invalidate) {
|
|
valid := VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.iCacheWays)(
|
|
VecInit(Seq.fill(lineInsts)(false.B))))))
|
|
state := sIdle
|
|
missReqSent := false.B
|
|
}.elsewhen(io.flush) {
|
|
state := sIdle
|
|
missReqSent := false.B
|
|
}.elsewhen(state === sIdle) {
|
|
when(io.reqValid) {
|
|
lookupAddr := io.reqAddr
|
|
lookupPc := io.reqPc
|
|
lookupSet := reqSet
|
|
lookupInst := reqInst
|
|
lookupValidRow := valid(reqSet)
|
|
state := sLookup
|
|
}
|
|
}.elsewhen(state === sLookup) {
|
|
when(hit) {
|
|
repl(lookupSet) := hitWay
|
|
when(io.respReady) {
|
|
state := sIdle
|
|
}.otherwise {
|
|
respReg := lookupResp
|
|
state := sResp
|
|
}
|
|
}.otherwise {
|
|
missAddr := lookupAddr
|
|
missPc := lookupPc
|
|
missSet := lookupSet
|
|
missInst := lookupInst
|
|
missWay := Mux(tagHit, tagHitWay, repl(lookupSet))
|
|
missRefillExisting := tagHit
|
|
missTagRow := readTags
|
|
missDataRow := readData
|
|
missValidRow := lookupValidRow
|
|
missReqSent := false.B
|
|
state := sMiss
|
|
}
|
|
}.elsewhen(state === sResp) {
|
|
when(io.respReady) {
|
|
state := sIdle
|
|
}
|
|
}.elsewhen(state === sMiss) {
|
|
when(!missReqSent) {
|
|
missReqSent := true.B
|
|
}
|
|
when(io.memRespValid) {
|
|
val tagWrite = Wire(Vec(p.iCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
|
|
val dataWrite = Wire(Vec(p.iCacheWays, Vec(lineInsts, UInt(32.W))))
|
|
val validWrite = Wire(Vec(p.iCacheWays, Vec(lineInsts, Bool())))
|
|
tagWrite := missTagRow
|
|
dataWrite := missDataRow
|
|
validWrite := missValidRow
|
|
tagWrite(missWay) := tag(missAddr)
|
|
when(!missRefillExisting) {
|
|
for (i <- 0 until lineInsts) {
|
|
validWrite(missWay)(i) := false.B
|
|
}
|
|
}
|
|
dataWrite(missWay)(missInst) := io.memRespBits(0)
|
|
validWrite(missWay)(missInst) := true.B
|
|
when(missCanFetchPair) {
|
|
dataWrite(missWay)(missInst + 1.U) := io.memRespBits(1)
|
|
validWrite(missWay)(missInst + 1.U) := true.B
|
|
}
|
|
valid(missSet) := validWrite
|
|
tags.write(missSet, tagWrite)
|
|
data.write(missSet, dataWrite)
|
|
when(!missRefillExisting) {
|
|
repl(missSet) := missWay + 1.U
|
|
}
|
|
when(io.respReady) {
|
|
state := sIdle
|
|
}.otherwise {
|
|
respReg := missResp
|
|
state := sResp
|
|
}
|
|
}
|
|
}
|
|
}
|