1
0

Handle TL errors in L1 I$

Cache the error bit in the tag array; report precisely on access.
This commit is contained in:
Andrew Waterman 2017-07-05 23:40:52 -07:00
parent 988caf5e34
commit 438abc76d2
2 changed files with 29 additions and 10 deletions

View File

@ -168,12 +168,13 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
fq.io.enq.bits.pc := s2_pc fq.io.enq.bits.pc := s2_pc
io.cpu.npc := ~(~Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc) | (coreInstBytes-1)) // discard LSB(s) io.cpu.npc := ~(~Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc) | (coreInstBytes-1)) // discard LSB(s)
fq.io.enq.bits.data := icache.io.resp.bits fq.io.enq.bits.data := icache.io.resp.bits.data
fq.io.enq.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes)) fq.io.enq.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes))
fq.io.enq.bits.xcpt := s2_tlb_resp
fq.io.enq.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt fq.io.enq.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt
fq.io.enq.bits.btb.valid := s2_btb_resp_valid fq.io.enq.bits.btb.valid := s2_btb_resp_valid
fq.io.enq.bits.btb.bits := s2_btb_resp_bits fq.io.enq.bits.btb.bits := s2_btb_resp_bits
fq.io.enq.bits.xcpt := s2_tlb_resp
when (icache.io.resp.valid && icache.io.resp.bits.ae) { fq.io.enq.bits.xcpt.ae.inst := true }
io.cpu.resp <> fq.io.deq io.cpu.resp <> fq.io.deq

View File

@ -58,6 +58,13 @@ class ICache(val icacheParams: ICacheParams, val hartid: Int)(implicit p: Parame
} }
} }
class ICacheResp(outer: ICache) extends Bundle {
val data = UInt(width = outer.icacheParams.fetchBytes*8)
val ae = Bool()
override def cloneType = new ICacheResp(outer).asInstanceOf[this.type]
}
class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) { class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) {
val hartid = UInt(INPUT, hartIdLen) val hartid = UInt(INPUT, hartIdLen)
val req = Decoupled(new ICacheReq).flip val req = Decoupled(new ICacheReq).flip
@ -66,7 +73,7 @@ class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) {
val s1_kill = Bool(INPUT) // delayed one cycle w.r.t. req val s1_kill = Bool(INPUT) // delayed one cycle w.r.t. req
val s2_kill = Bool(INPUT) // delayed two cycles; prevents I$ miss emission val s2_kill = Bool(INPUT) // delayed two cycles; prevents I$ miss emission
val resp = Valid(UInt(width = outer.icacheParams.fetchBytes*8)) val resp = Valid(new ICacheResp(outer))
val invalidate = Bool(INPUT) val invalidate = Bool(INPUT)
val tl_out = outer.masterNode.bundleOut val tl_out = outer.masterNode.bundleOut
val tl_in = outer.slaveNode.map(_.bundleIn) val tl_in = outer.slaveNode.map(_.bundleIn)
@ -145,15 +152,18 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
v v
} }
val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = tECC.width(tagBits)))) val tag_array = SeqMem(nSets, Vec(nWays, UInt(width = tECC.width(1 + tagBits))))
val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid) val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid)
val accruedRefillError = Reg(Bool())
val refillError = tl_out.d.bits.error || (refill_cnt > 0 && accruedRefillError)
when (refill_done) { when (refill_done) {
val tag = tECC.encode(refill_tag) val encTag = tECC.encode(Cat(refillError, refill_tag))
tag_array.write(refill_idx, Vec.fill(nWays)(tag), Vec.tabulate(nWays)(repl_way === _)) tag_array.write(refill_idx, Vec.fill(nWays)(encTag), Seq.tabulate(nWays)(repl_way === _))
} }
val vb_array = Reg(init=Bits(0, nSets*nWays)) val vb_array = Reg(init=Bits(0, nSets*nWays))
when (tl_out.d.fire()) { when (tl_out.d.fire()) {
accruedRefillError := refillError
// clear bit when refill starts so hit-under-miss doesn't fetch bad data // clear bit when refill starts so hit-under-miss doesn't fetch bad data
vb_array := vb_array.bitSet(Cat(repl_way, refill_idx), refill_done && !invalidated) vb_array := vb_array.bitSet(Cat(repl_way, refill_idx), refill_done && !invalidated)
} }
@ -164,6 +174,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
} }
val s1_tag_disparity = Wire(Vec(nWays, Bool())) val s1_tag_disparity = Wire(Vec(nWays, Bool()))
val s1_tlError = Wire(Vec(nWays, Bool()))
val wordBits = outer.icacheParams.fetchBytes*8 val wordBits = outer.icacheParams.fetchBytes*8
val s1_dout = Wire(Vec(nWays, UInt(width = dECC.width(wordBits)))) val s1_dout = Wire(Vec(nWays, UInt(width = dECC.width(wordBits))))
@ -179,8 +190,12 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
lineInScratchpad(scratchpadLine(s1s3_slaveAddr)) && scratchpadWay(s1s3_slaveAddr) === i, lineInScratchpad(scratchpadLine(s1s3_slaveAddr)) && scratchpadWay(s1s3_slaveAddr) === i,
addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i) addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i)
val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid
s1_tag_disparity(i) := s1_vb && tECC.decode(tag_rdata(i)).error val encTag = tECC.decode(tag_rdata(i))
s1_tag_hit(i) := scratchpadHit || (s1_vb && tECC.decode(tag_rdata(i)).uncorrected === s1_tag) val (tlError, tag) = Split(encTag.uncorrected, tagBits)
val tagMatch = s1_vb && tag === s1_tag
s1_tag_disparity(i) := s1_vb && encTag.error
s1_tlError(i) := tagMatch && tlError.toBool
s1_tag_hit(i) := tagMatch || scratchpadHit
} }
assert(!(s1_valid || s1_slaveValid) || PopCount(s1_tag_hit zip s1_tag_disparity map { case (h, d) => h && !d }) <= 1) assert(!(s1_valid || s1_slaveValid) || PopCount(s1_tag_hit zip s1_tag_disparity map { case (h, d) => h && !d }) <= 1)
@ -212,7 +227,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
require(tECC.isInstanceOf[uncore.util.IdentityCode]) require(tECC.isInstanceOf[uncore.util.IdentityCode])
require(dECC.isInstanceOf[uncore.util.IdentityCode]) require(dECC.isInstanceOf[uncore.util.IdentityCode])
require(outer.icacheParams.itimAddr.isEmpty) require(outer.icacheParams.itimAddr.isEmpty)
io.resp.bits := Mux1H(s1_tag_hit, s1_dout) io.resp.bits.data := Mux1H(s1_tag_hit, s1_dout)
io.resp.bits.ae := s1_tlError.asUInt.orR
io.resp.valid := s1_valid && s1_hit io.resp.valid := s1_valid && s1_hit
case 2 => case 2 =>
@ -221,11 +237,13 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
val s2_way_mux = Mux1H(s2_tag_hit, s2_dout) val s2_way_mux = Mux1H(s2_tag_hit, s2_dout)
val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_valid || s1_slaveValid).asUInt.orR val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_valid || s1_slaveValid).asUInt.orR
val s2_tlError = RegEnable(s1_tlError.asUInt.orR, s1_valid || s1_slaveValid)
val s2_data_decoded = dECC.decode(s2_way_mux) val s2_data_decoded = dECC.decode(s2_way_mux)
val s2_disparity = s2_tag_disparity || s2_data_decoded.error val s2_disparity = s2_tag_disparity || s2_data_decoded.error
when (s2_valid && s2_disparity) { invalidate := true } when (s2_valid && s2_disparity) { invalidate := true }
io.resp.bits := s2_data_decoded.uncorrected io.resp.bits.data := s2_data_decoded.uncorrected
io.resp.bits.ae := s2_tlError
io.resp.valid := s2_valid && s2_hit && !s2_disparity io.resp.valid := s2_valid && s2_hit && !s2_disparity
tl_in.map { tl => tl_in.map { tl =>