Skip to content

Commit

Permalink
l1tlb: tlb's req port can be configured to be block or non-blocked (O…
Browse files Browse the repository at this point in the history
…penXiangShan#1656)

each tlb's port can be configured to be block or non-blocked.
For blocked port, there will be a req miss slot stored in tlb, but belong to
core pipeline, which means only core pipeline flush will invalid them.

For another, itlb also use PTW Filter but with only 4 entries.
Last, keep svinval extension as usual, still work.


* tlb: add blocked-tlb support, miss frontend changes

* tlb: remove tlb's sameCycle support, result will return at next cycle

* tlb: remove param ShouldBlock, move block method into TLB module

* tlb: fix handle_block's miss_req logic

* mmu.filter: change filter's req.ready to canEnqueue

when filter can't let all the req enqueue, set the req.ready to false.
canEnqueue after filtering has long latency, so we use **_fake
without filtering, but the filter will still receive the reqs if
it can(after filtering).

* mmu.tlb: change name from BTlbPtwIO to VectorTlbPtwIO

* mmu: replace itlb's repeater to filter&repeaternb

* mmu.tlb: add TlbStorageWrapper to make TLB cleaner

more: BlockTlbRequestorIO is same with TlbRequestorIO, rm it

* mmu.tlb: rm unused param in function r_req_apply, fix syntax bug

* [WIP]icache: itlb usage from non-blocked to blocked

* mmu.tlb: change parameter NBWidth to Seq of boolean

* icache.mainpipe: fix itlb's resp.ready, not always true

* mmu.tlb: add kill sigal to blocked req that needs sync but fail

in frontend, icache,itlb,next pipe may not able to sync.
blocked tlb will store miss req ang blocks req, which makes itlb
couldn't work. So add kill logic to let itlb not to store reqs.

One more thing: fix icache's blocked tlb handling logic

* icache.mainpipe: fix tlb's ready_recv logic

icache mainpipe has two ports, but these two ports may not valid
all the same time. So add new signals tlb_need_recv to record whether
stage s1 should wait for the tlb.

* tlb: when flush, just set resp.valid and pf, pf for don't use it

* tlb: flush should concern satp.changed(for blocked io now)

* mmu.tlb: add new flush that doesn't flush reqs

Sfence.vma will flush inflight reqs and flushPipe
But some other sfence(svinval...) will not. So add new flush to
distinguish these two kinds of sfence signal

morw: forget to assign resp result when ptw back, fix it

* mmu.tlb: beautify miss_req_v and miss_v relative logic

* mmu.tlb: fix bug, when ptw back and bypass, concern level to genPPN

bug: when ptw back and bypass, forgot to concern level(1GB/2MB/4KB)
when genPPN.

by the way: some funtions need ": Unit = ", add it.

* mmu.filter: fix bug of canEnqueue, mixed with tlb_req and tlb.req

* icache.mainpipe: fix bug of tlbExcp's usage, & with tlb_need_back

Icache's mainpipe has two ports, but may only port 0 is valid.
When a port is invalid, the tlbexcp should be false.(Actually, should
be ignored).
So & tlb_need_back to fix this bug.

* sfence: instr in svinval ext will also flush pipe

A difficult problem to handle:
Sfence and Svinval will flush MMU, but only Sfence(some svinval)
  will flush pipe. For itlb that some requestors are blocked and
  icache doesn't recv flush for simplicity, itlb's blocked ptw req
  should not be flushed.
It's a huge problem for MMU to handle for good or bad solutions. But
  svinval is seldom used, so disable it's effiency.

* mmu: add parameter to control mmu's sfence delay latency

Difficult problem:
  itlb's blocked req should not be abandoned, but sfence will flush
  all infight reqs. when itlb and itlb repeater's delay is not same(itlb
  is flushed, two cycles later, itlb repeater is flushed, then itlb's
  ptw req after flushing will be also flushed sliently.
So add one parameter to control the flush delay to be the same.

* mmu.tlb: fix bug of csr.priv's delay & sfence valid when req fire

1. csr.priv's delay
csr.priv should not be delayed, csr.satp should be delayed.
for excep/intr will change csr.priv, which will be changed at one
instruction's (commit?). but csrrw satp will not, so satp has more
cycles to delay.
2. sfence
when sfence valid but blocked req fire, resp should still fire.
3. satp in TlbCsrBundle
let high bits of satp.ppn to be 0.U

* tlb&icache.mainpipe: rm commented codes

* mmu: move method genPPN to entry bundle

* l1tlb: divide l1tlb flush into flush_mmu and flush_pipe

Problem:
For l1tlb, there are blocked and non-blocked req ports.
For blocked ports, there are req slots to store missed reqs.
Some mmu flush like Sfence should not flush miss slots for outside
may still need get tlb resp, no matter wrong and correct resp.
For example. sfence will flush mmu and flush pipe, but won't flush
reqs inside icache, which waiting for tlb resp.
For example, svinval instr will flush mmu, but not flush pipe. so
tlb should return correct resp, althrough the ptw req is flushed
when tlb miss.

Solution:
divide l1tlb flush into flush_mmu and flush_pipe.
The req slot is considered to be a part of core pipeline and should
only be flushed by flush_pipe.
flush_mmu will flush mmu entries and inflight ptw reqs.
When miss but sfence flushed its ptw req, re-send.

* l1tlb: code clean, correct comments and rm unused codes

* l2tlb: divide filterSize into ifiterSize and dfilterSize

* l2tlb: prefetch req won't enter miss queue. Rename MSHR to missqueue

* l1tlb: when disable vm, ptw back should not bypass tlb and should let miss req go ahead
  • Loading branch information
Lemover authored Jul 18, 2022
1 parent 7114a23 commit f1fe869
Show file tree
Hide file tree
Showing 24 changed files with 674 additions and 683 deletions.
7 changes: 3 additions & 4 deletions src/main/scala/top/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,11 @@ class MinimalConfig(n: Int = 1) extends Config(
name = "itlb",
fetchi = true,
useDmode = false,
sameCycle = false,
missSameCycle = true,
normalReplacer = Some("plru"),
superReplacer = Some("plru"),
normalNWays = 4,
normalNSets = 1,
superNWays = 2,
shouldBlock = true
superNWays = 2
),
ldtlbParameters = TLBParameters(
name = "ldtlb",
Expand All @@ -131,6 +128,7 @@ class MinimalConfig(n: Int = 1) extends Config(
superNWays = 4,
normalAsVictim = true,
partialStaticPMP = true,
outsideRecvFlush = true,
outReplace = false
),
sttlbParameters = TLBParameters(
Expand All @@ -142,6 +140,7 @@ class MinimalConfig(n: Int = 1) extends Config(
normalAsVictim = true,
superNWays = 4,
partialStaticPMP = true,
outsideRecvFlush = true,
outReplace = false
),
btlbParameters = TLBParameters(
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/utils/Hold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ object ValidHold {
}
}


/*
* Hold the 'fire' for only one cycle unless new fire comes in
*/
Expand Down
40 changes: 20 additions & 20 deletions src/main/scala/xiangshan/Bundle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ class CtrlFlow(implicit p: Parameters) extends XSBundle {
val waitForRobIdx = new RobPtr // store set predicted previous store robIdx
// Load wait is needed
// load inst will not be executed until former store (predicted by mdp) addr calcuated
val loadWaitBit = Bool()
// If (loadWaitBit && loadWaitStrict), strict load wait is needed
val loadWaitBit = Bool()
// If (loadWaitBit && loadWaitStrict), strict load wait is needed
// load inst will not be executed until ALL former store addr calcuated
val loadWaitStrict = Bool()
val loadWaitStrict = Bool()
val ssid = UInt(SSIDWidth.W)
val ftqPtr = new FtqPtr
val ftqOffset = UInt(log2Up(PredictWidth).W)
Expand Down Expand Up @@ -409,28 +409,27 @@ class FrontendToCtrlIO(implicit p: Parameters) extends XSBundle {
val toFtq = Flipped(new CtrlToFtqIO)
}

class SatpStruct extends Bundle {
class SatpStruct(implicit p: Parameters) extends XSBundle {
val mode = UInt(4.W)
val asid = UInt(16.W)
val ppn = UInt(44.W)
}

class TlbCsrBundle(implicit p: Parameters) extends XSBundle {
val satp = new Bundle {
val changed = Bool()
val mode = UInt(4.W) // TODO: may change number to parameter
val asid = UInt(16.W)
val ppn = UInt(44.W) // just use PAddrBits - 3 - vpnnLen

def apply(satp_value: UInt): Unit = {
require(satp_value.getWidth == XLEN)
val sa = satp_value.asTypeOf(new SatpStruct)
mode := sa.mode
asid := sa.asid
ppn := sa.ppn
changed := DataChanged(sa.asid) // when ppn is changed, software need do the flush
}
class TlbSatpBundle(implicit p: Parameters) extends SatpStruct {
val changed = Bool()

def apply(satp_value: UInt): Unit = {
require(satp_value.getWidth == XLEN)
val sa = satp_value.asTypeOf(new SatpStruct)
mode := sa.mode
asid := sa.asid
ppn := Cat(0.U(44-PAddrBits), sa.ppn(PAddrBits-1, 0)).asUInt()
changed := DataChanged(sa.asid) // when ppn is changed, software need do the flush
}
}

class TlbCsrBundle(implicit p: Parameters) extends XSBundle {
val satp = new TlbSatpBundle()
val priv = new Bundle {
val mxr = Bool()
val sum = Bool()
Expand All @@ -451,10 +450,11 @@ class SfenceBundle(implicit p: Parameters) extends XSBundle {
val rs2 = Bool()
val addr = UInt(VAddrBits.W)
val asid = UInt(AsidLength.W)
val flushPipe = Bool()
}

override def toPrintable: Printable = {
p"valid:0x${Hexadecimal(valid)} rs1:${bits.rs1} rs2:${bits.rs2} addr:${Hexadecimal(bits.addr)}"
p"valid:0x${Hexadecimal(valid)} rs1:${bits.rs1} rs2:${bits.rs2} addr:${Hexadecimal(bits.addr)}, flushPipe:${bits.flushPipe}"
}
}

Expand Down
7 changes: 3 additions & 4 deletions src/main/scala/xiangshan/Parameters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,10 @@ case class XSCoreParameters
name = "itlb",
fetchi = true,
useDmode = false,
sameCycle = false,
missSameCycle = true,
normalNWays = 32,
normalReplacer = Some("plru"),
superNWays = 4,
superReplacer = Some("plru"),
shouldBlock = true
superReplacer = Some("plru")
),
ldtlbParameters: TLBParameters = TLBParameters(
name = "ldtlb",
Expand All @@ -191,6 +188,7 @@ case class XSCoreParameters
normalAsVictim = true,
outReplace = false,
partialStaticPMP = true,
outsideRecvFlush = true,
saveLevel = true
),
sttlbParameters: TLBParameters = TLBParameters(
Expand All @@ -203,6 +201,7 @@ case class XSCoreParameters
normalAsVictim = true,
outReplace = false,
partialStaticPMP = true,
outsideRecvFlush = true,
saveLevel = true
),
refillBothTlb: Boolean = false,
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/xiangshan/XSCore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,10 @@ class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer)
memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq
memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType)

val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb)
val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb)
val dtlbRepeater1 = PTWFilter(memBlock.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize)
val dtlbRepeater2 = PTWRepeaterNB(passReady = false, dtlbRepeater1.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb)
val itlbRepeater1 = PTWFilter(itlbParams.fenceDelay,frontend.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.ifilterSize)
val itlbRepeater2 = PTWRepeaterNB(passReady = false, itlbParams.fenceDelay, itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb)
val dtlbRepeater1 = PTWFilter(ldtlbParams.fenceDelay, memBlock.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.dfilterSize)
val dtlbRepeater2 = PTWRepeaterNB(passReady = false, ldtlbParams.fenceDelay, dtlbRepeater1.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb)
ptw.io.sfence <> fenceio.sfence
ptw.io.csr.tlb <> csrioIn.tlb
ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr
Expand Down
9 changes: 5 additions & 4 deletions src/main/scala/xiangshan/backend/MemBlock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import xiangshan.backend.exu.StdExeUnit
import xiangshan.backend.fu._
import xiangshan.backend.rob.RobLsqIO
import xiangshan.cache._
import xiangshan.cache.mmu.{BTlbPtwIO, TLB, TlbReplace}
import xiangshan.cache.mmu.{VectorTlbPtwIO, TLBNonBlock, TlbReplace}
import xiangshan.mem._

class Std(implicit p: Parameters) extends FunctionUnit {
Expand Down Expand Up @@ -75,7 +75,7 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
// misc
val stIn = Vec(exuParameters.StuCnt, ValidIO(new ExuInput))
val memoryViolation = ValidIO(new Redirect)
val ptw = new BTlbPtwIO(exuParameters.LduCnt + exuParameters.StuCnt)
val ptw = new VectorTlbPtwIO(exuParameters.LduCnt + exuParameters.StuCnt)
val sfence = Input(new SfenceBundle)
val tlbCsr = Input(new TlbCsrBundle)
val fenceToSbuffer = Flipped(new FenceToSbuffer)
Expand Down Expand Up @@ -166,18 +166,19 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer)
val sfence = RegNext(RegNext(io.sfence))
val tlbcsr = RegNext(RegNext(io.tlbCsr))
val dtlb_ld = VecInit(Seq.fill(1){
val tlb_ld = Module(new TLB(exuParameters.LduCnt, ldtlbParams))
val tlb_ld = Module(new TLBNonBlock(exuParameters.LduCnt, ldtlbParams))
tlb_ld.io // let the module have name in waveform
})
val dtlb_st = VecInit(Seq.fill(1){
val tlb_st = Module(new TLB(exuParameters.StuCnt, sttlbParams))
val tlb_st = Module(new TLBNonBlock(exuParameters.StuCnt, sttlbParams))
tlb_st.io // let the module have name in waveform
})
val dtlb = dtlb_ld ++ dtlb_st
val dtlb_reqs = dtlb.map(_.requestor).flatten
val dtlb_pmps = dtlb.map(_.pmp).flatten
dtlb.map(_.sfence := sfence)
dtlb.map(_.csr := tlbcsr)
dtlb.map(_.flushPipe.map(a => a := false.B)) // non-block doesn't need
if (refillBothTlb) {
require(ldtlbParams.outReplace == sttlbParams.outReplace)
require(ldtlbParams.outReplace)
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/xiangshan/backend/decode/DecodeUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ object FDivSqrtDecode extends DecodeConstants {
*/
object SvinvalDecode extends DecodeConstants {
val table: Array[(BitPat, List[BitPat])] = Array(
/* sinval_vma is like sfence.vma , but sinval_vma can be dispatched and issued like normal instructions while sfence.vma
/* sinval_vma is like sfence.vma , but sinval_vma can be dispatched and issued like normal instructions while sfence.vma
* must assure it is the ONLY instrucion executing in backend.
*/
SINVAL_VMA ->List(SrcType.reg, SrcType.reg, SrcType.X, FuType.fence, FenceOpType.sfence, N, N, N, N, N, N, SelImm.X),
Expand All @@ -408,17 +408,17 @@ object SvinvalDecode extends DecodeConstants {
/* sfecne.inval.ir is the end instrucion of a TLB flush which set *noSpecExec* *blockBackward* and *flushPipe* signals
* so when it comes to dispatch , it will wait until all sinval_vma ahead of it in rob commit
* then dispatch and issue this instrucion
* when it commit at the head of rob , flush the pipeline since some instrucions have been fetched to ibuffer using old TLB map
* when it commit at the head of rob , flush the pipeline since some instrucions have been fetched to ibuffer using old TLB map
*/
SFENCE_INVAL_IR ->List(SrcType.DC, SrcType.DC, SrcType.X, FuType.fence, FenceOpType.nofence, N, N, N, Y, Y, Y, SelImm.X)
/* what is Svinval extension ?
* -----> sfecne.w.inval
* sfence.vma vpn1 -----> sinval_vma vpn1
* sfence.vma vpn2 -----> sinval_vma vpn2
* -----> sfecne.inval.ir
*
*
* sfence.vma should be executed in-order and it flushes the pipeline after committing
* we can parallel sfence instrucions with this extension
* we can parallel sfence instrucions with this extension
*/
)
}
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/xiangshan/backend/fu/Fence.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Fence(implicit p: Parameters) extends FunctionUnit {
sfence.valid := state === s_tlb && !disableSfence
sfence.bits.rs1 := uop.ctrl.imm(4, 0) === 0.U
sfence.bits.rs2 := uop.ctrl.imm(9, 5) === 0.U
sfence.bits.flushPipe := uop.ctrl.flushPipe
XSError(sfence.valid && uop.ctrl.lsrc(0) =/= uop.ctrl.imm(4, 0), "lsrc0 is passed by imm\n")
XSError(sfence.valid && uop.ctrl.lsrc(1) =/= uop.ctrl.imm(9, 5), "lsrc1 is passed by imm\n")
sfence.bits.addr := RegEnable(io.in.bits.src(0), io.in.fire())
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/xiangshan/cache/mmu/L2TLB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) wi
missQueue.io.in.ready || ptw.io.req.ready))

missQueue.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit &&
!cache.io.resp.bits.toFsm.l2Hit && !ptw.io.req.ready
!cache.io.resp.bits.toFsm.l2Hit && !from_pre(cache.io.resp.bits.req_info.source) && !ptw.io.req.ready
missQueue.io.in.bits := cache.io.resp.bits.req_info
missQueue.io.sfence := sfence
missQueue.io.csr := csr
Expand Down Expand Up @@ -330,7 +330,7 @@ class L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) wi
XSPerfAccumulate("mem_count", mem.a.fire())

// print configs
println(s"${l2tlbParams.name}: a ptw, a llptw with size ${l2tlbParams.llptwsize}, miss queue size ${MSHRSize} l1:${l2tlbParams.l1Size} fa l2: nSets ${l2tlbParams.l2nSets} nWays ${l2tlbParams.l2nWays} l3: ${l2tlbParams.l3nSets} nWays ${l2tlbParams.l3nWays} blockBytes:${l2tlbParams.blockBytes}")
println(s"${l2tlbParams.name}: a ptw, a llptw with size ${l2tlbParams.llptwsize}, miss queue size ${MissQueueSize} l1:${l2tlbParams.l1Size} fa l2: nSets ${l2tlbParams.l2nSets} nWays ${l2tlbParams.l2nWays} l3: ${l2tlbParams.l3nSets} nWays ${l2tlbParams.l3nWays} blockBytes:${l2tlbParams.blockBytes}")

// time out assert
for (i <- 0 until MemReqWidth) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/xiangshan/cache/mmu/L2TLBMissQueue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class L2TlbMQIO(implicit p: Parameters) extends MMUIOBaseBundle with HasPtwConst
}

class L2TlbMissQueue(implicit p: Parameters) extends XSModule with HasPtwConst {
require(MSHRSize >= (2 + l2tlbParams.filterSize))
require(MissQueueSize >= (l2tlbParams.ifilterSize + l2tlbParams.dfilterSize))
val io = IO(new L2TlbMQIO())

io.out <> Queue(io.in, MSHRSize, flush = Some(io.sfence.valid || io.csr.satp.changed))
}
io.out <> Queue(io.in, MissQueueSize, flush = Some(io.sfence.valid || io.csr.satp.changed))
}
Loading

0 comments on commit f1fe869

Please sign in to comment.