From c4448af10792392bf065a2df3e2f06e7f2e2bfad Mon Sep 17 00:00:00 2001 From: good-circle Date: Thu, 17 Sep 2026 23:04:59 +0800 Subject: [PATCH 1/2] TLB: apply in-order A/D page-fault checks to the OoO path The OoO TLB ignored A/D on hit and PTW, so a missing A (or a store with missing D) translated successfully. Mirror EmbeddedTLB: raise a page fault unless FPGAPlatform, which keeps the hardware A/D update path. --- src/main/scala/nutcore/mem/TLB.scala | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/scala/nutcore/mem/TLB.scala b/src/main/scala/nutcore/mem/TLB.scala index 2e61cf85..9b55a9a8 100644 --- a/src/main/scala/nutcore/mem/TLB.scala +++ b/src/main/scala/nutcore/mem/TLB.scala @@ -417,9 +417,10 @@ sealed class TLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ // hit permission check val hitCheck = hit /*&& hitFlag.v */&& !(pf.privilegeMode === ModeU && !hitFlag.u) && !(pf.privilegeMode === ModeS && hitFlag.u && (!pf.status_sum || ifecth)) - val hitExec = hitCheck && hitFlag.x - val hitLoad = hitCheck && (hitFlag.r || pf.status_mxr && hitFlag.x) - val hitStore = hitCheck && hitFlag.w + val hitADCheck = if (Settings.get("FPGAPlatform")) false.B else !hitFlag.a || !hitFlag.d && req.isWrite() + val hitExec = hitCheck && !hitADCheck && hitFlag.x + val hitLoad = hitCheck && !hitADCheck && (hitFlag.r || pf.status_mxr && hitFlag.x) + val hitStore = hitCheck && !hitADCheck && hitFlag.w io.pf.loadPF := loadPF //RegNext(loadPF, init =false.B) io.pf.storePF := storePF //RegNext(storePF, init = false.B) @@ -506,9 +507,10 @@ sealed class TLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ } }.elsewhen (level =/= 0.U) { //TODO: fix needFlush val permCheck = missflag.v && !(pf.privilegeMode === ModeU && !missflag.u) && !(pf.privilegeMode === ModeS && missflag.u && (!pf.status_sum || ifecth)) - val permExec = permCheck && missflag.x - val permLoad = permCheck && (missflag.r || pf.status_mxr && missflag.x) - val permStore = permCheck && missflag.w + val permAD = if (Settings.get("FPGAPlatform")) false.B else !missflag.a || (!missflag.d && req.isWrite()) + val permExec = permCheck && !permAD && missflag.x + val permLoad = permCheck && !permAD && (missflag.r || pf.status_mxr && missflag.x) + val permStore = permCheck && !permAD && missflag.w val updateAD = if (Settings.get("FPGAPlatform")) !missflag.a || (!missflag.d && req.isWrite()) else false.B val updateData = Cat( 0.U(56.W), req.isWrite(), 1.U(1.W), 0.U(6.W) ) missRefillFlag := Cat(req.isWrite(), 1.U(1.W), 0.U(6.W)) | missflag.asUInt From de8d2fdd290b1d8e1c8cd974cc2a2c2f057ff948 Mon Sep 17 00:00:00 2001 From: Haoyuan Feng Date: Sun, 20 Sep 2026 10:23:06 +0800 Subject: [PATCH 2/2] TLB: gate hardware A/D updates behind EnableUpdateAD (#280) Default off, so missing A or (store and missing D) raises a page fault on both TLB paths. Set EnableUpdateAD to restore PTE write-back. Independent of FPGAPlatform. --- src/main/scala/nutcore/mem/EmbeddedTLB.scala | 9 +++++---- src/main/scala/nutcore/mem/TLB.scala | 9 +++++---- src/main/scala/top/Settings.scala | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/scala/nutcore/mem/EmbeddedTLB.scala b/src/main/scala/nutcore/mem/EmbeddedTLB.scala index dc05012f..7842a1ad 100644 --- a/src/main/scala/nutcore/mem/EmbeddedTLB.scala +++ b/src/main/scala/nutcore/mem/EmbeddedTLB.scala @@ -223,13 +223,14 @@ class EmbeddedTLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ val hitMask = hitMeta.mask // hit write back pte.flag val hitinstrPF = WireInit(false.B) - val hitWB = hit && (!hitFlag.a || !hitFlag.d && req.isWrite()) && !hitinstrPF && !(loadPF || storePF || io.pf.isPF()) + val enableUpdateAD = Settings.get("EnableUpdateAD") + val hitWB = if (enableUpdateAD) hit && (!hitFlag.a || !hitFlag.d && req.isWrite()) && !hitinstrPF && !(loadPF || storePF || io.pf.isPF()) else false.B val hitRefillFlag = Cat(req.isWrite().asUInt, 1.U(1.W), 0.U(6.W)) | hitFlag.asUInt val hitWBStore = RegEnable(Cat(0.U(10.W), hitData.ppn, 0.U(2.W), hitRefillFlag), hitWB) // hit permission check val hitCheck = hit /*&& hitFlag.v */&& !(pf.privilegeMode === ModeU && !hitFlag.u) && !(pf.privilegeMode === ModeS && hitFlag.u && (!pf.status_sum || ifecth)) - val hitADCheck = if (Settings.get("FPGAPlatform")) false.B else !hitFlag.a || !hitFlag.d && req.isWrite() + val hitADCheck = if (enableUpdateAD) false.B else !hitFlag.a || !hitFlag.d && req.isWrite() val hitExec = hitCheck && !hitADCheck && hitFlag.x val hitLoad = hitCheck && !hitADCheck && (hitFlag.r || pf.status_mxr && hitFlag.x) val hitStore = hitCheck && !hitADCheck && hitFlag.w @@ -318,11 +319,11 @@ class EmbeddedTLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ } }.elsewhen (level =/= 0.U) { //TODO: fix needFlush val permCheck = missflag.v && !(pf.privilegeMode === ModeU && !missflag.u) && !(pf.privilegeMode === ModeS && missflag.u && (!pf.status_sum || ifecth)) - val permAD = if (Settings.get("FPGAPlatform")) false.B else !missflag.a || (!missflag.d && req.isWrite()) + val permAD = if (enableUpdateAD) false.B else !missflag.a || (!missflag.d && req.isWrite()) val permExec = permCheck && !permAD && missflag.x val permLoad = permCheck && !permAD && (missflag.r || pf.status_mxr && missflag.x) val permStore = permCheck && !permAD && missflag.w - val updateAD = if (Settings.get("FPGAPlatform")) !missflag.a || (!missflag.d && req.isWrite()) else false.B + val updateAD = if (enableUpdateAD) !missflag.a || (!missflag.d && req.isWrite()) else false.B val updateData = Cat( 0.U(56.W), req.isWrite(), 1.U(1.W), 0.U(6.W) ) missRefillFlag := Cat(req.isWrite(), 1.U(1.W), 0.U(6.W)) | missflag.asUInt memRespStore := io.mem.resp.bits.rdata | updateData diff --git a/src/main/scala/nutcore/mem/TLB.scala b/src/main/scala/nutcore/mem/TLB.scala index 9b55a9a8..bd593c02 100644 --- a/src/main/scala/nutcore/mem/TLB.scala +++ b/src/main/scala/nutcore/mem/TLB.scala @@ -411,13 +411,14 @@ sealed class TLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ val hitMask = hitMeta.mask // hit write back pte.flag val hitinstrPF = WireInit(false.B) - val hitWB = hit && (!hitFlag.a || !hitFlag.d && req.isWrite()) && !hitinstrPF && !(loadPF || storePF || io.pf.isPF()) + val enableUpdateAD = Settings.get("EnableUpdateAD") + val hitWB = if (enableUpdateAD) hit && (!hitFlag.a || !hitFlag.d && req.isWrite()) && !hitinstrPF && !(loadPF || storePF || io.pf.isPF()) else false.B val hitRefillFlag = Cat(req.isWrite().asUInt, 1.U(1.W), 0.U(6.W)) | hitFlag.asUInt val hitWBStore = RegEnable(Cat(0.U(10.W), hitData.ppn, 0.U(2.W), hitRefillFlag), hitWB) // hit permission check val hitCheck = hit /*&& hitFlag.v */&& !(pf.privilegeMode === ModeU && !hitFlag.u) && !(pf.privilegeMode === ModeS && hitFlag.u && (!pf.status_sum || ifecth)) - val hitADCheck = if (Settings.get("FPGAPlatform")) false.B else !hitFlag.a || !hitFlag.d && req.isWrite() + val hitADCheck = if (enableUpdateAD) false.B else !hitFlag.a || !hitFlag.d && req.isWrite() val hitExec = hitCheck && !hitADCheck && hitFlag.x val hitLoad = hitCheck && !hitADCheck && (hitFlag.r || pf.status_mxr && hitFlag.x) val hitStore = hitCheck && !hitADCheck && hitFlag.w @@ -507,11 +508,11 @@ sealed class TLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{ } }.elsewhen (level =/= 0.U) { //TODO: fix needFlush val permCheck = missflag.v && !(pf.privilegeMode === ModeU && !missflag.u) && !(pf.privilegeMode === ModeS && missflag.u && (!pf.status_sum || ifecth)) - val permAD = if (Settings.get("FPGAPlatform")) false.B else !missflag.a || (!missflag.d && req.isWrite()) + val permAD = if (enableUpdateAD) false.B else !missflag.a || (!missflag.d && req.isWrite()) val permExec = permCheck && !permAD && missflag.x val permLoad = permCheck && !permAD && (missflag.r || pf.status_mxr && missflag.x) val permStore = permCheck && !permAD && missflag.w - val updateAD = if (Settings.get("FPGAPlatform")) !missflag.a || (!missflag.d && req.isWrite()) else false.B + val updateAD = if (enableUpdateAD) !missflag.a || (!missflag.d && req.isWrite()) else false.B val updateData = Cat( 0.U(56.W), req.isWrite(), 1.U(1.W), 0.U(6.W) ) missRefillFlag := Cat(req.isWrite(), 1.U(1.W), 0.U(6.W)) | missflag.asUInt memRespStore := io.mem.resp.bits.rdata | updateData diff --git a/src/main/scala/top/Settings.scala b/src/main/scala/top/Settings.scala index 0777da5d..3b08726e 100644 --- a/src/main/scala/top/Settings.scala +++ b/src/main/scala/top/Settings.scala @@ -37,6 +37,7 @@ object DefaultSettings { "IsRV32" -> false, "FPGAPlatform" -> false, + "EnableUpdateAD" -> false, "EnableILA" -> true, "EnableDebug" -> false, "EnableRVC" -> true