提交 d5ccdcaa 编写于 作者: L linjiawei

Merge 'dev-soc-tlb' into 'soc-diplomacy-tlb'

mkdir -p build
for t in $(ls tests);
do
echo ${t%.c}
make ARCH=riscv64-noop ALL=${t%.c} V=OFF 2>&1 run | tee > build/${t%.c}.log
cat build/${t%.c}.log | grep "HIT GOOD TRAP"
done
\ No newline at end of file
......@@ -5,9 +5,10 @@ package bus.axi4
import chisel3._
import chisel3.util._
import noop.HasNOOPParameter
// import noop.HasNOOPParameter
import xiangshan.HasXSParameter
object AXI4Parameters extends HasNOOPParameter {
object AXI4Parameters extends HasXSParameter {
// These are all fixed by the AXI4 standard:
val lenBits = 8
val sizeBits = 3
......
......@@ -39,7 +39,6 @@ class MMIOTLToAXI4(params: TLParameters) extends XSModule
assert(innerBeatSize == outerBeatSize)
val axi4_size = log2Up(outerBeatBytes).U
val s_idle :: s_wait_awready :: s_mem_write :: s_wait_bresp :: s_wait_arready :: s_mem_read :: s_send_resp :: Nil = Enum(7)
val state = RegInit(s_idle)
......
......@@ -100,6 +100,8 @@ sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheMod
val out = Decoupled(new Stage1IO)
val metaReadBus = CacheMetaArrayReadBus()
val dataReadBus = CacheDataArrayReadBus()
val s2s3Empty = Input(Bool()) // FIXME: remove me when do not use nut's cache
})
if (ro) when (io.in.fire()) { assert(!io.in.bits.isWrite()) }
......@@ -117,8 +119,8 @@ sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheMod
io.dataReadBus.apply(valid = readBusValid, setIdx = getDataIdx(io.in.bits.addr))
io.out.bits.req := io.in.bits
io.out.valid := io.in.valid && io.metaReadBus.req.ready && io.dataReadBus.req.ready
io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready
io.out.valid := io.in.valid && io.metaReadBus.req.ready && io.dataReadBus.req.ready && io.s2s3Empty // FIXME: remove me when do not use nut's cache
io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready && io.s2s3Empty // FIXME: remove me when do not use nut's cache
Debug() {
if (debug) {
......@@ -181,7 +183,7 @@ sealed class CacheStage2(implicit val cacheConfig: CacheConfig) extends CacheMod
io.out.bits.hit := io.in.valid && hitVec.orR
io.out.bits.waymask := waymask
io.out.bits.datas := io.dataReadResp
io.out.bits.mmio := xiangshan.AddressSpace.isMMIO(req.addr)
io.out.bits.mmio := xiangshan.AddressSpace.isMMIO(ZeroExt(req.addr, 40)) // FIXME: isMMIO should have PAddrBits Length ??
val isForwardData = io.in.valid && (io.dataWriteBus.req match { case r =>
r.valid && r.bits.setIdx === getDataIdx(req.addr)
......@@ -484,6 +486,7 @@ class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule {
io.out.mem <> s3.io.mem
io.mmio <> s3.io.mmio
io.empty := !s2.io.in.valid && !s3.io.in.valid
s1.io.s2s3Empty := io.empty // FIXME: remove me when do not use nut's cache
io.in.resp.valid := Mux(s3.io.out.valid && s3.io.out.bits.isPrefetch(), false.B, s3.io.out.valid || s3.io.dataReadRespToL1)
......@@ -527,7 +530,7 @@ class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule {
when (s1.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S1]: ${s1.io.in.bits}\n") }
when (s2.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S2]: ${s2.io.in.bits.req}\n") }
when (s3.io.in.valid) { printf("%d ", GTimer()) ; printf(p"[${cacheName}.S3]: ${s3.io.in.bits.req}\n") }
//s3.io.mem.dump(cacheName + ".mem")
// s3.io.mem.dump(cacheName + ".mem")
}}
}
}
......
......@@ -226,3 +226,35 @@ class FrontendToBackendIO extends XSBundle {
val outOfOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
val inOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
}
class TlbCsrBundle extends XSBundle {
val satp = new Bundle {
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
}
val priv = new Bundle {
val mxr = Bool()
val sum = Bool()
val imode = UInt(2.W)
val dmode = UInt(2.W)
}
override def toPrintable: Printable = {
p"Satp mode:0x${Hexadecimal(satp.mode)} asid:0x${Hexadecimal(satp.asid)} ppn:0x${Hexadecimal(satp.ppn)} " +
p"Priv mxr:${priv.mxr} sum:${priv.sum} imode:${priv.imode} dmode:${priv.dmode}"
}
}
class SfenceBundle extends XSBundle {
val valid = Bool()
val bits = new Bundle {
val rs1 = Bool()
val rs2 = Bool()
val addr = UInt(VAddrBits.W)
}
override def toPrintable: Printable = {
p"valid:0x${Hexadecimal(valid)} rs1:${bits.rs1} rs2:${bits.rs2} addr:${Hexadecimal(bits.addr)}"
}
}
\ No newline at end of file
......@@ -9,7 +9,7 @@ import xiangshan.backend.dispatch.DispatchParameters
import xiangshan.backend.exu.ExuParameters
import xiangshan.frontend._
import xiangshan.mem._
import xiangshan.cache.{DCache, DCacheParameters, ICacheParameters, Uncache}
import xiangshan.cache.{DCache, DCacheParameters, ICacheParameters, PTW, Uncache}
import chipsalliance.rocketchip.config
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
import freechips.rocketchip.tilelink.{TLBundleParameters, TLClientNode, TLIdentityNode}
......@@ -26,7 +26,7 @@ case class XSCoreParameters
EnableStoreQueue: Boolean = true,
AddrBits: Int = 64,
VAddrBits: Int = 39,
PAddrBits: Int = 32,
PAddrBits: Int = 40,
HasFPU: Boolean = true,
FectchWidth: Int = 8,
EnableBPU: Boolean = true,
......@@ -80,7 +80,11 @@ case class XSCoreParameters
LoadPipelineWidth: Int = 2,
StorePipelineWidth: Int = 2,
StoreBufferSize: Int = 16,
RefillSize: Int = 512
RefillSize: Int = 512,
TlbEntrySize: Int = 32,
TlbL2EntrySize: Int = 256, // or 512
PtwL1EntrySize: Int = 16,
PtwL2EntrySize: Int = 256
)
trait HasXSParameter {
......@@ -148,6 +152,11 @@ trait HasXSParameter {
val StorePipelineWidth = core.StorePipelineWidth
val StoreBufferSize = core.StoreBufferSize
val RefillSize = core.RefillSize
val DTLBWidth = core.LoadPipelineWidth + core.StorePipelineWidth
val TlbEntrySize = core.TlbEntrySize
val TlbL2EntrySize = core.TlbL2EntrySize
val PtwL1EntrySize = core.PtwL1EntrySize
val PtwL2EntrySize = core.PtwL2EntrySize
val l1BusDataWidth = 64
......@@ -225,17 +234,21 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer) with HasXSParameter
val dcache = outer.dcache.module
val uncache = outer.uncache.module
val ptw = Module(new PTW)
// TODO: connect this
dcache.io.lsu.misc <> DontCare
front.io.backend <> backend.io.frontend
mem.io.backend <> backend.io.mem
ptw.io.tlb(0) <> mem.io.ptw
ptw.io.tlb(1) <> DontCare
ptw.io.mem <> DontCare
dcache.io.lsu.load <> mem.io.loadUnitToDcacheVec
dcache.io.lsu.lsroq <> mem.io.miscToDcache
dcache.io.lsu.store <> mem.io.sbufferToDcache
uncache.io.lsroq <> mem.io.uncache
backend.io.memMMU.imem <> DontCare
backend.io.memMMU.dmem <> DontCare
}
......@@ -24,8 +24,6 @@ import utils.ParallelOR
class Backend extends XSModule
with NeedImpl {
val io = IO(new Bundle {
// val dmem = new SimpleBusUC(addrBits = VAddrBits)
val memMMU = Flipped(new MemMMUIO)
val frontend = Flipped(new FrontendToBackendIO)
val mem = Flipped(new MemToBackendIO)
})
......
......@@ -131,13 +131,13 @@ class Decoder extends XSModule with HasInstrType {
io.out.ctrl.src1Type := Mux(instr(6,0) === "b0110111".U || instr(15, 13) === "b011".U && instr(1, 0) === "b01".U, SrcType.reg, src1Type)
io.out.ctrl.src2Type := src2Type
val vmEnable = WireInit(false.B)
BoringUtils.addSink(vmEnable, "DTLBENABLE")
// val vmEnable = WireInit(false.B)
// BoringUtils.addSink(vmEnable, "DTLBENABLE")
io.out.cf.exceptionVec.map(_ := false.B)
io.out.cf.exceptionVec(illegalInstr) := instrType === InstrN
io.out.cf.exceptionVec(instrPageFault) := io.in.exceptionVec(instrPageFault)
io.out.cf.exceptionVec(instrAccessFault) := io.in.pc(VAddrBits - 1, PAddrBits).orR && !vmEnable
// io.out.cf.exceptionVec(instrAccessFault) := io.in.pc(VAddrBits - 1, PAddrBits).orR && !vmEnable // NOTE: PAddrBits is larger than VAddrBits, so comment it
io.out.ctrl.isXSTrap := (instr === XSTrap.TRAP)
when(io.out.ctrl.isXSTrap){
......
......@@ -21,8 +21,6 @@ class JmpExeUnit extends Exu(Exu.jmpExeUnitCfg) {
csr.io.fpu_csr := DontCare
csr.io.exception <> io.exception
csr.io.instrValid := DontCare
csr.io.imemMMU := DontCare
csr.io.dmemMMU := DontCare
csr.io.out.ready := io.out.ready
csr.io.in.bits.src3 := DontCare
val csrOut = csr.access(
......
......@@ -171,8 +171,6 @@ class CSRIO extends FunctionUnitIO {
val instrValid = Input(Bool())
// for differential testing
// val intrNO = Output(UInt(XLEN.W))
val imemMMU = Flipped(new MMUIO)
val dmemMMU = Flipped(new MMUIO)
val wenFix = Output(Bool())
}
......@@ -209,7 +207,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
val pad0 = Output(UInt(9.W))
val tsr = Output(UInt(1.W))
val tw = Output(UInt(1.W))
val tvm = Output(UInt(1.W))
val tvm = Output(UInt(1.W)) // TODO: add excp check
val mxr = Output(UInt(1.W))
val sum = Output(UInt(1.W))
val mprv = Output(UInt(1.W))
......@@ -268,7 +266,7 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// | pad0 |
// | tsr |
// | tw |
// | tvm |
// | tvm | // TODO: add excp check 3.1.6.4
// | mxr |
// | sum |
// | mprv |
......@@ -315,15 +313,22 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// val sie = RegInit(0.U(XLEN.W))
val sieMask = "h222".U & mideleg
val sipMask = "h222".U & mideleg
//val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U)
val satp = RegInit(UInt(XLEN.W), 0.U)
val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U) // only use for tlb naive debug
// val satp = RegInit(UInt(XLEN.W), 0.U)
val sepc = RegInit(UInt(XLEN.W), 0.U)
val scause = RegInit(UInt(XLEN.W), 0.U)
val stval = Reg(UInt(XLEN.W))
val sscratch = RegInit(UInt(XLEN.W), 0.U)
val scounteren = RegInit(UInt(XLEN.W), 0.U)
// FIXME
// ExcitingUtils.addSource(satp, "CSRSATP")
val tlbBundle = Wire(new TlbCsrBundle)
val sfence = Wire(new SfenceBundle)
tlbBundle.satp.mode := satp(63, 60)
tlbBundle.satp.asid := satp(59, 44)
tlbBundle.satp.ppn := satp(43, 0)
sfence := 0.U.asTypeOf(new SfenceBundle)
BoringUtils.addSource(tlbBundle, "TLBCSRIO")
BoringUtils.addSource(sfence, "SfenceBundle") // FIXME: move to MOU
// User-Level CSRs
val uepc = Reg(UInt(XLEN.W))
......@@ -546,16 +551,14 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
// assert(!hasStorePageFault)
//TODO: Havn't test if io.dmemMMU.priviledgeMode is correct yet
io.imemMMU.priviledgeMode := priviledgeMode
io.dmemMMU.priviledgeMode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
io.imemMMU.status_sum := mstatusStruct.sum.asBool
io.dmemMMU.status_sum := mstatusStruct.sum.asBool
io.imemMMU.status_mxr := DontCare
io.dmemMMU.status_mxr := mstatusStruct.mxr.asBool
tlbBundle.priv.mxr := mstatusStruct.mxr.asBool
tlbBundle.priv.sum := mstatusStruct.sum.asBool
tlbBundle.priv.imode := priviledgeMode
tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
val hasInstrPageFault = io.exception.bits.cf.exceptionVec(instrPageFault) && io.exception.valid
val hasLoadPageFault = io.dmemMMU.loadPF
val hasStorePageFault = io.dmemMMU.storePF
val hasLoadPageFault = false.B // FIXME: add ld-pf/st-pf
val hasStorePageFault = false.B
val hasStoreAddrMisaligned = io.exception.bits.cf.exceptionVec(storeAddrMisaligned)
val hasLoadAddrMisaligned = io.exception.bits.cf.exceptionVec(loadAddrMisaligned)
......@@ -567,7 +570,8 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
SignExt(io.exception.bits.cf.pc + 2.U, XLEN),
SignExt(io.exception.bits.cf.pc, XLEN)
),
SignExt(io.dmemMMU.addr, XLEN)
// SignExt(io.dmemMMU.addr, XLEN)
"hffffffff".U // FIXME: add ld/st pf
)
when(priviledgeMode === ModeM){
mtval := tval
......@@ -767,7 +771,18 @@ class CSR extends FunctionUnit(csrCfg) with HasCSRConst{
"RoqWaitFp" -> (0xb11, "perfCntCondRoqWaitFp" ),
"RoqWaitLoad" -> (0xb12, "perfCntCondRoqWaitLoad" ),
"RoqWaitStore"-> (0xb13, "perfCntCondRoqWaitStore"),
"Dp1Empty" -> (0xb14, "perfCntCondDp1Empty" )
"Dp1Empty" -> (0xb14, "perfCntCondDp1Empty" ),
"DTlbReqCnt0" -> (0xb15, "perfCntDtlbReqCnt0" ),
"DTlbReqCnt1" -> (0xb16, "perfCntDtlbReqCnt1" ),
"DTlbReqCnt2" -> (0xb17, "perfCntDtlbReqCnt2" ),
"DTlbReqCnt3" -> (0xb18, "perfCntDtlbReqCnt3" ),
"DTlbMissCnt0"-> (0xb19, "perfCntDtlbMissCnt0" ),
"DTlbMissCnt1"-> (0xb20, "perfCntDtlbMissCnt1" ),
"DTlbMissCnt2"-> (0xb21, "perfCntDtlbMissCnt2" ),
"DTlbMissCnt3"-> (0xb22, "perfCntDtlbMissCnt3" ),
"PtwReqCnt" -> (0xb23, "perfCntPtwReqCnt" ),
"PtwCycleCnt" -> (0xb24, "perfCntPtwCycleCnt" ),
"PtwL2TlbHit" -> (0xb25, "perfCntPtwL2TlbHit" )
// "Custom1" -> (0xb1b, "Custom1" ),
// "Custom2" -> (0xb1c, "Custom2" ),
// "Custom3" -> (0xb1d, "Custom3" ),
......
......@@ -341,7 +341,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
assert(!(miscReq.fire() && miscReq.bits.meta.tlb_miss),
"TLB missed requests should not go to cache")
assert(!io.lsu.misc.s1_kill, "Lsroq should never use s1 kill on misc")
assert(!io.ptw.s1_kill, "Lsroq should never use s1 kill on misc")
assert(!io.ptw.s1_kill, "Lsroq should never use s1 kill on misc") // TODO: ptw wanna use s1_kill
//----------------------------------------
......
......@@ -4,38 +4,362 @@ import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
import bus.simplebus._
import xiangshan.backend.fu.HasCSRConst
import chisel3.ExcitingUtils._
class DtlbReq extends XSBundle {
trait HasTlbConst extends HasXSParameter {
val Level = 3
val offLen = 12
val ppnLen = PAddrBits - offLen
val vpnnLen = 9
val vpnLen = VAddrBits - offLen
val flagLen = 8
val pteResLen = XLEN - ppnLen - 2 - flagLen
val asidLen = 16
def vaBundle = new Bundle {
val vpn = UInt(vpnLen.W)
val off = UInt(offLen.W)
}
def pteBundle = new Bundle {
val reserved = UInt(pteResLen.W)
val ppn = UInt(ppnLen.W)
val rsw = UInt(2.W)
val perm = new Bundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
val v = Bool()
}
}
}
abstract class TlbBundle extends XSBundle with HasTlbConst
abstract class TlbModule extends XSModule with HasTlbConst
class PermBundle(val hasV: Boolean = true) extends TlbBundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
if (hasV) { val v = Bool() }
override def toPrintable: Printable = {
p"d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"// +
//(if(hasV) (p"v:${v}") else p"")
}
}
class TlbEntry extends TlbBundle {
val vpn = UInt(vpnLen.W) // tag is vpn
val ppn = UInt(ppnLen.W)
val level = UInt(log2Up(Level).W) // 0 for 4KB, 1 for 2MB, 2 for 1GB
// val asid = UInt(asidLen.W), asid maybe expensive to support, but useless
// val v = Bool() // v&g is special, may need sperate storage?
val perm = new PermBundle(hasV = false)
def vpnHit(vpn: UInt):Bool = {
val fullMask = VecInit((Seq.fill(vpnLen)(true.B))).asUInt
val maskLevel = VecInit((Level-1 to 0 by -1).map{i => // NOTE: level 2 for 4KB, 1 for 2MB, 0 for 1GB
VecInit(Seq.fill(vpnLen-i*vpnnLen)(true.B) ++ Seq.fill(i*vpnnLen)(false.B)).asUInt})
val mask = maskLevel(level)
(mask&this.vpn) === (mask&vpn)
}
// def asidHit(asid: UInt) = {
// this.asid === asid
// }
def hit(vpn: UInt/*, asid: UInt*/):Bool = {
vpnHit(vpn)// && asidHit(asid)
}
def genTlbEntry(pte: UInt, level: UInt, vpn: UInt/*, asid: UInt*/) = {
val e = Wire(new TlbEntry)
e.ppn := pte.asTypeOf(pteBundle).ppn
e.level := level
e.vpn := vpn
e.perm := pte.asTypeOf(pteBundle).perm
// e.asid := asid
e
}
override def toPrintable: Printable = {
p"vpn:0x${Hexadecimal(vpn)} ppn:0x${Hexadecimal(ppn)} level:${level} perm:${perm}"
}
}
object TlbCmd {
def read = "b00".U
def write = "b01".U
def exec = "b10".U
def apply() = UInt(2.W)
def isRead(a: UInt) = a===read
def isWrite(a: UInt) = a===write
def isExec(a: UInt) = a===exec
}
class TlbReq extends TlbBundle {
val vaddr = UInt(VAddrBits.W)
val idx = UInt(RoqIdxWidth.W)
val cmd = TlbCmd()
val debug = new Bundle {
val pc = UInt(XLEN.W)
val roqIdx = UInt(RoqIdxWidth.W)
val lsroqIdx = UInt(LsroqIdxWidth.W)
}
override def toPrintable: Printable = {
p"vaddr:0x${Hexadecimal(vaddr)} idx:${idx} cmd:${cmd} pc:0x${Hexadecimal(debug.pc)} roqIdx:${debug.roqIdx} lsroqIdx:${debug.lsroqIdx}"
}
}
class DtlbResp extends XSBundle {
class TlbResp extends TlbBundle {
val paddr = UInt(PAddrBits.W)
val miss = Bool()
val excp = new Bundle {
val pf = new Bundle {
val ld = Bool()
val st = Bool()
val instr = Bool()
}
}
override def toPrintable: Printable = {
p"paddr:0x${Hexadecimal(paddr)} miss:${miss} excp.pf: ld:${excp.pf.ld} st:${excp.pf.st} instr:${excp.pf.instr}"
}
}
class TlbRequestIO() extends TlbBundle {
val req = Valid(new TlbReq)
val resp = Flipped(Valid(new TlbResp))
// override def cloneType: this.type = (new TlbRequestIO(Width)).asInstanceOf[this.type]
}
class DtlbToLsuIO extends XSBundle {
val req = Flipped(ValidIO(new DtlbReq))
val resp = ValidIO(new DtlbResp)
class TlbPtwIO extends TlbBundle {
val req = DecoupledIO(new PtwReq)
val resp = Flipped(DecoupledIO(new PtwResp))
}
class DtlbIO extends XSBundle {
val lsu = Vec(LoadPipelineWidth + StorePipelineWidth, new DtlbToLsuIO)
// val l2 = TODO
class TlbIO(Width: Int) extends TlbBundle {
val requestor = Vec(Width, Flipped(new TlbRequestIO))
val ptw = new TlbPtwIO
override def cloneType: this.type = (new TlbIO(Width)).asInstanceOf[this.type]
}
class Dtlb extends XSModule {
val io = IO(new DtlbIO)
// Dtlb has 4 ports: 2 for load, 2 fore store
// fake dtlb
(0 until LoadPipelineWidth + StorePipelineWidth).map(i => {
io.lsu(i).resp.valid := io.lsu(i).req.valid
io.lsu(i).resp.bits.paddr := io.lsu(i).req.bits.vaddr
io.lsu(i).resp.bits.miss := LFSR64()(5, 0) === 0.U
when(io.lsu(i).req.valid){
XSDebug("vaddr %x paddr %x miss %b\n",
io.lsu(i).req.bits.vaddr, io.lsu(i).resp.bits.paddr, io.lsu(i).resp.bits.miss)
class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
val io = IO(new TlbIO(Width))
val req = io.requestor.map(_.req)
val resp = io.requestor.map(_.resp)
val ptw = io.ptw
val sfence = WireInit(0.U.asTypeOf(new SfenceBundle))
val csr = WireInit(0.U.asTypeOf(new TlbCsrBundle))
val satp = csr.satp
val priv = csr.priv
val ifecth = if (isDtlb) false.B else true.B
val mode = if (isDtlb) priv.dmode else priv.imode
val vmEnable = satp.mode === 8.U // && (mode < ModeM) // FIXME: fix me when boot xv6/linux...
BoringUtils.addSink(sfence, "SfenceBundle")
BoringUtils.addSink(csr, "TLBCSRIO")
val reqAddr = req.map(_.bits.vaddr.asTypeOf(vaBundle))
val cmd = req.map(_.bits.cmd)
val valid = req.map(_.valid)
def widthMapSeq[T <: Seq[Data]](f: Int => T) = (0 until Width).map(f)
def widthMap[T <: Data](f: Int => T) = (0 until Width).map(f)
val v = RegInit(0.U(TlbEntrySize.W))
val pf = RegInit(0.U(TlbEntrySize.W)) // TODO: when ptw resp a pf(now only page not found), store here
val entry = Reg(Vec(TlbEntrySize, new TlbEntry))
val entryHitVec = widthMapSeq{i => VecInit(entry.map(_.hit(reqAddr(i).vpn/*, satp.asid*/))) }
val hitVec = widthMapSeq{ i => (v.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } }
val pfHitVec = widthMapSeq{ i => (pf.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } }
val pfArray = widthMap{ i => ParallelOR(pfHitVec(i)).asBool && valid(i) && vmEnable }
val hit = widthMap{ i => ParallelOR(hitVec(i)).asBool && valid(i) && vmEnable && ~pfArray(i) }
val miss = widthMap{ i => !hit(i) && valid(i) && vmEnable && ~pfArray(i) }
val hitppn = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.ppn)) }
val hitPerm = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.perm)) }
val multiHit = {
val hitSum = widthMap{ i => PopCount(hitVec(i)) }
val pfHitSum = widthMap{ i => PopCount(pfHitVec(i)) }
ParallelOR(widthMap{ i => !(hitSum(i)===0.U || hitSum(i)===1.U) || !(pfHitSum(i)===0.U || pfHitSum(i)===1.U)})
}
// resp // TODO: A/D has not being concerned
for(i <- 0 until Width) {
resp(i).valid := valid(i)
resp(i).bits.paddr := Mux(vmEnable, Cat(hitppn(i), reqAddr(i).off), SignExt(req(i).bits.vaddr, PAddrBits))
resp(i).bits.miss := miss(i)
val perm = hitPerm(i) // NOTE: given the excp, the out module choose one to use?
val update = false.B && hit(i) && (!hitPerm(i).a || !hitPerm(i).d && TlbCmd.isWrite(cmd(i))) // update A/D through exception
val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth))
val ldPf = (pfArray(i) && TlbCmd.isRead(cmd(i)) && true.B /*!isAMO*/) || hit(i) && !(modeCheck && (perm.r || priv.mxr && perm.x)) && (TlbCmd.isRead(cmd(i)) && true.B/*!isAMO*/) // TODO: handle isAMO
val stPf = (pfArray(i) && TlbCmd.isWrite(cmd(i)) || false.B /*isAMO*/ ) || hit(i) && !(modeCheck && perm.w) && (TlbCmd.isWrite(cmd(i)) || false.B/*TODO isAMO. */)
val instrPf = (pfArray(i) && TlbCmd.isExec(cmd(i))) || hit(i) && !(modeCheck && perm.x) && TlbCmd.isExec(cmd(i))
resp(i).bits.excp.pf.ld := ldPf || update
resp(i).bits.excp.pf.st := stPf || update
resp(i).bits.excp.pf.instr := instrPf || update
}
// ptw
val state_idle :: state_wait :: Nil = Enum(2)
val state = RegInit(state_idle)
ptw <> DontCare // TODO: need check it
ptw.req.valid := ParallelOR(miss).asBool && state===state_idle
ptw.resp.ready := state===state_wait
class comBundle extends TlbBundle with HasRoqIdx{
val valid = Bool()
val bits = new PtwReq
def isPrior(that: comBundle): Bool = {
(this.valid && !that.valid) || (this.valid && that.valid && (that isAfter this))
}
}
object Compare {
def apply[T<:Data](xs: Seq[comBundle]): comBundle = {
ParallelOperation(xs, (a: comBundle, b: comBundle) => Mux(a isPrior b, a, b))
}
}
// val ptwReqSeq = Wire(Seq.fill(Width)(new comBundle()))
val ptwReqSeq = Seq.fill(Width)(Wire(new comBundle()))
for (i <- 0 until Width) {
ptwReqSeq(i).valid := valid(i) && miss(i)
ptwReqSeq(i).roqIdx := req(i).bits.idx
ptwReqSeq(i).bits.vpn := reqAddr(i).vpn
ptwReqSeq(i).bits.idx := req(i).bits.idx
}
ptw.req.bits := Compare(ptwReqSeq).bits
switch (state) {
is (state_idle) {
when (ParallelOR(miss).asBool) {
state := state_wait
}
assert(!ptw.resp.valid)
}
is (state_wait) {
when (ptw.resp.fire()) {
state := state_idle
}
}
})
}
// reset pf when pf hit
val pfHitReset = WireInit(0.U(TlbEntrySize.W))
when (ParallelOR(pfArray).asBool /* or ParallelOR(valid)*/) {
val pfHitAndValid = widthMap{i => Mux(valid(i), VecInit(pfHitVec(i)).asUInt, 0.U) }
pfHitReset := ParallelOR(pfHitAndValid)
}
// refill
val refill = ptw.resp.fire()
val randIdx = LFSR64()(log2Up(TlbEntrySize)-1,0)
val priorIdx = PriorityEncoder(~v)
val antiPriorIdx = (TlbEntrySize-1).U - PriorityEncoder(Reverse(~(v|pf))) // or just (TlbEntrySize-1).U
val refillIdx = Mux(ParallelAND((v|pf).asBools), randIdx, Mux(ptw.resp.bits.pf, antiPriorIdx, priorIdx))
val pfRefill = WireInit(0.U(TlbEntrySize.W))
when (refill) {
v := Mux(ptw.resp.bits.pf, v & ~UIntToOH(refillIdx), v | UIntToOH(refillIdx))
pfRefill := Mux(ptw.resp.bits.pf, UIntToOH(refillIdx), 0.U)
entry(refillIdx) := ptw.resp.bits.entry
XSDebug(p"Refill: idx:${refillIdx} entry:${ptw.resp.bits.entry}\n")
}
// pf update
when (refill || ParallelOR(pfArray).asBool /* or ParallelOR(valid)*/) {
pf := (pf & ~pfHitReset) | pfRefill
}
// sfence (flush)
when (sfence.valid) {
when (sfence.bits.rs1) { // virtual address *.rs1 <- (rs1===0.U)
when (sfence.bits.rs2) { // asid, but i do not want to support asid, *.rs2 <- (rs2===0.U)
v := 0.U // all should be flush
pf := 0.U
}.otherwise { // all pte but only spec asid
v := v & ~VecInit(entry.map(e => /*e.asid === sfence.bits.asid && */!e.perm.g)).asUInt
pf := pf & ~VecInit(entry.map(e => /*e.asid === sfence.bits.asid && */!e.perm.g)).asUInt
}
}.otherwise { // virtual rs1=/=0.U
when (sfence.bits.rs2) { // asid
v := v & ~VecInit(entry.map(_.vpn === sfence.bits.addr.asTypeOf(vaBundle).vpn)).asUInt
pf := pf & ~VecInit(entry.map(_.vpn === sfence.bits.addr.asTypeOf(vaBundle).vpn)).asUInt
}.otherwise { // particular va and asid
v := v & ~VecInit(entry.map(e => e.vpn === sfence.bits.addr.asTypeOf(vaBundle).vpn && (/*e.asid === sfence.bits.asid && */!e.perm.g))).asUInt
pf := pf & ~VecInit(entry.map(e => e.vpn === sfence.bits.addr.asTypeOf(vaBundle).vpn && (/*e.asid === sfence.bits.asid && */!e.perm.g))).asUInt
}
}
}
if (!env.FPGAPlatform) {
ExcitingUtils.addSource(valid(0)/* && vmEnable*/, "perfCntDtlbReqCnt0", Perf)
ExcitingUtils.addSource(valid(1)/* && vmEnable*/, "perfCntDtlbReqCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/, "perfCntDtlbReqCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/, "perfCntDtlbReqCnt3", Perf)
ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && miss(0), "perfCntDtlbMissCnt0", Perf)
ExcitingUtils.addSource(valid(1)/* && vmEnable*/ && miss(1), "perfCntDtlbMissCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/ && miss(2), "perfCntDtlbMissCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/ && miss(3), "perfCntDtlbMissCnt3", Perf)
}
// Log
for(i <- 0 until Width) {
XSDebug(req(i).valid, p"req(${i.U}): ${req(i).bits}\n")
XSDebug(resp(i).valid, p"resp(${i.U}): ${resp(i).bits}\n")
}
XSDebug(sfence.valid, p"Sfence: ${sfence}\n")
XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n")
XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hit).asUInt)} miss:${Binary(VecInit(miss).asUInt)} v:${Hexadecimal(v)} pf:${Hexadecimal(pf)} state:${state}\n")
XSDebug(ptw.req.fire(), p"PTW req:${ptw.req.bits}\n")
XSDebug(ptw.resp.valid, p"PTW resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n")
// assert check, can be remove when tlb can work
for(i <- 0 until Width) {
assert((hit(i)&pfArray(i))===false.B, "hit(%d):%d pfArray(%d):%d v:0x%x pf:0x%x", i.U, hit(i), i.U, pfArray(i), v, pf)
}
for(i <- 0 until Width) {
XSDebug(multiHit, p"vpn:0x${Hexadecimal(reqAddr(i).vpn)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)} pfHitVec:0x${Hexadecimal(VecInit(pfHitVec(i)).asUInt)}\n")
}
for(i <- 0 until TlbEntrySize) {
XSDebug(multiHit, p"entry(${i.U}): v:${v(i)} ${entry(i)}\n")
}
assert(!multiHit) // add multiHit here, later it should be removed (maybe), turn to miss and flush
for (i <- 0 until Width) {
XSDebug(resp(i).valid && hit(i) && !(req(i).bits.vaddr===resp(i).bits.paddr), p"vaddr:0x${Hexadecimal(req(i).bits.vaddr)} paddr:0x${Hexadecimal(resp(i).bits.paddr)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)}}\n")
when (resp(i).valid && hit(i) && !(req(i).bits.vaddr===resp(i).bits.paddr)) {
for (j <- 0 until TlbEntrySize) {
XSDebug(true.B, p"TLBEntry(${j.U}): v:${v(j)} ${entry(j)}\n")
}
} // FIXME: remove me when tlb may be ok
when(resp(i).valid && hit(i)) {
assert(req(i).bits.vaddr===resp(i).bits.paddr, "vaddr:0x%x paddr:0x%x hitVec:%x ", req(i).bits.vaddr, resp(i).bits.paddr, VecInit(hitVec(i)).asUInt)
} // FIXME: remove me when tlb may be ok
}
assert((v&pf)===0.U, "v and pf can't be true at same time: v:0x%x pf:0x%x", v, pf)
}
package xiangshan.cache
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
import chisel3.ExcitingUtils._
trait HasPtwConst extends HasTlbConst with MemoryOpConstants{
val PtwWidth = 2
}
abstract class PtwBundle extends XSBundle with HasPtwConst
abstract class PtwModule extends XSModule with HasPtwConst
class PteBundle extends PtwBundle{
val reserved = UInt(pteResLen.W)
val ppn = UInt(ppnLen.W)
val rsw = UInt(2.W)
val perm = new Bundle {
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
val v = Bool()
}
def isPf() = {
!perm.v || (!perm.r && perm.w)
}
def isLeaf() = {
!isPf() && (perm.r || perm.x)
}
override def toPrintable: Printable = {
p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}"
}
}
class PtwEntry(tagLen: Int) extends PtwBundle {
val tag = UInt(tagLen.W)
val ppn = UInt(ppnLen.W)
val perm = new PermBundle
// TODO: add superpage
def hit(addr: UInt) = {
require(addr.getWidth >= PAddrBits)
tag === addr(PAddrBits-1, PAddrBits-tagLen)
}
def refill(addr: UInt, pte: UInt) {
tag := addr(PAddrBits-1, PAddrBits-tagLen)
ppn := pte.asTypeOf(pteBundle).ppn
perm := pte.asTypeOf(pteBundle).perm
}
def genPtwEntry(addr: UInt, pte: UInt) = {
val e = Wire(new PtwEntry(tagLen))
e.tag := addr(PAddrBits-1, PAddrBits-tagLen)
e.ppn := pte.asTypeOf(pteBundle).ppn
e.perm := pte.asTypeOf(pteBundle).perm
e
}
override def cloneType: this.type = (new PtwEntry(tagLen)).asInstanceOf[this.type]
override def toPrintable: Printable = {
p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}"
}
}
class PtwReq extends PtwBundle {
val vpn = UInt(vpnLen.W)
val idx = UInt(RoqIdxWidth.W) // itlb could ignore it
override def toPrintable: Printable = {
p"vpn:0x${Hexadecimal(vpn)} idx:${idx}"
}
}
class PtwResp extends PtwBundle {
val entry = new TlbEntry
val idx = UInt(RoqIdxWidth.W)
val pf = Bool() // simple pf no matter cmd
override def toPrintable: Printable = {
p"entry:${entry} idx:${idx} pf:${pf}"
}
}
class PtwIO extends PtwBundle {
val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO))
//val mem = new SimpleBusUC(addrBits = PAddrBits) // Use Dcache temp
val mem = new DCacheLoadIO
}
object ValidHold {
def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = {
val valid = RegInit(false.B)
when (outfire) { valid := false.B }
when (infire) { valid := true.B }
when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok?
valid
}
}
object OneCycleValid {
def apply(fire: Bool, flush: Bool = false.B) = {
val valid = RegInit(false.B)
when (valid) { valid := false.B }
when (fire) { valid := true.B }
when (false.B) { valid := false.B }
valid
}
}
class PTW extends PtwModule {
val io = IO(new PtwIO)
val arb = Module(new Arbiter(new PtwReq, PtwWidth))
arb.io.in <> VecInit(io.tlb.map(_.req))
val arbChosen = RegEnable(arb.io.chosen, arb.io.out.fire())
val req = RegEnable(arb.io.out.bits, arb.io.out.fire())
val resp = VecInit(io.tlb.map(_.resp))
val valid = ValidHold(arb.io.out.fire(), resp(arbChosen).fire())
val validOneCycle = OneCycleValid(arb.io.out.fire())
arb.io.out.ready := !valid || resp(arbChosen).fire()
val mem = io.mem
val sfence = WireInit(0.U.asTypeOf(new SfenceBundle))
val csr = WireInit(0.U.asTypeOf(new TlbCsrBundle))
val satp = csr.satp
val priv = csr.priv
BoringUtils.addSink(sfence, "SfenceBundle")
BoringUtils.addSink(csr, "TLBCSRIO")
val memRdata = mem.resp.bits.data
val memPte = memRdata.asTypeOf(new PteBundle)
// two level: l2-tlb-cache && pde/pte-cache
// l2-tlb-cache is ram-larger-edition tlb
// pde/pte-cache is cache of page-table, speeding up ptw
// may seperate valid bits to speed up sfence's flush
// Reg/Mem/SyncReadMem is not sure now
val tagLen1 = PAddrBits - log2Up(XLEN/8)
val tagLen2 = PAddrBits - log2Up(XLEN/8) - log2Up(PtwL2EntrySize)
val tlbl2 = SyncReadMem(TlbL2EntrySize, new TlbEntry)
val tlbv = RegInit(0.U(TlbL2EntrySize.W))
val ptwl1 = Reg(Vec(PtwL1EntrySize, new PtwEntry(tagLen = tagLen1)))
val l1v = RegInit(0.U(PtwL1EntrySize.W))
val ptwl2 = SyncReadMem(PtwL2EntrySize, new PtwEntry(tagLen = tagLen2)) // NOTE: the Mem could be only single port(r&w)
val l2v = RegInit(0.U(PtwL2EntrySize.W))
// fsm
val state_idle :: state_req :: state_wait_resp :: state_wait_ready :: Nil = Enum(4)
val state = RegInit(state_idle)
val level = RegInit(0.U(2.W)) // 0/1/2
val latch = Reg(new PtwResp)
/*
* tlbl2
*/
val (tlbHit, tlbHitData) = {
// tlbl2 is by addr
// TODO: optimize tlbl2'l2 tag len
val ramData = tlbl2.read(req.vpn(log2Up(TlbL2EntrySize)-1, 0), validOneCycle)
val vidx = RegEnable(tlbv(req.vpn(log2Up(TlbL2EntrySize)-1, 0)), validOneCycle)
(ramData.hit(req.vpn) && vidx, ramData) // TODO: optimize tag
// TODO: add exception and refill
}
def MakeAddr(ppn: UInt, off: UInt) = {
require(off.getWidth == 9)
Cat(ppn, off, 0.U(log2Up(XLEN/8).W))(PAddrBits-1, 0)
}
def getVpnn(vpn: UInt, idx: Int) = {
vpn(vpnnLen*(idx+1)-1, vpnnLen*idx)
}
/*
* ptwl1
*/
val l1addr = MakeAddr(satp.ppn, getVpnn(req.vpn, 2))
val (l1Hit, l1HitData) = { // TODO: add excp
// 16 terms may casue long latency, so divide it into 2 stage, like l2tlb
val hitVecT = ptwl1.zipWithIndex.map{case (a,b) => a.hit(l1addr) && l1v(b) }
val hitVec = hitVecT.map(RegEnable(_, validOneCycle)) // TODO: could have useless init value
val hitData = ParallelMux(hitVec zip ptwl1)
val hit = ParallelOR(hitVec).asBool
(hit, hitData)
}
/*
* ptwl2
*/
val l1MemBack = mem.resp.fire() && state===state_wait_resp && level===0.U
val l1Res = Mux(l1Hit, l1HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
val l2addr = MakeAddr(l1Res, getVpnn(req.vpn, 1))
val (l2Hit, l2HitData) = { // TODO: add excp
val readRam = (l1Hit && level===0.U && state===state_req) || (mem.resp.fire() && state===state_wait_resp && level===0.U)
val ridx = l2addr(log2Up(PtwL2EntrySize)-1+log2Up(XLEN/8), log2Up(XLEN/8))
val ramData = ptwl2.read(ridx, readRam)
val vidx = RegEnable(l2v(ridx), readRam)
(ramData.hit(l2addr), ramData) // TODO: optimize tag
}
/* ptwl3
* ptwl3 has not cache
* ptwl3 may be functional conflict with l2-tlb
* if l2-tlb does not hit, ptwl3 would not hit (mostly)
*/
val l2MemBack = mem.resp.fire() && state===state_wait_resp && level===1.U
val l2Res = Mux(l2Hit, l2HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
val l3addr = MakeAddr(l2Res, getVpnn(req.vpn, 0))
/*
* fsm
*/
assert(!(level===3.U))
assert(!(tlbHit && (mem.req.valid || state===state_wait_resp))) // when tlb hit, should not req/resp.valid
switch (state) {
is (state_idle) {
when (valid) {
state := state_req
level := 0.U
}
}
is (state_req) {
when (tlbHit) {
when (resp(arbChosen).ready) {
state := state_idle
}.otherwise {
state := state_wait_ready
}
}.elsewhen (l1Hit && level===0.U || l2Hit && level===1.U) {
level := level + 1.U // TODO: consider superpage
}.elsewhen (mem.req.ready) {
state := state_wait_resp
assert(!(level === 3.U)) // NOTE: pte is not found after 3 layers(software system is wrong)
}
}
is (state_wait_resp) {
when (mem.resp.fire()) {
when (memPte.isLeaf() || memPte.isPf()) {
when (resp(arbChosen).ready) {
state := state_idle
}.otherwise {
state := state_wait_ready
latch.entry := new TlbEntry().genTlbEntry(memRdata, level, req.vpn)
latch.pf := memPte.isPf()
}
}.otherwise {
state := state_req
level := level + 1.U
}
}
}
is (state_wait_ready) {
when (resp(arbChosen).ready) {
state := state_idle
}
}
}
/*
* mem
*/
mem.req.valid := state === state_req &&
((level===0.U && !tlbHit && !l1Hit) ||
(level===1.U && !l2Hit) ||
(level===2.U))
mem.req.bits.cmd := M_XRD
mem.req.bits.addr := Mux(level===0.U, l1addr/*when l1Hit, DontCare, when l1miss, l1addr*/,
Mux(level===1.U, Mux(l2Hit, l3addr, l2addr)/*when l2Hit, l3addr, when l2miss, l2addr*/,
l3addr))
mem.req.bits.data := DontCare
mem.req.bits.mask := VecInit(Fill(mem.req.bits.mask.getWidth, true.B)).asUInt
mem.req.bits.meta := DontCare // TODO: check it
mem.resp.ready := true.B // TODO: mem.resp.ready := state===state_wait_resp
assert(!mem.resp.valid || state===state_wait_resp, "mem.resp.valid:%d state:%d", mem.resp.valid, state)
mem.s1_kill := false.B // NOTE: shoud not use it. for ptw will change to TL later
/*
* resp
*/
val ptwFinish = (state===state_req && tlbHit && level===0.U) || ((memPte.isLeaf() || memPte.isPf()) && mem.resp.fire()) || state===state_wait_ready
for(i <- 0 until PtwWidth) {
resp(i).valid := valid && arbChosen===i.U && ptwFinish // TODO: add resp valid logic
resp(i).bits.entry := Mux(tlbHit, tlbHitData,
Mux(state===state_wait_ready, latch.entry, new TlbEntry().genTlbEntry(memRdata, level, req.vpn)))
resp(i).bits.idx := req.idx
resp(i).bits.pf := Mux(tlbHit, false.B, Mux(state===state_wait_ready, latch.pf, memPte.isPf()))
// TODO: the pf must not be correct, check it
}
/* sfence
* for ram is syncReadMem, so could not flush conditionally
* l3 may be conflict with l2tlb??, may be we could combine l2-tlb with l3-ptw
*/
when (sfence.valid) {
tlbv := 0.U
l1v := 0.U
l2v := 0.U
}
/*
* refill
*/
assert(!mem.resp.fire() || state===state_wait_resp)
when (mem.resp.fire() && !memPte.isPf()) {
when (state===state_wait_resp && level===0.U && !memPte.isPf) {
val refillIdx = LFSR64()(log2Up(PtwL1EntrySize)-1,0) // TODO: may be LRU
ptwl1(refillIdx).refill(l1addr, memRdata)
l1v := l1v | UIntToOH(refillIdx)
}
when (state===state_wait_resp && level===1.U && !memPte.isPf) {
val l2addrStore = RegEnable(l2addr, mem.req.fire() && state===state_req && level===1.U)
val refillIdx = getVpnn(req.vpn, 1)(log2Up(PtwL2EntrySize)-1, 0)
ptwl2.write(refillIdx, new PtwEntry(tagLen2).genPtwEntry(l2addrStore, memRdata))
l2v := l2v | UIntToOH(refillIdx)
}
when (state===state_wait_resp && memPte.isLeaf() && !memPte.isPf) {
val refillIdx = getVpnn(req.vpn, 0)(log2Up(TlbL2EntrySize)-1, 0)
tlbl2.write(refillIdx, new TlbEntry().genTlbEntry(memRdata, level, req.vpn))
tlbv := tlbv | UIntToOH(refillIdx)
}
}
if (!env.FPGAPlatform) {
ExcitingUtils.addSource(validOneCycle, "perfCntPtwReqCnt", Perf)
ExcitingUtils.addSource(valid, "perfCntPtwCycleCnt", Perf)
ExcitingUtils.addSource(valid && tlbHit && state===state_req && level===0.U, "perfCntPtwL2TlbHit", Perf)
}
def PrintFlag(en: Bool, flag: Bool, nameEnable: String, nameDisable: String): Unit = {
when(flag) {
XSDebug(false, en, nameEnable)
}.otherwise {
XSDebug(false, en, nameDisable)
}
}
XSDebug(validOneCycle, "**New Ptw Req from ")
PrintFlag(validOneCycle, arbChosen===0.U, "DTLB**:", "ITLB**:")
XSDebug(false, validOneCycle, p"(v:${validOneCycle} r:${arb.io.out.ready}) vpn:0x${Hexadecimal(req.vpn)} (roq)idx:${req.idx}\n")
XSDebug(resp(arbChosen).fire(), "**Ptw Resp to ")
PrintFlag(resp(arbChosen).fire(), arbChosen===0.U, "DTLB**:\n", "ITLB**\n")
XSDebug(resp(arbChosen).fire(), p"(v:${resp(arbChosen).valid} r:${resp(arbChosen).ready}) entry:${resp(arbChosen).bits.entry} (roq)idx:${resp(arbChosen).bits.idx} pf:${resp(arbChosen).bits.pf}\n")
XSDebug(sfence.valid, p"Sfence: sfence instr here ${sfence.bits}\n")
XSDebug(valid, p"CSR: ${csr}\n")
XSDebug(valid, p"vpn2:0x${Hexadecimal(getVpnn(req.vpn, 2))} vpn1:0x${Hexadecimal(getVpnn(req.vpn, 1))} vpn0:0x${Hexadecimal(getVpnn(req.vpn, 0))}\n")
XSDebug(valid, p"state:${state} level:${level} tlbHit:${tlbHit} l1addr:0x${Hexadecimal(l1addr)} l1Hit:${l1Hit} l2addr:0x${Hexadecimal(l2addr)} l2Hit:${l2Hit} l3addr:0x${Hexadecimal(l3addr)} memReq(v:${mem.req.valid} r:${mem.req.ready})\n")
XSDebug(mem.req.fire(), p"mem req fire addr:0x${Hexadecimal(mem.req.bits.addr)}\n")
XSDebug(mem.resp.fire(), p"mem resp fire rdata:0x${Hexadecimal(mem.resp.bits.data)} Pte:${memPte}\n")
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, TlbCmd, MemoryOpConstants}
class LoadToLsroqIO extends XSBundle {
val loadIn = ValidIO(new LsPipelineBundle)
......@@ -19,7 +19,7 @@ class LoadUnit extends XSModule {
val redirect = Flipped(ValidIO(new Redirect))
val tlbFeedback = ValidIO(new TlbFeedback)
val dcache = new DCacheLoadIO
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO()
val sbuffer = new LoadForwardQueryIO
val lsroq = new LoadToLsroqIO
})
......@@ -61,6 +61,11 @@ class LoadUnit extends XSModule {
// send req to dtlb
io.dtlb.req.valid := l2_out.valid
io.dtlb.req.bits.vaddr := l2_out.bits.vaddr
io.dtlb.req.bits.idx := l2_out.bits.uop.roqIdx
io.dtlb.req.bits.cmd := TlbCmd.read
io.dtlb.req.bits.debug.pc := l2_out.bits.uop.cf.pc
io.dtlb.req.bits.debug.roqIdx := l2_out.bits.uop.roqIdx
io.dtlb.req.bits.debug.lsroqIdx := l2_out.bits.uop.lsroqIdx
l2_dtlb_hit := io.dtlb.resp.valid && !io.dtlb.resp.bits.miss
l2_dtlb_miss := io.dtlb.resp.valid && io.dtlb.resp.bits.miss
......
......@@ -5,7 +5,7 @@ import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, MemoryOpConstants}
class LsRoqEntry extends XSBundle {
val paddr = UInt(PAddrBits.W)
......
......@@ -118,18 +118,18 @@ class Memend extends XSModule {
val miscToDcache = new DCacheLoadIO
val sbufferToDcache = new DCacheStoreIO
val uncache = new DCacheLoadIO
val ptw = new TlbPtwIO
})
val loadUnits = (0 until exuParameters.LduCnt).map(_ => Module(new LoadUnit))
val storeUnits = (0 until exuParameters.StuCnt).map(_ => Module(new StoreUnit))
val miscUnit = Module(new MiscUnit)
// val mshq = Module(new MSHQ)
val dtlb = Module(new Dtlb) //TODO: move dtlb out
val dtlb = Module(new TLB(Width = DTLBWidth, isDtlb = true))
val lsroq = Module(new Lsroq)
val sbuffer = Module(new FakeSbuffer)
dtlb.io := DontCare
val loadUnitToDcacheVec = Wire(Vec(exuParameters.LduCnt, new DCacheLoadIO))
val sbufferToDcache = Wire(new DCacheStoreIO)
......@@ -147,6 +147,8 @@ class Memend extends XSModule {
io.sbufferToDcache <> sbufferToDcache
io.uncache <> lsroqToUncache
io.ptw <> dtlb.io.ptw
// LoadUnit
for (i <- 0 until exuParameters.LduCnt) {
loadUnits(i).io.ldin <> io.backend.ldin(i)
......@@ -154,7 +156,7 @@ class Memend extends XSModule {
loadUnits(i).io.redirect <> io.backend.redirect
loadUnits(i).io.tlbFeedback <> io.backend.tlbFeedback(i)
loadUnits(i).io.dcache <> loadUnitToDcacheVec(i)
loadUnits(i).io.dtlb <> dtlb.io.lsu(i)
loadUnits(i).io.dtlb <> dtlb.io.requestor(i)
loadUnits(i).io.sbuffer <> sbuffer.io.forward(i)
lsroq.io.loadIn(i) <> loadUnits(i).io.lsroq.loadIn
......@@ -167,7 +169,7 @@ class Memend extends XSModule {
storeUnits(i).io.stin <> io.backend.stin(i)
storeUnits(i).io.redirect <> io.backend.redirect
storeUnits(i).io.tlbFeedback <> io.backend.tlbFeedback(exuParameters.LduCnt + i)
storeUnits(i).io.dtlb <> dtlb.io.lsu(exuParameters.LduCnt + i)
storeUnits(i).io.dtlb <> dtlb.io.requestor(exuParameters.LduCnt + i) // FIXME
storeUnits(i).io.lsroq <> lsroq.io.storeIn(i)
}
......@@ -193,7 +195,7 @@ class Memend extends XSModule {
miscUnit.io.in.valid := io.backend.ldin(0).valid && io.backend.ldin(0).bits.uop.ctrl.fuType === FuType.mou ||
io.backend.ldin(1).valid && io.backend.ldin(1).bits.uop.ctrl.fuType === FuType.mou
when(miscUnit.io.dtlb.req.valid){
dtlb.io.lsu(0) <> miscUnit.io.dtlb
dtlb.io.requestor(0) <> miscUnit.io.dtlb // TODO: check it later
}
miscUnit.io.dcache <> miscUnitToDcache
......
......@@ -4,14 +4,14 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.{DCacheLoadIO, DtlbToLsuIO, MemoryOpConstants}
import xiangshan.cache.{DCacheLoadIO, TlbRequestIO, TlbCmd, MemoryOpConstants}
class MiscUnit extends XSModule with MemoryOpConstants{
val io = IO(new Bundle() {
val in = Flipped(Decoupled(new ExuInput))
val out = Decoupled(new ExuOutput)
val dcache = new DCacheLoadIO
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO
})
//-------------------------------------------------------
......@@ -23,7 +23,7 @@ class MiscUnit extends XSModule with MemoryOpConstants{
switch (state) {
is (s_tlb) {
when(io.in.valid && io.dtlb.resp.valid){
when(io.in.valid && io.dtlb.resp.valid && !io.dtlb.resp.bits.miss){
state := s_cache_req
}
}
......@@ -42,8 +42,14 @@ class MiscUnit extends XSModule with MemoryOpConstants{
// TLB
// send req to dtlb
// keep firing until tlb hit
io.dtlb.req.valid := io.in.valid && state === s_tlb
io.dtlb.req.valid := io.in.valid && state === s_tlb
io.dtlb.req.bits.vaddr := io.in.bits.src1
io.dtlb.req.bits.idx := io.in.bits.uop.roqIdx
io.dtlb.req.bits.cmd := Mux(io.in.bits.uop.ctrl.fuOpType === LSUOpType.lr, TlbCmd.read, TlbCmd.write)
io.dtlb.req.bits.debug.pc := io.in.bits.uop.cf.pc
io.dtlb.req.bits.debug.roqIdx := io.in.bits.uop.roqIdx
io.dtlb.req.bits.debug.lsroqIdx := io.in.bits.uop.lsroqIdx
// TODO: add excp logic of dtlb.resp.bits.excp.pf
// record paddr
val paddr = RegEnable(io.dtlb.resp.bits.paddr, io.in.fire())
......
......@@ -4,14 +4,14 @@ import chisel3._
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.cache.DtlbToLsuIO
import xiangshan.cache.{TlbRequestIO, TlbCmd}
class StoreUnit extends XSModule {
val io = IO(new Bundle() {
val stin = Flipped(Decoupled(new ExuInput))
val redirect = Flipped(ValidIO(new Redirect))
val tlbFeedback = ValidIO(new TlbFeedback)
val dtlb = Flipped(new DtlbToLsuIO)
val dtlb = new TlbRequestIO()
val lsroq = ValidIO(new LsPipelineBundle)
})
......@@ -55,6 +55,11 @@ class StoreUnit extends XSModule {
io.dtlb.req.bits.vaddr := saddr
io.dtlb.req.valid := io.stin.valid
io.dtlb.req.bits.idx := io.stin.bits.uop.roqIdx
io.dtlb.req.bits.cmd := TlbCmd.write
io.dtlb.req.bits.debug.pc := io.stin.bits.uop.cf.pc
io.dtlb.req.bits.debug.roqIdx := io.stin.bits.uop.roqIdx
io.dtlb.req.bits.debug.lsroqIdx := io.stin.bits.uop.lsroqIdx
s2_out.bits := DontCare
s2_out.bits.vaddr := saddr
......
......@@ -27,16 +27,36 @@ void addpageSv39() {
#define PTEADDR(i) (0x88000000 - (PAGESIZE * PTENUM) + (PAGESIZE * i)) //0x88000000 - 0x100*64
#define PTEMMIONUM 128
#define PDEMMIONUM 1
#define PTEDEVNUM 128
#define PDEDEVNUM 1
uint64_t pdde[ENTRYNUM];
uint64_t pde[ENTRYNUM];
uint64_t pte[PTENUM][ENTRYNUM];
//special addr for mmio 0x40000000 - 0x4fffffff
// special addr for mmio 0x40000000 - 0x4fffffff
uint64_t pdemmio[ENTRYNUM];
uint64_t ptemmio[PTEMMIONUM][ENTRYNUM];
pdde[1] = (((PDDEADDR-PAGESIZE*1) & 0xfffff000) >> 2) | 0x1;
// special addr for internal devices 0x30000000-0x3fffffff
uint64_t pdedev[ENTRYNUM];
uint64_t ptedev[PTEDEVNUM][ENTRYNUM];
// dev: 0x30000000-0x3fffffff
pdde[0] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)) & 0xfffff000) >> 2) | 0x1;
for (int i = 0; i < PTEDEVNUM; i++) {
pdedev[ENTRYNUM-PTEDEVNUM+i] = (((PDDEADDR-PAGESIZE*(PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM-i)) & 0xfffff000) >> 2) | 0x1;
}
for(int outidx = 0; outidx < PTEDEVNUM; outidx++) {
for(int inidx = 0; inidx < ENTRYNUM; inidx++) {
ptedev[outidx][inidx] = (((0x30000000 + outidx*PTEVOLUME + inidx*PAGESIZE) & 0xfffff000) >> 2) | 0xf;
}
}
// mmio: 0x40000000 - 0x4fffffff
pdde[1] = (((PDDEADDR-PAGESIZE*PDEMMIONUM) & 0xfffff000) >> 2) | 0x1;
for(int i = 0; i < PTEMMIONUM; i++) {
pdemmio[i] = (((PDDEADDR-PAGESIZE*(PTEMMIONUM+PDEMMIONUM-i)) & 0xfffff000) >> 2) | 0x1;
......@@ -63,6 +83,8 @@ void addpageSv39() {
}
}
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM+PTEDEVNUM)),ptedev,PAGESIZE*PTEDEVNUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM+PDEDEVNUM)),pdedev,PAGESIZE*PDEDEVNUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM+PTEMMIONUM)),ptemmio, PAGESIZE*PTEMMIONUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM+PDEMMIONUM)), pdemmio, PAGESIZE*PDEMMIONUM);
memcpy((char *)ram+(RAMSIZE-PAGESIZE*(PTENUM+PDDENUM+PDENUM)), pdde, PAGESIZE*PDDENUM);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册