Skip to content

Commit

Permalink
Fetch: optimization timing for IFU/ICache/IPrefetch (OpenXiangShan#1432)
Browse files Browse the repository at this point in the history
* IFU <timing>: f2_data select signal optimization

* ICacheMainPipe <timing>: latch fetch req when tlb miss

* Frontend <timing>: add additional PMP checker

* Ftq <timing>: delete flush condition for prefetch.req

* ICacheMainPipe <timing>: move hit state change to s2

* ICache <bug-fix> delete PMP check assertion

* ICache <bug-fix> fix parity error condition

* ICacheMainPipe <bug-fix>: fix tlb resp condition

* when TLB req has been latched into tlb_slot, the
tlb_all_resp condition, which affects s0_fire should
depend on the slot result.
  • Loading branch information
jinyue110 authored Jan 23, 2022
1 parent ff1b5db commit 61e1db3
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 72 deletions.
18 changes: 10 additions & 8 deletions src/main/scala/xiangshan/frontend/Frontend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,23 @@ class FrontendImp (outer: Frontend) extends LazyModuleImp(outer)
val triggerEn = csrCtrl.trigger_enable
ifu.io.csrTriggerEnable := VecInit(triggerEn(0), triggerEn(1), triggerEn(6), triggerEn(8))

// pmp
// pmp
val pmp = Module(new PMP())
val pmp_check = VecInit(Seq.fill(2)(Module(new PMPChecker(3, sameCycle = true)).io))
val pmp_check = VecInit(Seq.fill(4)(Module(new PMPChecker(3, sameCycle = true)).io))
pmp.io.distribute_csr := csrCtrl.distribute_csr
val pmp_req_vec = Wire(Vec(2, Valid(new PMPReqBundle())))
val pmp_req_vec = Wire(Vec(4, Valid(new PMPReqBundle())))
pmp_req_vec(0) <> icache.io.pmp(0).req
pmp_req_vec(1).valid := icache.io.pmp(1).req.valid || ifu.io.pmp.req.valid
pmp_req_vec(1).bits := Mux(ifu.io.pmp.req.valid, ifu.io.pmp.req.bits, icache.io.pmp(1).req.bits)
pmp_req_vec(1) <> icache.io.pmp(1).req
pmp_req_vec(2) <> icache.io.pmp(2).req
pmp_req_vec(3) <> ifu.io.pmp.req

for (i <- pmp_check.indices) {
pmp_check(i).apply(tlbCsr.priv.imode, pmp.io.pmp, pmp.io.pma, pmp_req_vec(i))
icache.io.pmp(i).resp <> pmp_check(i).resp
}
ifu.io.pmp.resp <> pmp_check(1).resp
ifu.io.pmp.req.ready := false.B
icache.io.pmp(0).resp <> pmp_check(0).resp
icache.io.pmp(1).resp <> pmp_check(1).resp
icache.io.pmp(2).resp <> pmp_check(2).resp
ifu.io.pmp.resp <> pmp_check(3 ).resp

val tlb_req_arb = Module(new Arbiter(new TlbReq, 2))
tlb_req_arb.io.in(0) <> ifu.io.iTLBInter.req
Expand Down
17 changes: 10 additions & 7 deletions src/main/scala/xiangshan/frontend/IFU.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class NewIFUIO(implicit p: Parameters) extends XSBundle {
val csrTriggerEnable = Input(Vec(4, Bool()))
val rob_commits = Flipped(Vec(CommitWidth, Valid(new RobCommitInfo)))
val iTLBInter = new BlockTlbRequestIO
val pmp = new IPrefetchPMPBundle
val pmp = new ICachePMPBundle
}

// record the situation in which fallThruAddr falls into
Expand Down Expand Up @@ -235,7 +235,9 @@ class NewIFU(implicit p: Parameters) extends XSModule
.elsewhen(f1_fire && !f1_flush) {f2_valid := true.B }
.elsewhen(f2_fire) {f2_valid := false.B}

val f2_cache_response_data = ResultHoldBypass(valid = f2_icache_all_resp_wire, data = VecInit(fromICache.map(_.bits.readData)))
// val f2_cache_response_data = ResultHoldBypass(valid = f2_icache_all_resp_wire, data = VecInit(fromICache.map(_.bits.readData)))
val f2_cache_response_data = VecInit(fromICache.map(_.bits.readData))


val f2_except_pf = VecInit((0 until PortNumber).map(i => fromICache(i).bits.tlbExcp.pageFault))
val f2_except_af = VecInit((0 until PortNumber).map(i => fromICache(i).bits.tlbExcp.accessFault))
Expand Down Expand Up @@ -366,10 +368,11 @@ class NewIFU(implicit p: Parameters) extends XSModule
val f3_mmio_to_commit_next = RegNext(f3_mmio_to_commit)
val f3_mmio_can_go = f3_mmio_to_commit && !f3_mmio_to_commit_next

val f3_ftq_flush_self = fromFtq.redirect.valid && RedirectLevel.flushItself(fromFtq.redirect.bits.level)
val f3_ftq_flush_by_older = fromFtq.redirect.valid && isBefore(fromFtq.redirect.bits.ftqIdx, f3_ftq_req.ftqIdx)
val fromFtqRedirectReg = RegNext(fromFtq.redirect)
val f3_ftq_flush_self = fromFtqRedirectReg.valid && RedirectLevel.flushItself(fromFtqRedirectReg.bits.level)
val f3_ftq_flush_by_older = fromFtqRedirectReg.valid && isBefore(fromFtqRedirectReg.bits.ftqIdx, f3_ftq_req.ftqIdx)

val f3_need_not_flush = f3_req_is_mmio && fromFtq.redirect.valid && !f3_ftq_flush_self && !f3_ftq_flush_by_older
val f3_need_not_flush = f3_req_is_mmio && fromFtqRedirectReg.valid && !f3_ftq_flush_self && !f3_ftq_flush_by_older

when(f3_flush && !f3_need_not_flush) {f3_valid := false.B}
.elsewhen(f2_fire && !f2_flush ) {f3_valid := true.B }
Expand All @@ -378,8 +381,8 @@ class NewIFU(implicit p: Parameters) extends XSModule

val f3_mmio_use_seq_pc = RegInit(false.B)

val (redirect_ftqIdx, redirect_ftqOffset) = (fromFtq.redirect.bits.ftqIdx,fromFtq.redirect.bits.ftqOffset)
val redirect_mmio_req = fromFtq.redirect.valid && redirect_ftqIdx === f3_ftq_req.ftqIdx && redirect_ftqOffset === 0.U
val (redirect_ftqIdx, redirect_ftqOffset) = (fromFtqRedirectReg.bits.ftqIdx,fromFtqRedirectReg.bits.ftqOffset)
val redirect_mmio_req = fromFtqRedirectReg.valid && redirect_ftqIdx === f3_ftq_req.ftqIdx && redirect_ftqOffset === 0.U

when(RegNext(f2_fire && !f2_flush) && f3_req_is_mmio) { f3_mmio_use_seq_pc := true.B }
.elsewhen(redirect_mmio_req) { f3_mmio_use_seq_pc := false.B }
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/xiangshan/frontend/NewFtq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ class Ftq(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelpe
// XSError(true.B, "\ns3_redirect mechanism not implemented!\n")
}

io.toPrefetch.req.valid := allowToIfu && prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send
io.toPrefetch.req.valid := prefetchPtr =/= bpuPtr && entry_fetch_status(prefetchPtr.value) === f_to_send
io.toPrefetch.req.bits.target := update_target(prefetchPtr.value)

when(redirectVec.map(r => r.valid).reduce(_||_)){
Expand Down
22 changes: 7 additions & 15 deletions src/main/scala/xiangshan/frontend/icache/ICache.scala
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,9 @@ class ICacheDataArray(implicit p: Parameters) extends ICacheArray
for(((dataArray,codeArray),i) <- dataArrays.zip(codeArrays).zipWithIndex){
read_datas(i) := dataArray.io.r.resp.asTypeOf(Vec(nWays,UInt(blockBits.W)))
read_codes(i) := codeArray.io.r.resp.asTypeOf(Vec(nWays,UInt(dataCodeEntryBits.W)))
(0 until nWays).map{ w => io.readResp.errors(i)(w) := RegNext(io.read.fire()) && read_codes(i)(w).asUInt.orR }
val data_full_wayBits = VecInit((0 until nWays).map( w => Cat(read_codes(i)(w), read_datas(i)(w))))
val data_error_wayBits = VecInit(data_full_wayBits.map(data => cacheParams.dataCode.decode(data).error) )
(0 until nWays).map{ w => io.readResp.errors(i)(w) := RegNext(io.read.fire()) && data_error_wayBits(w) }
}

//Parity Encode
Expand Down Expand Up @@ -434,7 +436,7 @@ class ICacheIO(implicit p: Parameters) extends ICacheBundle
val prefetch = Flipped(new FtqPrefechBundle)
val stop = Input(Bool())
val fetch = Vec(PortNumber, new ICacheMainPipeBundle)
val pmp = Vec(PortNumber, new ICachePMPBundle)
val pmp = Vec(PortNumber + 1, new ICachePMPBundle)
val itlb = Vec(PortNumber, new BlockTlbRequestIO)
val perfInfo = Output(new ICachePerfInfo)
val error = new L1CacheErrorInfo
Expand Down Expand Up @@ -529,24 +531,14 @@ class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParame
prefetchPipe.io.fromFtq <> DontCare
}

io.pmp(0).req.valid := mainPipe.io.pmp(0).req.valid || prefetchPipe.io.pmp.req.valid
io.pmp(0).req.bits := Mux(mainPipe.io.pmp(0).req.valid, mainPipe.io.pmp(0).req.bits, prefetchPipe.io.pmp.req.bits)
prefetchPipe.io.pmp.req.ready := !mainPipe.io.pmp(0).req.valid

mainPipe.io.pmp(0).resp <> io.pmp(0).resp
prefetchPipe.io.pmp.resp <> io.pmp(0).resp
io.pmp(0) <> mainPipe.io.pmp(0)
io.pmp(1) <> mainPipe.io.pmp(1)
io.pmp(2) <> prefetchPipe.io.pmp

prefetchPipe.io.prefetchEnable := mainPipe.io.prefetchEnable
prefetchPipe.io.prefetchDisable := mainPipe.io.prefetchDisable


io.pmp(1) <> mainPipe.io.pmp(1)

when(mainPipe.io.pmp(0).req.valid && prefetchPipe.io.pmp.req.valid)
{
assert(false.B, "Both mainPipe PMP and prefetchPipe PMP valid!")
}

tlb_req_arb.io.in(0) <> mainPipe.io.itlb(0).req
tlb_req_arb.io.in(1) <> prefetchPipe.io.iTLBInter.req
io.itlb(0).req <> tlb_req_arb.io.out
Expand Down
87 changes: 54 additions & 33 deletions src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,27 +138,45 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
val s0_valid = fromIFU.map(_.valid).reduce(_||_)
val s0_req_vaddr = VecInit(fromIFU.map(_.bits.vaddr))
val s0_req_vsetIdx = VecInit(fromIFU.map(_.bits.vsetIdx))
val s0_only_fisrt = fromIFU(0).valid && !fromIFU(0).valid
val s0_only_first = fromIFU(0).valid && !fromIFU(0).valid
val s0_double_line = fromIFU(0).valid && fromIFU(1).valid

/** s0 tlb */
class tlbMissSlot(implicit p: Parameters) extends ICacheBundle{
val valid = Bool()
val only_first = Bool()
val double_line = Bool()
val req_vaddr = Vec(PortNumber,UInt(VAddrBits.W))
val req_vsetIdx = Vec(PortNumber, UInt(idxBits.W))
}

val tlb_slot = RegInit(0.U.asTypeOf(new tlbMissSlot))

val s0_final_vaddr = Mux(tlb_slot.valid,tlb_slot.req_vaddr ,s0_req_vaddr)
val s0_final_vsetIdx = Mux(tlb_slot.valid,tlb_slot.req_vsetIdx ,s0_req_vsetIdx)
val s0_final_only_first = Mux(tlb_slot.valid,tlb_slot.only_first ,s0_only_first)
val s0_final_double_line = Mux(tlb_slot.valid,tlb_slot.double_line ,s0_double_line)



/** SRAM request */
val fetch_req = List(toMeta, toData)
for(i <- 0 until 2) {
fetch_req(i).valid := s0_valid && !missSwitchBit
fetch_req(i).bits.isDoubleLine := s0_double_line
fetch_req(i).bits.vSetIdx := s0_req_vsetIdx
fetch_req(i).valid := (s0_valid || tlb_slot.valid) && !missSwitchBit
fetch_req(i).bits.isDoubleLine := s0_final_double_line
fetch_req(i).bits.vSetIdx := s0_final_vsetIdx
}

toITLB(0).valid := s0_valid && !missSwitchBit
toITLB(0).valid := (s0_valid || tlb_slot.valid) && !missSwitchBit

toITLB(0).bits.size := 3.U // TODO: fix the size
toITLB(0).bits.vaddr := s0_req_vaddr(0)
toITLB(0).bits.debug.pc := s0_req_vaddr(0)
toITLB(0).bits.vaddr := s0_final_vaddr(0)
toITLB(0).bits.debug.pc := s0_final_vaddr(0)

toITLB(1).valid := s0_valid && s0_double_line && !missSwitchBit
toITLB(1).valid := (s0_valid || tlb_slot.valid) && s0_final_double_line && !missSwitchBit
toITLB(1).bits.size := 3.U // TODO: fix the size
toITLB(1).bits.vaddr := s0_req_vaddr(1)
toITLB(1).bits.debug.pc := s0_req_vaddr(1)
toITLB(1).bits.vaddr := s0_final_vaddr(1)
toITLB(1).bits.debug.pc := s0_final_vaddr(1)

toITLB.map{port =>
port.bits.cmd := TlbCmd.exec
Expand All @@ -167,33 +185,35 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
}

/** ITLB miss wait logic */
val t_idle :: t_miss :: t_fixed :: Nil = Enum(3)
val tlb_status = RegInit(VecInit(Seq.fill(PortNumber)(t_idle)))
dontTouch(tlb_status)
// val t_idle :: t_miss :: t_fixed :: Nil = Enum(3)
// val tlb_status = RegInit(VecInit(Seq.fill(PortNumber)(t_idle)))
// dontTouch(tlb_status)

val tlb_miss_vec = VecInit((0 until PortNumber).map( i => toITLB(i).valid && fromITLB(i).bits.miss ))
val tlb_has_miss = tlb_miss_vec.reduce(_||_)
val tlb_resp = Wire(Vec(2, Bool()))
tlb_resp(0) := !fromITLB(0).bits.miss
tlb_resp(1) := !fromITLB(1).bits.miss || !s0_double_line
tlb_resp(1) := !fromITLB(1).bits.miss || !s0_final_double_line
val tlb_all_resp = tlb_resp.reduce(_&&_)

(0 until PortNumber).map { i =>
when(tlb_miss_vec(i)){
tlb_status(i) := t_miss
}
when(tlb_has_miss && !tlb_slot.valid){
tlb_slot.valid := s0_valid
tlb_slot.only_first := s0_only_first
tlb_slot.double_line := s0_double_line
tlb_slot.req_vaddr := s0_req_vaddr
tlb_slot.req_vsetIdx := s0_req_vsetIdx
}

when(tlb_status(i) === t_miss && !fromITLB(i).bits.miss){
tlb_status(i) := t_idle
}
when(s0_fire && tlb_slot.valid){
tlb_slot.valid := false.B
}

s0_fire := s0_valid && !missSwitchBit && s1_ready && tlb_all_resp && fetch_req(0).ready && fetch_req(1).ready
s0_fire := (s0_valid || tlb_slot.valid) && !missSwitchBit && s1_ready && tlb_all_resp && fetch_req(0).ready && fetch_req(1).ready

//TODO: fix GTimer() condition
fromIFU.map(_.ready := fetch_req(0).ready && fetch_req(1).ready && !missSwitchBit &&
tlb_all_resp &&
!tlb_slot.valid &&
s1_ready && GTimer() > 500.U )

/**
******************************************************************************
* ICache Stage 1
Expand All @@ -208,10 +228,10 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule

val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = false.B, lastFlush = false.B)

val s1_req_vaddr = RegEnable(next = s0_req_vaddr, enable = s0_fire)
val s1_req_vsetIdx = RegEnable(next = s0_req_vsetIdx, enable = s0_fire)
val s1_only_fisrt = RegEnable(next = s0_only_fisrt, enable = s0_fire)
val s1_double_line = RegEnable(next = s0_double_line, enable = s0_fire)
val s1_req_vaddr = RegEnable(next = s0_final_vaddr, enable = s0_fire)
val s1_req_vsetIdx = RegEnable(next = s0_final_vsetIdx, enable = s0_fire)
val s1_only_first = RegEnable(next = s0_final_only_first, enable = s0_fire)
val s1_double_line = RegEnable(next = s0_final_double_line, enable = s0_fire)

s1_ready := s2_ready && tlbRespAllValid || !s1_valid
s1_fire := s1_valid && tlbRespAllValid && s2_ready
Expand Down Expand Up @@ -325,13 +345,14 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
val (s2_req_paddr , s2_req_vaddr) = (RegEnable(next = s1_req_paddr, enable = s1_fire), RegEnable(next = s1_req_vaddr, enable = s1_fire))
val s2_req_vsetIdx = RegEnable(next = s1_req_vsetIdx, enable = s1_fire)
val s2_req_ptags = RegEnable(next = s1_req_ptags, enable = s1_fire)
val s2_only_fisrt = RegEnable(next = s1_only_fisrt, enable = s1_fire)
val s2_only_first = RegEnable(next = s1_only_first, enable = s1_fire)
val s2_double_line = RegEnable(next = s1_double_line, enable = s1_fire)
val s2_hit = RegEnable(next = s1_hit , enable = s1_fire)
val s2_port_hit = RegEnable(next = s1_port_hit, enable = s1_fire)
val s2_bank_miss = RegEnable(next = s1_bank_miss, enable = s1_fire)
val s2_waymask = RegEnable(next = s1_victim_oh, enable = s1_fire)
val s2_victim_coh = RegEnable(next = s1_victim_coh, enable = s1_fire)
val s2_tag_match_vec = RegEnable(next = s1_tag_match_vec, enable = s1_fire)

/** status imply that s2 is a secondary miss (no need to resend miss request) */
val sec_meet_vec = Wire(Vec(2, Bool()))
Expand Down Expand Up @@ -431,7 +452,7 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
def waitSecondComeIn(missState: UInt): Bool = (missState === m_wait_sec_miss)

def getMissSituat(slotNum : Int, missNum : Int ) :Bool = {
RegNext(s1_fire) && (missSlot(slotNum).m_vSetIdx === s2_req_vsetIdx(missNum)) && (missSlot(slotNum).m_pTag === s2_req_ptags(missNum)) && !s2_port_hit(missNum) && waitSecondComeIn(missStateQueue(slotNum)) && !s2_mmio
RegNext(s1_fire) && (missSlot(slotNum).m_vSetIdx === s2_req_vsetIdx(missNum)) && (missSlot(slotNum).m_pTag === s2_req_ptags(missNum)) && !s2_port_hit(missNum) && waitSecondComeIn(missStateQueue(slotNum)) //&& !s2_mmio
}

val miss_0_s2_0 = getMissSituat(slotNum = 0, missNum = 0)
Expand Down Expand Up @@ -581,9 +602,9 @@ class ICacheMainPipe(implicit p: Parameters) extends ICacheModule

/** update replacement status register: 0 is hit access/ 1 is miss access */
(touch_ways zip touch_sets).zipWithIndex.map{ case((t_w,t_s), i) =>
t_s(0) := s1_req_vsetIdx(i)
t_w(0).valid := s1_port_hit(i)
t_w(0).bits := OHToUInt(s1_tag_match_vec(i))
t_s(0) := s2_req_vsetIdx(i)
t_w(0).valid := s2_valid && s2_port_hit(i)
t_w(0).bits := OHToUInt(s2_tag_match_vec(i))

t_s(1) := s2_req_vsetIdx(i)
t_w(1).valid := s2_valid && !s2_port_hit(i)
Expand Down
11 changes: 3 additions & 8 deletions src/main/scala/xiangshan/frontend/icache/IPrefetch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ class PIQReq(implicit p: Parameters) extends IPrefetchBundle {
val paddr = UInt(PAddrBits.W)
}

class IPrefetchPMPBundle(implicit p: Parameters) extends ICacheBundle{
val req = DecoupledIO(new PMPReqBundle())
val resp = Input(new PMPRespBundle())
}


class IPrefetchToMissUnit(implicit p: Parameters) extends IPrefetchBundle{
val enqReq = DecoupledIO(new PIQReq)
Expand All @@ -47,7 +42,7 @@ class IPrefetchToMissUnit(implicit p: Parameters) extends IPrefetchBundle{
class IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle {
val fromFtq = Flipped(new FtqPrefechBundle)
val iTLBInter = new BlockTlbRequestIO
val pmp = new IPrefetchPMPBundle
val pmp = new ICachePMPBundle
val toIMeta = Decoupled(new ICacheReadBundle)
val fromIMeta = Input(new ICacheMetaRespBundle)
val toMissUnit = new IPrefetchToMissUnit
Expand Down Expand Up @@ -151,7 +146,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule

/** Prefetch Stage 2: filtered req PIQ enqueue */
val p2_valid = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B)
val p2_pmp_fire = p2_valid && io.pmp.req.ready
val p2_pmp_fire = p2_valid
val pmpExcpAF = fromPMP.instr

val p2_paddr = RegEnable(next = tlb_resp_paddr, enable = p1_fire)
Expand All @@ -169,7 +164,7 @@ class IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule

p2_ready := p2_fire || p2_discard || !p2_valid
p2_fire := p2_valid && !p2_exception && p3_ready && p2_pmp_fire
p2_discard := p2_valid && ((p2_exception && p2_pmp_fire) || !io.pmp.req.ready)
p2_discard := p2_valid && (p2_exception && p2_pmp_fire)

/** Prefetch Stage 2: filtered req PIQ enqueue */
val p3_valid = generatePipeControl(lastFire = p2_fire, thisFire = p3_fire || p3_discard, thisFlush = false.B, lastFlush = false.B)
Expand Down

0 comments on commit 61e1db3

Please sign in to comment.