diff --git a/src/main/scala/rocket/Frontend.scala b/src/main/scala/rocket/Frontend.scala index 44f51d32..7a341047 100644 --- a/src/main/scala/rocket/Frontend.scala +++ b/src/main/scala/rocket/Frontend.scala @@ -168,12 +168,13 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer) 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) - 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.xcpt := s2_tlb_resp 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.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 diff --git a/src/main/scala/rocket/ICache.scala b/src/main/scala/rocket/ICache.scala index dfb240f4..57368a8c 100644 --- a/src/main/scala/rocket/ICache.scala +++ b/src/main/scala/rocket/ICache.scala @@ -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) { val hartid = UInt(INPUT, hartIdLen) 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 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 tl_out = outer.masterNode.bundleOut val tl_in = outer.slaveNode.map(_.bundleIn) @@ -145,15 +152,18 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) 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 accruedRefillError = Reg(Bool()) + val refillError = tl_out.d.bits.error || (refill_cnt > 0 && accruedRefillError) when (refill_done) { - val tag = tECC.encode(refill_tag) - tag_array.write(refill_idx, Vec.fill(nWays)(tag), Vec.tabulate(nWays)(repl_way === _)) + val encTag = tECC.encode(Cat(refillError, refill_tag)) + tag_array.write(refill_idx, Vec.fill(nWays)(encTag), Seq.tabulate(nWays)(repl_way === _)) } val vb_array = Reg(init=Bits(0, nSets*nWays)) when (tl_out.d.fire()) { + accruedRefillError := refillError // 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) } @@ -164,6 +174,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) } val s1_tag_disparity = Wire(Vec(nWays, Bool())) + val s1_tlError = Wire(Vec(nWays, Bool())) val wordBits = outer.icacheParams.fetchBytes*8 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, addrInScratchpad(io.s1_paddr) && scratchpadWay(io.s1_paddr) === i) val s1_vb = vb_array(Cat(UInt(i), s1_idx)) && !s1_slaveValid - s1_tag_disparity(i) := s1_vb && tECC.decode(tag_rdata(i)).error - s1_tag_hit(i) := scratchpadHit || (s1_vb && tECC.decode(tag_rdata(i)).uncorrected === s1_tag) + val encTag = tECC.decode(tag_rdata(i)) + 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) @@ -212,7 +227,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer) require(tECC.isInstanceOf[uncore.util.IdentityCode]) require(dECC.isInstanceOf[uncore.util.IdentityCode]) 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 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_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_disparity = s2_tag_disparity || s2_data_decoded.error 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 tl_in.map { tl =>