From 921e6bd5a19ecd1c14ac1e17d79d1b4b7cf1e2fa Mon Sep 17 00:00:00 2001 From: kenny Date: Sun, 17 Aug 2025 15:58:08 +0800 Subject: [PATCH 1/4] Add DTLB bundle and initial agent interfaces --- .../dtlb/ld_tlb/agent/ld_dtlb_agent.py | 246 ++++++++++++++++++ .../dtlb/ld_tlb/bundle/ld_tlb_bundle.py | 145 +++++++++++ 2 files changed, 391 insertions(+) create mode 100644 ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py create mode 100644 ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py diff --git a/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py b/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py new file mode 100644 index 00000000..76d78112 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py @@ -0,0 +1,246 @@ +from toffee.agent import Agent, driver_method, monitor_method +from toffee import Value +from ld_tlb_bundle import DTLBBundle, RequestorBundle, CSRBundle, PTWBundle, PMPBundle + +class DTLBAgent(Agent): + def __init__(self, dtlb_bundle: DTLBBundle): + super().__init__(dtlb_bundle) + self.requestor = dtlb_bundle.requestor + + @driver_method() + async def drive_request(self, port: int, vaddr: int, cmd: int, hyperinst: bool = False): + """发送请求到指定端口。 + Args: + port: 端口号 (0-3) + vaddr: 虚拟地址 + cmd: 请求命令 + hyperinst: 是否为 hypervisor 指令 + Returns: + int or None: 物理地址 (paddr_0) 如果有效;否则 None(miss 或异常) + """ + if not 0 <= port < 4: + raise ValueError("Port must be 0-3") + + req_bundle = self.requestor[port].req + req_bundle.valid.value = 1 + req_bundle.bits_vaddr.value = vaddr + req_bundle.bits_cmd.value = cmd + req_bundle.bits_hyperinst.value = 1 if hyperinst else 0 + await self.bundle.step() # 启动请求 + req_bundle.valid.value = 0 + resp = self.requestor[port].resp + + await Value(resp.valid, 1) # 等待 resp.valid = 1,无论miss还是hit + + # 检查异常信号(扩展所有相关异常) + has_fault = (resp.bits_excp_0_gpf_ld.value == 1 or + resp.bits_excp_0_pf_ld.value == 1 or + resp.bits_excp_0_af_ld.value == 1) + + if resp.valid.value == 1 and resp.bits_miss.value == 0 and not has_fault: + return resp.bits_paddr_0.value + return None # miss 或异常,检查 monitor_resp + + @monitor_method() + async def monitor_resp(self): + """ + 监测响应。 + """ + for port in range(4): + resp = self.requestor[port].resp + if resp.valid.value == 1: + return { + "port": port, + "miss": resp.bits_miss.value, + "paddr": resp.bits_paddr_0.value, + "fullva": resp.bits_fullva.value, + "pbmt": resp.bits_pbmt_0.value, + "excp_pf_ld": resp.bits_excp_0_pf_ld.value, + "excp_af_ld": resp.bits_excp_0_af_ld.value, + } + return None + + @monitor_method() + async def monitor_multi_port(self): + """ + 监测多端口请求内容。 + """ + for port in range(4): + req = self.requestor[port].req + if req.valid.value == 1: + return { + "port": port, + "vaddr": req.bits_vaddr.value, + "fullva": req.bits_fullva.value, + "checkfullva": req.bits_checkfullva.value, + "cmd": req.bits_cmd.value, + "hyperinst": req.bits_hyperinst.value, + "hlvx": req.bits_hlvx.value, + "kill": req.bits_kill.value, + "isPrefetch": req.bits_isPrefetch.value, + "no_translate": req.bits_no_translate.value, + "pmp_addr": req.bits_pmp_addr.value, + "debug_robIdx_flag": req.bits_debug_robIdx_flag.value, + "debug_robIdx_value": req.bits_debug_robIdx_value.value, + "debug_isFirstIssue": req.bits_debug_isFirstIssue.value + } + return None + +class CSRAgent(Agent): + def __init__(self, csr_bundle: CSRBundle): + super().__init__(csr_bundle) + + @driver_method() + async def drive_virt_config(self, virt: bool, satp_mode: int, vsatp_mode: int, hgatp_mode: int): + """配置虚拟化模式。 + Args: + virt: 是否启用虚拟化 + satp_mode: SATP 模式 + vsatp_mode: VSATP 模式 + hgatp_mode: HGATP 模式 + """ + self.bundle.priv_virt.value = 1 if virt else 0 + self.bundle.Satp.mode.value = satp_mode + self.bundle.Vsatp.mode.value = vsatp_mode + self.bundle.HGatp.mode.value = hgatp_mode + await self.bundle.step() + + +class PTWAgent(Agent): + def __init__(self, dtlb_bundle: DTLBBundle): + super().__init__(dtlb_bundle.ptw) + self.dtlb_bundle = dtlb_bundle + + @driver_method() + async def drive_ptw_req(self, port: int, vpn: int, s2xlate: int): + """发送 PTW 请求并等待完整流程。 + Args: + port: 端口号 (0-3) + vpn: 虚拟页号 + s2xlate: 二阶段翻译模式 + Returns: + int or None: 最终物理地址 (paddr_0) 如果无 fault;否则 None + """ + if not 0 <= port < 4: + raise ValueError("Port must be 0-3") + + req = self.bundle.req[port] + req.valid.value = 1 + req.bits_vpn.value = vpn + req.bits_s2xlate.value = s2xlate + await self.bundle.step() + req.valid.value = 0 + + await Value(self.bundle.resp.valid, 1) + has_fault = (self.bundle.resp.bits_s1_pf.value == 1 or + self.bundle.resp.bits_s1_af.value == 1 or + self.bundle.resp.bits_s2_gpf.value == 1 or + self.bundle.resp.bits_s2_gaf.value == 1) + if has_fault: + return None # Fault 发生 + + await Value(self.dtlb_bundle.requestor[port].resp.valid, 1) + resp = self.dtlb_bundle.requestor[port].resp + resp_has_fault = (resp.bits_excp_0_gpf_ld.value == 1 or + resp.bits_excp_0_pf_ld.value == 1 or + resp.bits_excp_0_af_ld.value == 1) + if resp.bits_miss.value == 0 and not resp_has_fault: + return resp.bits_paddr_0.value + return None # Miss 或异常,检查 monitor_resp + + @monitor_method() + async def monitor_ptw_resp(self): + """监测 PTW 响应内容。 + """ + if self.bundle.resp.valid.value == 1: + # 查找最近触发的 PTW 请求端口 + for port in range(4): + if self.bundle.req[port].valid.value == 1 or self.dtlb_bundle.tlbreplay[port].value == 1: + return { + "port": port, + "s1_pf": self.bundle.resp.bits_s1_pf.value, + "s1_af": self.bundle.resp.bits_s1_af.value, + "s2_gpf": self.bundle.resp.bits_s2_gpf.value, + "s2_gaf": self.bundle.resp.bits_s2_gaf.value, + "s2xlate": self.bundle.resp.bits_s2xlate.value + } + + @monitor_method() + async def monitor_requestor_resp(self): + """监测 DTLB 请求响应内容。 + """ + for port in range(4): + resp = self.dtlb_bundle.requestor[port].resp + if resp.valid.value == 1: + return { + "port": port, + "miss": resp.bits_miss.value, + "paddr": resp.bits_paddr_0.value, + "pbmt": resp.bits_pbmt_0.value, + "excp_pf_ld": resp.bits_excp_0_pf_ld.value, + "excp_af_ld": resp.bits_excp_0_af_ld.value, + "excp_gpf_ld": resp.bits_excp_0_gpf_ld.value, + "excp_pf_st": resp.bits_excp_0_pf_st.value, + "excp_af_st": resp.bits_excp_0_af_st.value, + "excp_gpf_st": resp.bits_excp_0_gpf_st.value, + "excp_vaNeedExt": resp.bits_excp_0_vaNeedExt.value, + "excp_isHyper": resp.bits_excp_0_isHyper.value + } + return None + +class ControlAgent(Agent): + def __init__(self, dtlb_bundle: DTLBBundle): + super().__init__(dtlb_bundle) + self.sfence = dtlb_bundle.sfence + self.redirect = dtlb_bundle.redirect + + @driver_method() + async def drive_sfence(self, rs1: bool, rs2: bool, addr: int = 0, id: int = 0, flushPipe: bool = False, hv: bool = False, hg: bool = False): + """配置SFENCE,配置刷新范围。 + Args: + rs1: 是否基于 RS1(地址刷新) + rs2: 是否基于 RS2(ASID/VMID 刷新) + addr: 目标虚拟地址(50 位) + id: ASID 或 VMID(16 位) + flushPipe: 是否刷新流水线 + hv: 是否针对 Hypervisor 模式 + hg: 是否针对 Guest 模式 + """ + self.sfence.bits_rs1.value = 1 if rs1 else 0 + self.sfence.bits_rs2.value = 1 if rs2 else 0 + self.sfence.bits_addr.value = addr & ((1 << 50) - 1) + self.sfence.bits_id.value = id & ((1 << 16) - 1) + self.sfence.bits_flushPipe.value = 1 if flushPipe else 0 + self.sfence.bits_hv.value = 1 if hv else 0 + self.sfence.bits_hg.value = 1 if hg else 0 + await self.bundle.step() + + @driver_method() + async def drive_redirect(self, flag: bool, value: int, level: bool): + """配置redirect。 + Args: + robIdx_flag: robIdx 标志 + robIdx_value: robIdx 值 + level: 重定向级别 + """ + self.redirect.bits_robIdx_value.value = value & ((1 << 8) - 1) + self.redirect.bits_robIdx_flag.value = 1 if flag else 0 + self.redirect.bits_level.value = 1 if level else 0 + await self.bundle.step() + +class PMPAgent(Agent): + def __init__(self, dtlb_bundle: DTLBBundle): + super().__init__(dtlb_bundle.pmp) + + @monitor_method() + async def monitor_pmp_excp(self): + """监测 PMP 。 + """ + for i in range(4): + if self.bundle[i].valid.value == 1: + return { + "port": i, + "pmp_triggered": True, + "af_ld": self.dtlb_bundle.requestor[i].resp.bits_excp_0_af_ld.value + } + return None diff --git a/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py b/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py new file mode 100644 index 00000000..14cdbf56 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py @@ -0,0 +1,145 @@ +from toffee import Bundle, Signal, Signals, SignalList, BundleList + +class CtrlBundle(Bundle): + clock, reset = Signals(2) +#------------------------------------------------------------------------ +class SfenceBundle(Bundle): + valid, \ + bits_rs1, \ + bits_rs2, \ + bits_flushPipe, \ + bits_hv, \ + bits_hg = Signals(6) + bits_addr = Signal() + bits_id = Signal() +#------------------------------------------------------------------------ +class ATPBundle(Bundle): + mode = Signal() + asid = Signal() + ppn = Signal() + changed = Signal() + +class PMMBundle(Bundle): + mseccfg, menvcfg, henvcfg, hstatus, senvcfg = Signals(5) + +class CSRBundle(Bundle): + priv_mxr, priv_sum, priv_vmxr, priv_vsum, priv_virt, priv_spvp = Signals(6) + priv_imode, priv_dmode = Signals(2) + + Satp = ATPBundle.from_prefix('satp_') + Vsatp = ATPBundle.from_prefix('vsatp_') + HGatp = ATPBundle.from_prefix('hgatp_') + PMM = PMMBundle.from_prefix('pmm_') +#------------------------------------------------------------------------ +class RequestorReqBundle(Bundle): + valid = Signal() + bits_vaddr = Signal() + bits_fullva = Signal() + bits_checkfullva = Signal() + bits_cmd = Signal() + bits_hyperinst, \ + bits_hlvx, \ + bits_kill, \ + bits_isPrefetch, \ + bits_no_translate = Signals(5) + bits_pmp_addr = Signal() + bits_debug_robIdx_flag = Signal() + bits_debug_robIdx_value = Signal() + bits_debug_isFirstIssue = Signal() + +class RequestorRespBundle(Bundle): + valid = Signal() + bits_paddr_0 = Signal() + bits_paddr_1 = Signal() + bits_gpaddr_0 = Signal() + bits_fullva = Signal() + bits_pbmt_0 = Signal() + bits_miss = Signal() + bits_isForVSnonLeafPTE = Signal() + bits_excp_0_vaNeedExt, \ + bits_excp_0_isHyper, \ + bits_excp_0_gpf_ld, \ + bits_excp_0_gpf_st, \ + bits_excp_0_pf_ld, \ + bits_excp_0_pf_st, \ + bits_excp_0_af_ld, \ + bits_excp_0_af_st = Signals(8) + bits_ptwBack = Signal() + +class RequestorBundle(Bundle): + req = RequestorReqBundle.from_prefix('req_') + resp = RequestorRespBundle.from_prefix('resp_') +#------------------------------------------------------------------------ +class RedirectBundle(Bundle): + valid = Signal() + bits_robIdx_flag = Signal() + bits_robIdx_value = Signal() + bits_level = Signal() +#------------------------------------------------------------------------ +class PTWReqBundle(Bundle): + valid = Signal() + bits_vpn = Signal() + bits_s2xlate = Signal() + bits_getGpa = Signal() +class PTWRespBundle(Bundle): + valid = Signal() + bits_s2xlate = Signal() + # S1 entry + bits_s1_entry_tag = Signal() + bits_s1_entry_asid = Signal() + bits_s1_entry_vmid = Signal() + bits_s1_entry_n = Signal() + bits_s1_entry_pbmt = Signal() + bits_s1_entry_perm_d, \ + bits_s1_entry_perm_a, \ + bits_s1_entry_perm_g, \ + bits_s1_entry_perm_u, \ + bits_s1_entry_perm_x, \ + bits_s1_entry_perm_w, \ + bits_s1_entry_perm_r = Signals(7) + bits_s1_entry_level = Signal() + bits_s1_entry_v = Signal() + bits_s1_entry_ppn = Signal() + bits_s1_addr_low = Signal() + # 列表信号 + bits_s1_ppn_low = SignalList("bits_s1_ppn_low_#", 8) + bits_s1_valididx = SignalList("bits_s1_valididx_#", 8) + bits_s1_pteidx = SignalList("bits_s1_pteidx_#", 8) + bits_s1_pf, bits_s1_af = Signals(2) + # S2 entry + bits_s2_entry_tag = Signal() + bits_s2_entry_vmid = Signal() + bits_s2_entry_n = Signal() + bits_s2_entry_pbmt = Signal() + bits_s2_entry_ppn = Signal() + bits_s2_entry_perm_d, \ + bits_s2_entry_perm_a, \ + bits_s2_entry_perm_g, \ + bits_s2_entry_perm_u, \ + bits_s2_entry_perm_x, \ + bits_s2_entry_perm_w, \ + bits_s2_entry_perm_r = Signals(7) + bits_s2_entry_level = Signal() + bits_s2_gpf, \ + bits_s2_gaf = Signals(2) + + bits_getGpa = Signal() + +class PTWBundle(Bundle): + req = BundleList(PTWReqBundle, "req_#_", 4) + resp = PTWRespBundle.from_prefix('resp_') +#------------------------------------------------------------------------ +class PMPBundle(Bundle): + valid = Signal() + bits_addr = Signal() + bits_cmd = Signal() +#------------------------------------------------------------------------ +class DTLBBundle(Bundle): + sfence = SfenceBundle.from_prefix('sfence_') + csr = CSRBundle.from_prefix('csr_') + hartId = Signal() + requestor = BundleList(RequestorBundle, "requestor_#_", 4) + redirect = RedirectBundle.from_prefix('redirect_') + ptw = PTWBundle.from_prefix('ptw_') + pmp = BundleList(PMPBundle, "pmp_#_", 4) + tlbreplay = SignalList("tlbreplay_#", 4) \ No newline at end of file From 9d2b281ed8696dd1559e729de22bc44ba9fb5617 Mon Sep 17 00:00:00 2001 From: kenny Date: Thu, 18 Sep 2025 19:11:51 +0800 Subject: [PATCH 2/4] add testcases for sfence --- .../dtlb/ld_tlb/agent/ld_dtlb_agent.py | 498 +++++++++++------- .../dtlb/ld_tlb/bundle/ld_tlb_bundle.py | 10 +- ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py | 78 +++ ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py | 192 +++++++ .../dtlb/ld_tlb/test/ld_tlb_fixture.py | 59 +++ ut_mem_block/dtlb/ld_tlb/test/test_sfence.py | 332 ++++++++++++ 6 files changed, 972 insertions(+), 197 deletions(-) create mode 100644 ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py create mode 100644 ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py create mode 100644 ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py create mode 100644 ut_mem_block/dtlb/ld_tlb/test/test_sfence.py diff --git a/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py b/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py index 76d78112..849be422 100644 --- a/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py +++ b/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py @@ -1,69 +1,324 @@ from toffee.agent import Agent, driver_method, monitor_method from toffee import Value -from ld_tlb_bundle import DTLBBundle, RequestorBundle, CSRBundle, PTWBundle, PMPBundle +from ..bundle.ld_tlb_bundle import DTLBBundle, RequestorBundle, CSRBundle, PTWBundle, PMPBundle + +def _canon_sv39_vaddr(va: int) -> int: + """把 64 位 VA 规范化为 Sv39 canonical 形式(按 bit[38] 符号扩展)""" + va = int(va) & ((1 << 64) - 1) + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (64 - 39)) - 1)) << 39 + return (upper | low39) & ((1 << 64) - 1) class DTLBAgent(Agent): - def __init__(self, dtlb_bundle: DTLBBundle): - super().__init__(dtlb_bundle) + def __init__(self, dtlb_bundle): + super().__init__(dtlb_bundle) + self.bundle = dtlb_bundle self.requestor = dtlb_bundle.requestor + self.ptw_resp = dtlb_bundle.ptw.resp @driver_method() - async def drive_request(self, port: int, vaddr: int, cmd: int, hyperinst: bool = False): - """发送请求到指定端口。 - Args: - port: 端口号 (0-3) - vaddr: 虚拟地址 - cmd: 请求命令 - hyperinst: 是否为 hypervisor 指令 - Returns: - int or None: 物理地址 (paddr_0) 如果有效;否则 None(miss 或异常) + async def drive_request( + self, + port: int, + vaddr: int, + cmd: int, + *, + hyperinst: bool = False, + pmp_addr: int | None = None, + hlvx: bool = False, + kill: bool = False, + is_prefetch: bool = False, + no_translate: bool = False, + check_fullva: bool = False, + debug_robIdx_flag: int = 0, + debug_robIdx_value: int = 0, + debug_isFirstIssue: int = 0, + return_on_miss: bool = False, + ): + """ + 命中且无异常 => 返回 paddr_0 (int) + miss / 异常 => 返回 None + return_on_miss=True: 一旦看到 miss 就立即返回 None(便于“下一拍注入”) """ if not 0 <= port < 4: - raise ValueError("Port must be 0-3") + raise ValueError("Port must be 0..N-1") + + fullva = int(vaddr) & ((1 << 64) - 1) # 完整 64 位 + canon = _canon_sv39_vaddr(fullva) # Sv39 规范化(再按端口位宽截取) + pmp = fullva if pmp_addr is None else int(pmp_addr) + + + # === 驱动 req === + req = self.requestor[port].req + + req.valid.value = 0 + req.bits_vaddr.value = canon & ((1 << 50) - 1) # 你的接口是 50 位,这里保守取低 50 位 + req.bits_fullva.value = fullva # 完整 64 位 + req.bits_checkfullva.value = 1 if check_fullva else 0 + + req.bits_cmd.value = int(cmd) + req.bits_hyperinst.value = 1 if hyperinst else 0 + req.bits_hlvx.value = 1 if hlvx else 0 + req.bits_kill.value = 1 if kill else 0 + req.bits_isPrefetch.value = 1 if is_prefetch else 0 + req.bits_no_translate.value = 0 + + req.bits_pmp_addr.value = pmp & ((1 << 48) - 1) + + req.bits_debug_robIdx_flag.value = 1 if debug_robIdx_flag else 0 + req.bits_debug_robIdx_value.value = int(debug_robIdx_value) & 0xFF + req.bits_debug_isFirstIssue.value = 1 if debug_isFirstIssue else 0 + + while (self.requestor[port].resp.valid.value == 1): + await self.bundle.step() + + req.valid.value = 1 + # print("resp_miss before request : ",self.requestor[port].resp.bits_miss.value, flush=True) + await Value(self.requestor[port].resp.valid, 1) # 发起 + req.valid.value = 0 + # print("resp_miss after request : ",self.requestor[port].resp.bits_miss.value, flush=True) + - req_bundle = self.requestor[port].req - req_bundle.valid.value = 1 - req_bundle.bits_vaddr.value = vaddr - req_bundle.bits_cmd.value = cmd - req_bundle.bits_hyperinst.value = 1 if hyperinst else 0 - await self.bundle.step() # 启动请求 - req_bundle.valid.value = 0 resp = self.requestor[port].resp + + miss = int(resp.bits_miss.value) + if miss == 1: + return None + + # 汇总异常位(ld/st 都看一遍更稳) + # print("resp_excp_0_pf_ld : ",resp.bits_excp_0_pf_ld.value, flush=True) + # print("resp_excp_0_pf_st : ",resp.bits_excp_0_pf_st.value, flush=True) + # print("resp_excp_0_af_ld : ",resp.bits_excp_0_af_ld.value, flush=True) + # print("resp_excp_0_af_st : ",resp.bits_excp_0_af_st.value, flush=True) + # print("resp_excp_0_gpf_ld: ",resp.bits_excp_0_gpf_ld.value, flush=True) + # print("resp_excp_0_gpf_st: ",resp.bits_excp_0_gpf_st.value, flush=True) + + gpf = resp.bits_excp_0_gpf_ld.value == 1 or resp.bits_excp_0_gpf_st.value == 1 + pf = resp.bits_excp_0_pf_ld.value == 1 or resp.bits_excp_0_pf_st.value == 1 + af = resp.bits_excp_0_af_ld.value == 1 or resp.bits_excp_0_af_st.value == 1 + if gpf or pf or af: + return -1 # 有异常 + + return int(resp.bits_paddr_0.value) + + + @driver_method() + async def set_ptw_resp(self, vaddr, paddr, level, *, + # S1/S2 选择 + valid: bool = True, + s2xlate: int = 0, + getGpa: bool = False, + # ---------- S1 entry ---------- + s1_asid: int = 0, + s1_vmid: int = 0, + s1_n: bool = False, + s1_pbmt: int = 0, + # 权限位 + s1_perm_d: bool = False, s1_perm_a: bool = True, s1_perm_g: bool = False, + s1_perm_u: bool = True, s1_perm_x: bool = False, s1_perm_w: bool = False, s1_perm_r: bool = True, + s1_v: bool = True, # 表项有效位 + s1_ppn_low: list[int] | None = None, # 直接给 ppn_low[8] 列表 + s1_valididx: list[int] | None = None, # 直接给 valididx[8] 列表 + s1_pteidx: list[int] | None = None, # 直接给 pteidx[8] 列表 + s1_pf: bool = False, s1_af: bool = False, + # ---------- S2 entry ---------- + s2_tag: int = 0, + s2_vmid: int = 0, + s2_n: bool = False, + s2_pbmt: int = 0, + s2_ppn: int = 0, + s2_perm_d: bool = False, s2_perm_a: bool = True, s2_perm_g: bool = False, + s2_perm_u: bool = False, s2_perm_x: bool = False, s2_perm_w: bool = False, s2_perm_r: bool = True, + s2_level: int = 0, + s2_gpf: bool = False, s2_gaf: bool = False, + ): + """ + 依据 vaddr/paddr 自动拼好 PTWResp:addr_low/entry_tag/entry_ppn/ppn_low/valididx/pteidx 等, + 并在观测到 ptw.req[i] 匹配的当下打一拍 resp.valid。 + 约定(Sv39): + - vpn = va>>12(27 位),addr_low = vpn[2:0],entry_tag = vpn>>3 + - ppn = pa>>12,entry_ppn = ppn>>3,ppn_low[addr_low] = ppn[2:0] + - 4KB 页 level=2(2MB=1,1GB=0) + """ + # -------- 计算索引/字段 -------- + vaddr = int(vaddr) & ((1 << 64) - 1) + paddr = int(paddr) & ((1 << 56) - 1) # 物理位宽保守截断 + vpn = (vaddr >> 12) & ((1 << 27) - 1) # Sv39 VPN + ppn = (paddr >> 12) + addr_low = vpn & 0b111 # vpn[2:0] + entry_tag = vpn >> 3 # 与硬件压缩槽对齐 + entry_ppn = (ppn >> 3) & ((1 << 21) - 1) # 高 21 位(低 3 位走 ppn_low[]) + ppn_low_val = ppn & 0b111 - await Value(resp.valid, 1) # 等待 resp.valid = 1,无论miss还是hit + # -------- (valid 暂时保持 0)-------- + self.ptw_resp.valid.value = 0 + self.ptw_resp.bits_s2xlate.value = s2xlate + self.ptw_resp.bits_getGpa.value = 1 if getGpa else 0 - # 检查异常信号(扩展所有相关异常) - has_fault = (resp.bits_excp_0_gpf_ld.value == 1 or - resp.bits_excp_0_pf_ld.value == 1 or - resp.bits_excp_0_af_ld.value == 1) + # S1 基本字段 + self.ptw_resp.bits_s1_entry_tag.value = entry_tag + self.ptw_resp.bits_s1_entry_asid.value = s1_asid + self.ptw_resp.bits_s1_entry_vmid.value = s1_vmid + self.ptw_resp.bits_s1_entry_n.value = 1 if s1_n else 0 + self.ptw_resp.bits_s1_entry_pbmt.value = s1_pbmt - if resp.valid.value == 1 and resp.bits_miss.value == 0 and not has_fault: - return resp.bits_paddr_0.value - return None # miss 或异常,检查 monitor_resp + self.ptw_resp.bits_s1_entry_perm_d.value = 1 if s1_perm_d else 0 + self.ptw_resp.bits_s1_entry_perm_a.value = 1 if s1_perm_a else 0 + self.ptw_resp.bits_s1_entry_perm_g.value = 1 if s1_perm_g else 0 + self.ptw_resp.bits_s1_entry_perm_u.value = 1 if s1_perm_u else 0 + self.ptw_resp.bits_s1_entry_perm_x.value = 1 if s1_perm_x else 0 + self.ptw_resp.bits_s1_entry_perm_w.value = 1 if s1_perm_w else 0 + self.ptw_resp.bits_s1_entry_perm_r.value = 1 if s1_perm_r else 0 + + self.ptw_resp.bits_s1_entry_level.value = int(level) + self.ptw_resp.bits_s1_entry_v.value = 1 if s1_v else 0 + self.ptw_resp.bits_s1_entry_ppn.value = entry_ppn + self.ptw_resp.bits_s1_addr_low.value = addr_low + + # 8 路列表:清零后只在 addr_low 位置写有效/索引/ppn_low + if s1_ppn_low is None and s1_valididx is None and s1_pteidx is None: + for i in range(8): + self.ptw_resp.bits_s1_ppn_low[i].value = 0 + self.ptw_resp.bits_s1_valididx[i].value = 0 + self.ptw_resp.bits_s1_pteidx[i].value = 0 + self.ptw_resp.bits_s1_ppn_low[addr_low].value = ppn_low_val + self.ptw_resp.bits_s1_valididx[addr_low].value = 1 + self.ptw_resp.bits_s1_pteidx[addr_low].value = 1 + else: + for i in range(8): + self.ptw_resp.bits_s1_ppn_low[i].value = s1_ppn_low[i] & 0b111 + self.ptw_resp.bits_s1_valididx[i].value = 1 if s1_valididx[i] else 0 + self.ptw_resp.bits_s1_pteidx[i].value = 1 if s1_pteidx[i] else 0 + + self.ptw_resp.bits_s1_pf.value = 1 if s1_pf else 0 + self.ptw_resp.bits_s1_af.value = 1 if s1_af else 0 + + # S2 + self.ptw_resp.bits_s2_entry_tag.value = s2_tag + self.ptw_resp.bits_s2_entry_vmid.value = s2_vmid + self.ptw_resp.bits_s2_entry_n.value = 1 if s2_n else 0 + self.ptw_resp.bits_s2_entry_pbmt.value = s2_pbmt + self.ptw_resp.bits_s2_entry_ppn.value = s2_ppn + + self.ptw_resp.bits_s2_entry_perm_d.value = 1 if s2_perm_d else 0 + self.ptw_resp.bits_s2_entry_perm_a.value = 1 if s2_perm_a else 0 + self.ptw_resp.bits_s2_entry_perm_g.value = 1 if s2_perm_g else 0 + self.ptw_resp.bits_s2_entry_perm_u.value = 1 if s2_perm_u else 0 + self.ptw_resp.bits_s2_entry_perm_x.value = 1 if s2_perm_x else 0 + self.ptw_resp.bits_s2_entry_perm_w.value = 1 if s2_perm_w else 0 + self.ptw_resp.bits_s2_entry_perm_r.value = 1 if s2_perm_r else 0 + + self.ptw_resp.bits_s2_entry_level.value = s2_level + self.ptw_resp.bits_s2_gpf.value = 1 if s2_gpf else 0 + self.ptw_resp.bits_s2_gaf.value = 1 if s2_gaf else 0 + + # -------- 对拍:见到某一路 ptw.req 匹配就打一拍 resp -------- + self.ptw_resp.valid.value = 1 + await self.bundle.step() + self.bundle.ptw.resp.valid.value = 0 + + # @driver_method() + # async def set_csr(self,*, + # priv_mxr = 0, priv_sum = 0, + # priv_vmxr = 0, priv_vsum = 0, + # priv_virt = 0, priv_spvp = 0, + # priv_imode = 0, priv_dmode = 0, + + # Satp_mode = 8, # Sv39 常见编码 + # Satp_asid = 0, + # Satp_ppn = 0, + # Satp_changed = 0, + + # Vsatp_mode = 0, + # Vsatp_asid = 0, + # Vsatp_ppn = 0, + # Vsatp_changed = 0, + + # HGatp_mode = 0, + # HGatp_vmid = 0, + # HGatp_ppn = 0, + # HGatp_changed = 0,): + # csr = self.bundle.csr + # csr.bits_priv_mxr.value = priv_mxr + # csr.bits_priv_sum.value = priv_sum + # csr.bits_priv_vmxr.value = priv_vmxr + # csr.bits_priv_vsum.value = priv_vsum + # csr.bits_priv_virt.value = priv_virt + # csr.bits_priv_spvp.value = priv_spvp + # csr.bits_priv_imode.value = priv_imode + # csr.bits_priv_dmode.value = priv_dmode + # csr.bits_Satp_mode.value = Satp_mode + # csr.bits_Satp_asid.value = Satp_asid + # csr.bits_Satp_ppn.value = Satp_ppn + # csr.bits_Satp_changed.value = Satp_changed + # csr.bits_Vsatp_mode.value = Vsatp_mode + # csr.bits_Vsatp_asid.value = Vsatp_asid + # csr.bits_Vsatp_ppn.value = Vsatp_ppn + # csr.bits_Vsatp_changed.value = Vsatp_changed + # csr.bits_HGatp_mode.value = HGatp_mode + # csr.bits_HGatp_vmid.value = HGatp_vmid + # csr.bits_HGatp_ppn.value = HGatp_ppn + # csr.bits_HGatp_changed.value = HGatp_changed + # await self.bundle.step() @monitor_method() - async def monitor_resp(self): + async def monitor_ptw_req(self): """ - 监测响应。 + 监测 PTW 请求。 """ for port in range(4): - resp = self.requestor[port].resp - if resp.valid.value == 1: + req = self.bundle.ptw.req[port] + if req.valid.value == 1: return { "port": port, - "miss": resp.bits_miss.value, - "paddr": resp.bits_paddr_0.value, - "fullva": resp.bits_fullva.value, - "pbmt": resp.bits_pbmt_0.value, - "excp_pf_ld": resp.bits_excp_0_pf_ld.value, - "excp_af_ld": resp.bits_excp_0_af_ld.value, + "vpn": req.bits_vpn.value, + "tag": req.bits_vpn.value >> 3, + "s2xlate": req.bits_s2xlate.value, + "getGpa": req.bits_getGpa.value } return None - + + @monitor_method() + async def monitor_ptw_resp(self): + ptw_resp = self.ptw_resp + if ptw_resp.valid.value == 1: + return { + "s2xlate": ptw_resp.bits_s2xlate.value, + "s1_asid": ptw_resp.bits_s1_entry_asid.value, + "s1_entry_tag": ptw_resp.bits_s1_entry_tag.value, + "s1_level": ptw_resp.bits_s1_entry_level.value, + "s1_ppn_low[0]": ptw_resp.bits_s1_ppn_low[0].value, + "s1_ppn_low[1]": ptw_resp.bits_s1_ppn_low[1].value, + "s1_ppn_low[2]": ptw_resp.bits_s1_ppn_low[2].value, + "s1_ppn_low[3]": ptw_resp.bits_s1_ppn_low[3].value, + "s1_ppn_low[4]": ptw_resp.bits_s1_ppn_low[4].value, + "s1_ppn_low[5]": ptw_resp.bits_s1_ppn_low[5].value, + "s1_ppn_low[6]": ptw_resp.bits_s1_ppn_low[6].value, + "s1_ppn_low[7]": ptw_resp.bits_s1_ppn_low[7].value, + "s1_valididx[0]": ptw_resp.bits_s1_valididx[0].value, + "s1_valididx[1]": ptw_resp.bits_s1_valididx[1].value, + "s1_valididx[2]": ptw_resp.bits_s1_valididx[2].value, + "s1_valididx[3]": ptw_resp.bits_s1_valididx[3].value, + "s1_valididx[4]": ptw_resp.bits_s1_valididx[4].value, + "s1_valididx[5]": ptw_resp.bits_s1_valididx[5].value, + "s1_valididx[6]": ptw_resp.bits_s1_valididx[6].value, + "s1_valididx[7]": ptw_resp.bits_s1_valididx[7].value, + "s1_pteidx[0]": ptw_resp.bits_s1_pteidx[0].value, + "s1_pteidx[1]": ptw_resp.bits_s1_pteidx[1].value, + "s1_pteidx[2]": ptw_resp.bits_s1_pteidx[2].value, + "s1_pteidx[3]": ptw_resp.bits_s1_pteidx[3].value, + "s1_pteidx[4]": ptw_resp.bits_s1_pteidx[4].value, + "s1_pteidx[5]": ptw_resp.bits_s1_pteidx[5].value, + "s1_pteidx[6]": ptw_resp.bits_s1_pteidx[6].value, + "s1_pteidx[7]": ptw_resp.bits_s1_pteidx[7].value + } + return None + @monitor_method() - async def monitor_multi_port(self): + async def monitor_req(self): """ - 监测多端口请求内容。 + 监测请求。 """ for port in range(4): req = self.requestor[port].req @@ -72,175 +327,30 @@ async def monitor_multi_port(self): "port": port, "vaddr": req.bits_vaddr.value, "fullva": req.bits_fullva.value, - "checkfullva": req.bits_checkfullva.value, "cmd": req.bits_cmd.value, "hyperinst": req.bits_hyperinst.value, "hlvx": req.bits_hlvx.value, "kill": req.bits_kill.value, "isPrefetch": req.bits_isPrefetch.value, "no_translate": req.bits_no_translate.value, - "pmp_addr": req.bits_pmp_addr.value, - "debug_robIdx_flag": req.bits_debug_robIdx_flag.value, - "debug_robIdx_value": req.bits_debug_robIdx_value.value, - "debug_isFirstIssue": req.bits_debug_isFirstIssue.value + "pmp_addr": req.bits_pmp_addr.value } return None - -class CSRAgent(Agent): - def __init__(self, csr_bundle: CSRBundle): - super().__init__(csr_bundle) - - @driver_method() - async def drive_virt_config(self, virt: bool, satp_mode: int, vsatp_mode: int, hgatp_mode: int): - """配置虚拟化模式。 - Args: - virt: 是否启用虚拟化 - satp_mode: SATP 模式 - vsatp_mode: VSATP 模式 - hgatp_mode: HGATP 模式 - """ - self.bundle.priv_virt.value = 1 if virt else 0 - self.bundle.Satp.mode.value = satp_mode - self.bundle.Vsatp.mode.value = vsatp_mode - self.bundle.HGatp.mode.value = hgatp_mode - await self.bundle.step() - - -class PTWAgent(Agent): - def __init__(self, dtlb_bundle: DTLBBundle): - super().__init__(dtlb_bundle.ptw) - self.dtlb_bundle = dtlb_bundle - - @driver_method() - async def drive_ptw_req(self, port: int, vpn: int, s2xlate: int): - """发送 PTW 请求并等待完整流程。 - Args: - port: 端口号 (0-3) - vpn: 虚拟页号 - s2xlate: 二阶段翻译模式 - Returns: - int or None: 最终物理地址 (paddr_0) 如果无 fault;否则 None - """ - if not 0 <= port < 4: - raise ValueError("Port must be 0-3") - - req = self.bundle.req[port] - req.valid.value = 1 - req.bits_vpn.value = vpn - req.bits_s2xlate.value = s2xlate - await self.bundle.step() - req.valid.value = 0 - - await Value(self.bundle.resp.valid, 1) - has_fault = (self.bundle.resp.bits_s1_pf.value == 1 or - self.bundle.resp.bits_s1_af.value == 1 or - self.bundle.resp.bits_s2_gpf.value == 1 or - self.bundle.resp.bits_s2_gaf.value == 1) - if has_fault: - return None # Fault 发生 - - await Value(self.dtlb_bundle.requestor[port].resp.valid, 1) - resp = self.dtlb_bundle.requestor[port].resp - resp_has_fault = (resp.bits_excp_0_gpf_ld.value == 1 or - resp.bits_excp_0_pf_ld.value == 1 or - resp.bits_excp_0_af_ld.value == 1) - if resp.bits_miss.value == 0 and not resp_has_fault: - return resp.bits_paddr_0.value - return None # Miss 或异常,检查 monitor_resp - + @monitor_method() - async def monitor_ptw_resp(self): - """监测 PTW 响应内容。 + async def monitor_resp(self): """ - if self.bundle.resp.valid.value == 1: - # 查找最近触发的 PTW 请求端口 - for port in range(4): - if self.bundle.req[port].valid.value == 1 or self.dtlb_bundle.tlbreplay[port].value == 1: - return { - "port": port, - "s1_pf": self.bundle.resp.bits_s1_pf.value, - "s1_af": self.bundle.resp.bits_s1_af.value, - "s2_gpf": self.bundle.resp.bits_s2_gpf.value, - "s2_gaf": self.bundle.resp.bits_s2_gaf.value, - "s2xlate": self.bundle.resp.bits_s2xlate.value - } - - @monitor_method() - async def monitor_requestor_resp(self): - """监测 DTLB 请求响应内容。 + 监测响应。 """ for port in range(4): - resp = self.dtlb_bundle.requestor[port].resp + resp = self.requestor[port].resp if resp.valid.value == 1: return { "port": port, "miss": resp.bits_miss.value, "paddr": resp.bits_paddr_0.value, - "pbmt": resp.bits_pbmt_0.value, - "excp_pf_ld": resp.bits_excp_0_pf_ld.value, - "excp_af_ld": resp.bits_excp_0_af_ld.value, - "excp_gpf_ld": resp.bits_excp_0_gpf_ld.value, - "excp_pf_st": resp.bits_excp_0_pf_st.value, - "excp_af_st": resp.bits_excp_0_af_st.value, - "excp_gpf_st": resp.bits_excp_0_gpf_st.value, - "excp_vaNeedExt": resp.bits_excp_0_vaNeedExt.value, - "excp_isHyper": resp.bits_excp_0_isHyper.value - } - return None - -class ControlAgent(Agent): - def __init__(self, dtlb_bundle: DTLBBundle): - super().__init__(dtlb_bundle) - self.sfence = dtlb_bundle.sfence - self.redirect = dtlb_bundle.redirect - - @driver_method() - async def drive_sfence(self, rs1: bool, rs2: bool, addr: int = 0, id: int = 0, flushPipe: bool = False, hv: bool = False, hg: bool = False): - """配置SFENCE,配置刷新范围。 - Args: - rs1: 是否基于 RS1(地址刷新) - rs2: 是否基于 RS2(ASID/VMID 刷新) - addr: 目标虚拟地址(50 位) - id: ASID 或 VMID(16 位) - flushPipe: 是否刷新流水线 - hv: 是否针对 Hypervisor 模式 - hg: 是否针对 Guest 模式 - """ - self.sfence.bits_rs1.value = 1 if rs1 else 0 - self.sfence.bits_rs2.value = 1 if rs2 else 0 - self.sfence.bits_addr.value = addr & ((1 << 50) - 1) - self.sfence.bits_id.value = id & ((1 << 16) - 1) - self.sfence.bits_flushPipe.value = 1 if flushPipe else 0 - self.sfence.bits_hv.value = 1 if hv else 0 - self.sfence.bits_hg.value = 1 if hg else 0 - await self.bundle.step() - - @driver_method() - async def drive_redirect(self, flag: bool, value: int, level: bool): - """配置redirect。 - Args: - robIdx_flag: robIdx 标志 - robIdx_value: robIdx 值 - level: 重定向级别 - """ - self.redirect.bits_robIdx_value.value = value & ((1 << 8) - 1) - self.redirect.bits_robIdx_flag.value = 1 if flag else 0 - self.redirect.bits_level.value = 1 if level else 0 - await self.bundle.step() - -class PMPAgent(Agent): - def __init__(self, dtlb_bundle: DTLBBundle): - super().__init__(dtlb_bundle.pmp) - - @monitor_method() - async def monitor_pmp_excp(self): - """监测 PMP 。 - """ - for i in range(4): - if self.bundle[i].valid.value == 1: - return { - "port": i, - "pmp_triggered": True, - "af_ld": self.dtlb_bundle.requestor[i].resp.bits_excp_0_af_ld.value + "fullva": resp.bits_fullva.value } return None + + diff --git a/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py b/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py index 14cdbf56..fca3f57c 100644 --- a/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py +++ b/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py @@ -1,7 +1,5 @@ from toffee import Bundle, Signal, Signals, SignalList, BundleList -class CtrlBundle(Bundle): - clock, reset = Signals(2) #------------------------------------------------------------------------ class SfenceBundle(Bundle): valid, \ @@ -19,6 +17,12 @@ class ATPBundle(Bundle): ppn = Signal() changed = Signal() +class HGATPBundle(Bundle): + mode = Signal() + vmid = Signal() + ppn = Signal() + changed = Signal() + class PMMBundle(Bundle): mseccfg, menvcfg, henvcfg, hstatus, senvcfg = Signals(5) @@ -28,7 +32,7 @@ class CSRBundle(Bundle): Satp = ATPBundle.from_prefix('satp_') Vsatp = ATPBundle.from_prefix('vsatp_') - HGatp = ATPBundle.from_prefix('hgatp_') + HGatp = HGATPBundle.from_prefix('hgatp_') PMM = PMMBundle.from_prefix('pmm_') #------------------------------------------------------------------------ class RequestorReqBundle(Bundle): diff --git a/ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py b/ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py new file mode 100644 index 00000000..d7ae09a4 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py @@ -0,0 +1,78 @@ +# env/dtlb_env.py +from toffee import Env +from ..bundle.ld_tlb_bundle import DTLBBundle +from ..agent.ld_dtlb_agent import DTLBAgent +from .dtlb_mdl import DTLBPLRURefModel + +class DTLBEnv_PLRU(Env): + def __init__(self, dut): + super().__init__() + self.dut = dut + self.bundle = DTLBBundle.from_prefix("io_").bind(dut) + # 事务级 agent + self.req = DTLBAgent(self.bundle) + self.mdl = DTLBPLRURefModel() + self.attach(self.mdl) + + async def set_sv39_defaults(self): + csr = self.bundle.csr + csr.priv_mxr.value = 0; csr.priv_sum.value = 0 + csr.priv_vmxr.value = 0; csr.priv_vsum.value = 0 + csr.priv_virt.value = 0; csr.priv_spvp.value = 0 + csr.priv_imode.value = 0; csr.priv_dmode.value = 0 + + csr.Satp.mode.value = 8 # Sv39 常见编码 + csr.Satp.asid.value = 0 + csr.Satp.ppn.value = 0 + csr.Satp.changed.value = 0 + + csr.Vsatp.mode.value = 0 + csr.Vsatp.asid.value = 0 + csr.Vsatp.ppn.value = 0 + csr.Vsatp.changed.value = 0 + + csr.HGatp.mode.value = 0 + csr.HGatp.vmid.value = 0 + csr.HGatp.ppn.value = 0 + csr.HGatp.changed.value = 0 + + sf = self.bundle.sfence + sf.valid.value = 0; sf.bits_rs1.value = 0; sf.bits_rs2.value = 0 + sf.bits_flushPipe.value = 0; sf.bits_hv.value = 0; sf.bits_hg.value = 0 + sf.bits_addr.value = 0; sf.bits_id.value = 0 + +class DTLBEnv(Env): + def __init__(self, dut): + super().__init__() + self.dut = dut + self.bundle = DTLBBundle.from_prefix("io_").bind(dut) + # 事务级 agent + self.req = DTLBAgent(self.bundle) + + + async def set_sv39_defaults(self): + csr = self.bundle.csr + csr.priv_mxr.value = 0; csr.priv_sum.value = 0 + csr.priv_vmxr.value = 0; csr.priv_vsum.value = 0 + csr.priv_virt.value = 0; csr.priv_spvp.value = 0 + csr.priv_imode.value = 0; csr.priv_dmode.value = 0 + + csr.Satp.mode.value = 8 # Sv39 常见编码 + csr.Satp.asid.value = 0 + csr.Satp.ppn.value = 0 + csr.Satp.changed.value = 0 + + csr.Vsatp.mode.value = 0 + csr.Vsatp.asid.value = 0 + csr.Vsatp.ppn.value = 0 + csr.Vsatp.changed.value = 0 + + csr.HGatp.mode.value = 0 + csr.HGatp.vmid.value = 0 + csr.HGatp.ppn.value = 0 + csr.HGatp.changed.value = 0 + + sf = self.bundle.sfence + sf.valid.value = 0; sf.bits_rs1.value = 0; sf.bits_rs2.value = 0 + sf.bits_flushPipe.value = 0; sf.bits_hv.value = 0; sf.bits_hg.value = 0 + sf.bits_addr.value = 0; sf.bits_id.value = 0 \ No newline at end of file diff --git a/ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py b/ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py new file mode 100644 index 00000000..e3d43bf8 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +from __future__ import annotations +from toffee.model import Model, driver_hook + +# ---------------------- Sv39 规范化 + page key ---------------------- +def _canon_sv39_vaddr(va: int) -> int: + va = int(va) & ((1 << 64) - 1) + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (64 - 39)) - 1)) << 39 + return (upper | low39) & ((1 << 64) - 1) + +def _page_key_from_va(va: int) -> int: + canon = _canon_sv39_vaddr(va) + va39 = canon & ((1 << 39) - 1) + return va39 & ~0xFFF # 清 4KB 偏移 + +# ---------------------- 不平衡 48-way Tree-PLRU(根 32/16) ---------------------- +class TreePLRU48: + """ + 48 路 Tree-PLRU(根拆成 左32/右16,不平衡) + 规则:victim 时 bit=0 走左、bit=1 走右;touch 某 way 时,沿路径把该结点位改成“指向另一侧”为冷。 + """ + class Node: + __slots__ = ("L", "R", "bit", "lch", "rch") + def __init__(self, L, R): + self.L, self.R = L, R # 左/右子树包含的叶子数 + self.bit = 0 # 0=左冷(选左)、1=右冷(选右) + self.lch = None + self.rch = None + + def __init__(self): + self.root = self.Node(32, 16) + def build(n): + if n.L > 1: + n.lch = self.Node(n.L // 2, n.L - n.L // 2) + build(n.lch) + if n.R > 1: + n.rch = self.Node(n.R // 2, n.R - n.R // 2) + build(n.rch) + build(self.root) + + def pick_victim(self) -> int: + """ + 无条件由 PLRU 选路(不做 invalid 优先)。当选择命中“叶子侧”时不再下探,直接终止。 + 返回 0..47 的 way 索引。 + """ + n = self.root + idx = 0 + while True: + # 到叶(单侧 1 个元素) + if n.L + n.R == 1: + break + if n.bit == 1: + # 走右侧 + idx += n.L + if n.R == 1: + break # 右侧是叶,不再往下 + n = n.rch + else: + # 走左侧 + if n.L == 1: + break # 左侧是叶,不再往下 + n = n.lch + return idx + + def touch(self, i: int) -> None: + """ + 命中/回填后:沿着 i 的路径把结点位改成“指向另一侧”为冷。 + 当命中的是叶子侧时,同样不再向下走。 + """ + n = self.root + idx = i + while n and (n.L + n.R > 1): + if idx < n.L: + # 走左:把右标冷(bit=1) + n.bit = 1 + if n.L == 1: + break # 左侧是叶,不再向下 + n = n.lch + else: + # 走右:把左标冷(bit=0) + idx -= n.L + n.bit = 0 + if n.R == 1: + break # 右侧是叶,不再向下 + n = n.rch + + def reset(self): + def walk(n): + if not n: return + n.bit = 0 + walk(n.lch); walk(n.rch) + walk(self.root) + + +# ---------------------- 参考模型:48 项全相联(无 invalid 优先) ---------------------- +class DTLBPLRURefModel(Model): + """ + - 48 项全相联缓存:每项保存 {valid, va_page_key(39b), pa_page_base} + - 替换:无条件 PLRU 选 way(不做 invalid 优先);写入后 touch + - 命中:返回 (pa_page_base | (vaddr & 0xFFF)) + """ + CAP = 48 + + def __init__(self): + super().__init__() + self.entries = [{"valid": False, "va": 0, "pa": 0} for _ in range(self.CAP)] + self.plru = TreePLRU48() + + # ---------------- driver_hook #1:命中查询 ---------------- + @driver_hook(agent_name="req", driver_name="drive_request") + def drive_request( + self, + port: int, + vaddr: int, + cmd: int, + *, + hyperinst: bool = False, + pmp_addr: int | None = None, + hlvx: bool = False, + kill: bool = False, + is_prefetch: bool = False, + no_translate: bool = False, + check_fullva: bool = False, + debug_robIdx_flag: int = 0, + debug_robIdx_value: int = 0, + debug_isFirstIssue: int = 0, + return_on_miss: bool = False, + ): + key = _page_key_from_va(vaddr) + for idx, e in enumerate(self.entries): + if e["valid"] and e["va"] == key: + self.plru.touch(idx) # 命中也要更新 PLRU + return int(e["pa"] | (int(vaddr) & 0xFFF)) + return None + + # ---------------- driver_hook #2:PTW 回填(无 invalid 优先) ---------------- + @driver_hook(agent_name="req", driver_name="set_ptw_resp") + def set_ptw_resp(self, vaddr, paddr, level, *, + # S1/S2 选择 + valid: bool = True, + s2xlate: int = 0, + getGpa: bool = False, + # ---------- S1 entry ---------- + s1_asid: int = 0, + s1_vmid: int = 0, + s1_n: bool = False, + s1_pbmt: int = 0, + # 权限位(按 D/A/G/U/X/W/R 的顺序给) + s1_perm_d: bool = False, s1_perm_a: bool = True, s1_perm_g: bool = False, + s1_perm_u: bool = True, s1_perm_x: bool = False, s1_perm_w: bool = False, s1_perm_r: bool = True, + s1_v: bool = True, # 表项有效位 + s1_ppn_low: list[int] | None = None, # 直接给 ppn_low[8] 列表 + s1_valididx: list[int] | None = None, # 直接给 valididx[8] 列表 + s1_pteidx: list[int] | None = None, # 直接给 pteidx[8] 列表 + s1_pf: bool = False, s1_af: bool = False, + # ---------- S2 entry(当 s2xlate=1 时生效) ---------- + s2_tag: int = 0, + s2_vmid: int = 0, + s2_n: bool = False, + s2_pbmt: int = 0, + s2_ppn: int = 0, + s2_perm_d: bool = False, s2_perm_a: bool = True, s2_perm_g: bool = False, + s2_perm_u: bool = False, s2_perm_x: bool = False, s2_perm_w: bool = False, s2_perm_r: bool = True, + s2_level: int = 0, + s2_gpf: bool = False, s2_gaf: bool = False, + ): + """ + 与 DUT 对齐:不找空槽,始终由 PLRU 选 way。 + 若已存在同 VA,做覆写并 touch(不新增)。 + """ + if not valid: + return None + + key = _page_key_from_va(vaddr) + pa_base = int(paddr) & ~0xFFF + + # 若已有同 VA:覆写 + touch(避免同一 VA 出现多份) + for idx, e in enumerate(self.entries): + if e["valid"] and e["va"] == key: + e["pa"] = pa_base + self.plru.touch(idx) + return None + + # 由 PLRU 直接给 wayIdx(即便有 invalid 也不优先用) + victim = self.plru.pick_victim() + self.entries[victim]["valid"] = True + self.entries[victim]["va"] = key + self.entries[victim]["pa"] = pa_base + self.plru.touch(victim) + return None diff --git a/ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py b/ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py new file mode 100644 index 00000000..84d52722 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py @@ -0,0 +1,59 @@ +import toffee +import toffee_test +from ..env.dtlb_env import DTLBEnv, DTLBEnv_PLRU +from dut.TLBNonBlock import DUTTLBNonBlock + +@toffee_test.fixture +async def dtlb_env_plru(toffee_request: toffee_test.ToffeeRequest): + + toffee.setup_logging(toffee.ERROR) + dut = toffee_request.create_dut(DUTTLBNonBlock) + + + dut.InitClock("clock") + toffee.start_clock(dut) + env = DTLBEnv_PLRU(dut) + # env.req.start_monitor("monitor_req", 50) + # env.req.start_monitor("monitor_resp", 50) + # env.req.start_monitor("monitor_ptw_resp", 50) + # env.req.start_monitor("monitor_ptw_req", 50) + + yield env + + import asyncio + loop = asyncio.get_event_loop() + for task in asyncio.all_tasks(loop): + if task.get_name() == "__clock_loop": + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + +@toffee_test.fixture +async def dtlb_env(toffee_request: toffee_test.ToffeeRequest): + + toffee.setup_logging(toffee.ERROR) + dut = toffee_request.create_dut(DUTTLBNonBlock) + + + dut.InitClock("clock") + toffee.start_clock(dut) + env = DTLBEnv(dut) + # env.req.start_monitor("monitor_req", 50) + # env.req.start_monitor("monitor_resp", 50) + # env.req.start_monitor("monitor_ptw_resp", 50) + # env.req.start_monitor("monitor_ptw_req", 50) + + yield env + + import asyncio + loop = asyncio.get_event_loop() + for task in asyncio.all_tasks(loop): + if task.get_name() == "__clock_loop": + task.cancel() + try: + await task + except asyncio.CancelledError: + pass diff --git a/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py b/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py new file mode 100644 index 00000000..d4818d77 --- /dev/null +++ b/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py @@ -0,0 +1,332 @@ +# -*- coding: utf-8 -*- +import toffee +import toffee_test +from .ld_tlb_fixture import dtlb_env + +LOAD = 0 +STORE = 1 + +async def _wait_ptw_req_and_capture(env, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = env.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await env.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) + +def _canon_sv39_to_50b(va: int, page_align: bool) -> int: + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (50 - 39)) - 1)) << 39 + va50 = (upper | low39) & ((1 << 50) - 1) + if page_align: + va50 &= ~0xFFF + return va50 + +async def do_sfence(env, *, hv=False, hg=False, rs1=False, addr=0, rs2=False, id_=0, settle_cycles=10): + sf = env.bundle.sfence + sf.bits_hv.value = 1 if hv else 0 + sf.bits_hg.value = 1 if hg else 0 + sf.bits_rs1.value = 1 if rs1 else 0 + sf.bits_rs2.value = 1 if rs2 else 0 + + sf.bits_addr.value = _canon_sv39_to_50b(addr, page_align=rs1) + sf.bits_id.value = int(id_) & ((1 << 16) - 1) # VMA: ASID;GVMA: VMID;VVMA: 实际忽略 + sf.bits_flushPipe.value = 0 + + sf.valid.value = 1 + await env.bundle.step() + sf.valid.value = 0 + + # 给硬件若干拍时间完成写口失效/遍历 + for _ in range(settle_cycles): + await env.bundle.step() + + +# ========================= +# 1) SFENCE.VMA 全量清(非 G) +# ========================= +@toffee_test.testcase +async def test_sfence_vma_global_noG(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x11 + + csr = env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await env.bundle.step() + + + + # miss → 回填(非 G)→ hit + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, va) + await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == expect + + # 全量清(rs1=0, rs2=0) + await do_sfence(env, hv=False, hg=False, rs1=False, rs2=False) + + # 应 miss + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 2) SFENCE.VMA 按 ASID 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_asid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x22 + + csr = env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await env.bundle.step() + + + + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, va) + await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + # 按当前 satp.asid 清(id 用 CSR.Satp.asid) + await do_sfence(env, hv=False, hg=False, rs1=False, rs2=True, id_=asid) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 3) SFENCE.VMA 按 VA 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_va(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 1 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x33 + + csr = env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await env.bundle.step() + + + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, va) + await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + await do_sfence(env, hv=False, hg=False, rs1=True, addr=va, rs2=False) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 4) SFENCE.VMA 按 (VA, ASID) 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_va_asid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 2 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x44 + + csr = env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await env.bundle.step() + + + + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, va) + await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + await do_sfence(env, hv=False, hg=False, rs1=True, addr=va, rs2=True, id_=asid) + assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 5) HFENCE.VVMA:按 VMID(全 GVA) +# ========================= +@toffee_test.testcase +async def test_hfence_vvma_by_vmid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 0 + gva = 0x0000_0000_8020_1000 + gpa = 0x0000_0001_0000_9000 + asid = 0x12 + vmid = 0xAA + + csr = env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 # VS-S1 开启 + csr.HGatp.mode.value = 0 # S2 关闭(only VS-S1) + csr.Vsatp.asid.value = asid + csr.HGatp.vmid.value = vmid # 关键:VVMA 用 CSR.HGATP.vmid 过滤 + await env.bundle.step() + + + + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, gva) + await env.req.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, + s1_asid=asid, s1_vmid=vmid, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, + s2xlate=s2x) + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) + + # VVMA:hv=1,通常按 VMID 过滤需 rs2=1;VMID 来源于 CSR.HGATP.vmid(id 忽略) + await do_sfence(env, hv=True, hg=False, rs1=False, rs2=True, id_=vmid) + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 6) HFENCE.VVMA:按 (GVA, VMID) 清 +# ========================= +@toffee_test.testcase +async def test_hfence_vvma_by_gva_vmid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 1 + gva = 0x0000_0000_8020_1000 + gpa = 0x0000_0001_0000_9000 + asid = 0x21 + vmid = 0xBB + + csr = env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = asid + csr.HGatp.vmid.value = vmid + await env.bundle.step() + + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(env, gva) + await env.req.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, + s1_asid=asid, s1_vmid=vmid, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, + s2xlate=s2x) + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) + + await do_sfence(env, hv=True, hg=False, rs1=True, addr=gva, rs2=True, id_=vmid) + assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 7) HFENCE.GVMA:按 VMID 清 S2(GPA 全范围) +# ========================= +@toffee_test.testcase +async def test_hfence_gvma_by_vmid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 2 + gpa_in = 0x0000_0000_8020_1000 + hpa = 0x0000_0002_2000_0000 + vmid = 0x66 + + csr = env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = vmid + await env.bundle.step() + + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(env, gpa_in) + await env.req.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) + + # GVMA:hg=1,按 VMID(来自 bits_id)清 S2 + await do_sfence(env, hv=False, hg=True, rs1=False, rs2=True, id_=vmid) + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 8) HFENCE.GVMA:按 (GPA, VMID) 清 S2 +# ========================= +@toffee_test.testcase +async def test_hfence_gvma_by_gpa_vmid(dtlb_env): + env = dtlb_env + env.dut.reset.value = 1; await env.bundle.step() + env.dut.reset.value = 0; await env.bundle.step() + await env.set_sv39_defaults(); await env.bundle.step() + + port = 3 + gpa_in = 0x0000_0000_8020_1000 + hpa = 0x0000_0002_2000_1000 + vmid = 0x77 + + csr = env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = vmid + await env.bundle.step() + + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(env, gpa_in) + await env.req.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) + + await do_sfence(env, hv=False, hg=True, rs1=True, addr=gpa_in, rs2=True, id_=vmid) + assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None From 7bd370d678234dace8dcc5ac12d81f466c91f782 Mon Sep 17 00:00:00 2001 From: kenny Date: Fri, 19 Sep 2025 18:13:23 +0800 Subject: [PATCH 3/4] add testcases for dtlb --- .../dtlb/{ld_tlb => agent}/__init__.py | 0 .../ld_dtlb_agent.py => agent/dtlb_agent.py} | 11 +- .../dtlb/{ld_tlb/agent => bundle}/__init__.py | 0 .../dtlb_bundle.py} | 0 .../dtlb/{ld_tlb/bundle => env}/__init__.py | 0 .../dtlb/{ld_tlb => }/env/dtlb_env.py | 10 +- .../dtlb/{ld_tlb => }/env/dtlb_mdl.py | 4 +- ut_mem_block/dtlb/ld_tlb/test/__init__.py | 0 ut_mem_block/dtlb/ld_tlb/test/test_sfence.py | 332 ------- ut_mem_block/dtlb/pf_tlb/__init__.py | 0 ut_mem_block/dtlb/pf_tlb/agent/__init__.py | 0 ut_mem_block/dtlb/pf_tlb/bundle/__init__.py | 0 ut_mem_block/dtlb/pf_tlb/env/__init__.py | 0 ut_mem_block/dtlb/pf_tlb/scripts/__init__.py | 0 .../dtlb/pf_tlb/scripts/bundle_code_gen.py | 160 ---- ut_mem_block/dtlb/pf_tlb/test/__init__.py | 0 .../dtlb/{ld_tlb/env => scripts}/__init__.py | 0 .../{ld_tlb => }/scripts/bundle_code_gen.py | 0 ut_mem_block/dtlb/st_tlb/__init__.py | 0 ut_mem_block/dtlb/st_tlb/agent/__init__.py | 0 ut_mem_block/dtlb/st_tlb/bundle/__init__.py | 0 ut_mem_block/dtlb/st_tlb/env/__init__.py | 0 ut_mem_block/dtlb/st_tlb/scripts/__init__.py | 0 .../dtlb/st_tlb/scripts/bundle_code_gen.py | 160 ---- ut_mem_block/dtlb/st_tlb/test/__init__.py | 0 .../dtlb/{ld_tlb/scripts => test}/__init__.py | 0 ut_mem_block/dtlb/test/funcov_dtlb.py | 178 ++++ .../dtlb/{ld_tlb => }/test/ld_tlb_fixture.py | 9 +- ut_mem_block/dtlb/test/test_ld_dtlb.py | 906 ++++++++++++++++++ ut_mem_block/dtlb/test/test_plru.py | 103 ++ ut_mem_block/dtlb/test/test_redirect.py | 128 +++ ut_mem_block/dtlb/test/test_sfence.py | 328 +++++++ ut_mem_block/dtlb/test/test_st_dtlb.py | 833 ++++++++++++++++ 33 files changed, 2494 insertions(+), 668 deletions(-) rename ut_mem_block/dtlb/{ld_tlb => agent}/__init__.py (100%) rename ut_mem_block/dtlb/{ld_tlb/agent/ld_dtlb_agent.py => agent/dtlb_agent.py} (97%) rename ut_mem_block/dtlb/{ld_tlb/agent => bundle}/__init__.py (100%) rename ut_mem_block/dtlb/{ld_tlb/bundle/ld_tlb_bundle.py => bundle/dtlb_bundle.py} (100%) rename ut_mem_block/dtlb/{ld_tlb/bundle => env}/__init__.py (100%) rename ut_mem_block/dtlb/{ld_tlb => }/env/dtlb_env.py (91%) rename ut_mem_block/dtlb/{ld_tlb => }/env/dtlb_mdl.py (98%) delete mode 100644 ut_mem_block/dtlb/ld_tlb/test/__init__.py delete mode 100644 ut_mem_block/dtlb/ld_tlb/test/test_sfence.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/__init__.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/agent/__init__.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/bundle/__init__.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/env/__init__.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/scripts/__init__.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/scripts/bundle_code_gen.py delete mode 100644 ut_mem_block/dtlb/pf_tlb/test/__init__.py rename ut_mem_block/dtlb/{ld_tlb/env => scripts}/__init__.py (100%) rename ut_mem_block/dtlb/{ld_tlb => }/scripts/bundle_code_gen.py (100%) delete mode 100644 ut_mem_block/dtlb/st_tlb/__init__.py delete mode 100644 ut_mem_block/dtlb/st_tlb/agent/__init__.py delete mode 100644 ut_mem_block/dtlb/st_tlb/bundle/__init__.py delete mode 100644 ut_mem_block/dtlb/st_tlb/env/__init__.py delete mode 100644 ut_mem_block/dtlb/st_tlb/scripts/__init__.py delete mode 100644 ut_mem_block/dtlb/st_tlb/scripts/bundle_code_gen.py delete mode 100644 ut_mem_block/dtlb/st_tlb/test/__init__.py rename ut_mem_block/dtlb/{ld_tlb/scripts => test}/__init__.py (100%) create mode 100644 ut_mem_block/dtlb/test/funcov_dtlb.py rename ut_mem_block/dtlb/{ld_tlb => }/test/ld_tlb_fixture.py (90%) create mode 100644 ut_mem_block/dtlb/test/test_ld_dtlb.py create mode 100644 ut_mem_block/dtlb/test/test_plru.py create mode 100644 ut_mem_block/dtlb/test/test_redirect.py create mode 100644 ut_mem_block/dtlb/test/test_sfence.py create mode 100644 ut_mem_block/dtlb/test/test_st_dtlb.py diff --git a/ut_mem_block/dtlb/ld_tlb/__init__.py b/ut_mem_block/dtlb/agent/__init__.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/__init__.py rename to ut_mem_block/dtlb/agent/__init__.py diff --git a/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py b/ut_mem_block/dtlb/agent/dtlb_agent.py similarity index 97% rename from ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py rename to ut_mem_block/dtlb/agent/dtlb_agent.py index 849be422..9f4c4b95 100644 --- a/ut_mem_block/dtlb/ld_tlb/agent/ld_dtlb_agent.py +++ b/ut_mem_block/dtlb/agent/dtlb_agent.py @@ -1,6 +1,6 @@ from toffee.agent import Agent, driver_method, monitor_method from toffee import Value -from ..bundle.ld_tlb_bundle import DTLBBundle, RequestorBundle, CSRBundle, PTWBundle, PMPBundle +from ..bundle.dtlb_bundle import DTLBBundle, RequestorBundle, CSRBundle, PTWBundle, PMPBundle def _canon_sv39_vaddr(va: int) -> int: """把 64 位 VA 规范化为 Sv39 canonical 形式(按 bit[38] 符号扩展)""" @@ -53,7 +53,7 @@ async def drive_request( req = self.requestor[port].req req.valid.value = 0 - req.bits_vaddr.value = canon & ((1 << 50) - 1) # 你的接口是 50 位,这里保守取低 50 位 + req.bits_vaddr.value = canon & ((1 << 39) - 1) # 你的接口是 50 位,这里保守取低 50 位 req.bits_fullva.value = fullva # 完整 64 位 req.bits_checkfullva.value = 1 if check_fullva else 0 @@ -62,7 +62,7 @@ async def drive_request( req.bits_hlvx.value = 1 if hlvx else 0 req.bits_kill.value = 1 if kill else 0 req.bits_isPrefetch.value = 1 if is_prefetch else 0 - req.bits_no_translate.value = 0 + req.bits_no_translate.value = 1 if no_translate else 0 req.bits_pmp_addr.value = pmp & ((1 << 48) - 1) @@ -148,7 +148,10 @@ async def set_ptw_resp(self, vaddr, paddr, level, *, ppn = (paddr >> 12) addr_low = vpn & 0b111 # vpn[2:0] entry_tag = vpn >> 3 # 与硬件压缩槽对齐 - entry_ppn = (ppn >> 3) & ((1 << 21) - 1) # 高 21 位(低 3 位走 ppn_low[]) + if s2xlate == 0: + entry_ppn = (ppn >> 3) & ((1 << 21) - 1) # 高 21 位(低 3 位走 ppn_low[]) + else: + entry_ppn = (ppn >> 3) & ((1 << 26) - 1) ppn_low_val = ppn & 0b111 # -------- (valid 暂时保持 0)-------- diff --git a/ut_mem_block/dtlb/ld_tlb/agent/__init__.py b/ut_mem_block/dtlb/bundle/__init__.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/agent/__init__.py rename to ut_mem_block/dtlb/bundle/__init__.py diff --git a/ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py b/ut_mem_block/dtlb/bundle/dtlb_bundle.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/bundle/ld_tlb_bundle.py rename to ut_mem_block/dtlb/bundle/dtlb_bundle.py diff --git a/ut_mem_block/dtlb/ld_tlb/bundle/__init__.py b/ut_mem_block/dtlb/env/__init__.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/bundle/__init__.py rename to ut_mem_block/dtlb/env/__init__.py diff --git a/ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py b/ut_mem_block/dtlb/env/dtlb_env.py similarity index 91% rename from ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py rename to ut_mem_block/dtlb/env/dtlb_env.py index d7ae09a4..2451002d 100644 --- a/ut_mem_block/dtlb/ld_tlb/env/dtlb_env.py +++ b/ut_mem_block/dtlb/env/dtlb_env.py @@ -1,7 +1,7 @@ # env/dtlb_env.py from toffee import Env -from ..bundle.ld_tlb_bundle import DTLBBundle -from ..agent.ld_dtlb_agent import DTLBAgent +from ..bundle.dtlb_bundle import DTLBBundle +from ..agent.dtlb_agent import DTLBAgent from .dtlb_mdl import DTLBPLRURefModel class DTLBEnv_PLRU(Env): @@ -9,8 +9,7 @@ def __init__(self, dut): super().__init__() self.dut = dut self.bundle = DTLBBundle.from_prefix("io_").bind(dut) - # 事务级 agent - self.req = DTLBAgent(self.bundle) + self.agent = DTLBAgent(self.bundle) self.mdl = DTLBPLRURefModel() self.attach(self.mdl) @@ -46,8 +45,7 @@ def __init__(self, dut): super().__init__() self.dut = dut self.bundle = DTLBBundle.from_prefix("io_").bind(dut) - # 事务级 agent - self.req = DTLBAgent(self.bundle) + self.agent = DTLBAgent(self.bundle) async def set_sv39_defaults(self): diff --git a/ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py b/ut_mem_block/dtlb/env/dtlb_mdl.py similarity index 98% rename from ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py rename to ut_mem_block/dtlb/env/dtlb_mdl.py index e3d43bf8..3c101f0f 100644 --- a/ut_mem_block/dtlb/ld_tlb/env/dtlb_mdl.py +++ b/ut_mem_block/dtlb/env/dtlb_mdl.py @@ -109,7 +109,7 @@ def __init__(self): self.plru = TreePLRU48() # ---------------- driver_hook #1:命中查询 ---------------- - @driver_hook(agent_name="req", driver_name="drive_request") + @driver_hook(agent_name="agent", driver_name="drive_request") def drive_request( self, port: int, @@ -136,7 +136,7 @@ def drive_request( return None # ---------------- driver_hook #2:PTW 回填(无 invalid 优先) ---------------- - @driver_hook(agent_name="req", driver_name="set_ptw_resp") + @driver_hook(agent_name="agent", driver_name="set_ptw_resp") def set_ptw_resp(self, vaddr, paddr, level, *, # S1/S2 选择 valid: bool = True, diff --git a/ut_mem_block/dtlb/ld_tlb/test/__init__.py b/ut_mem_block/dtlb/ld_tlb/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py b/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py deleted file mode 100644 index d4818d77..00000000 --- a/ut_mem_block/dtlb/ld_tlb/test/test_sfence.py +++ /dev/null @@ -1,332 +0,0 @@ -# -*- coding: utf-8 -*- -import toffee -import toffee_test -from .ld_tlb_fixture import dtlb_env - -LOAD = 0 -STORE = 1 - -async def _wait_ptw_req_and_capture(env, vaddr, max_cycles=32): - vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) - for _ in range(max_cycles): - for i in range(4): - req = env.bundle.ptw.req[i] - if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: - return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) - await env.bundle.step() - raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) - -def _canon_sv39_to_50b(va: int, page_align: bool) -> int: - low39 = va & ((1 << 39) - 1) - sign = (low39 >> 38) & 1 - upper = ((-sign) & ((1 << (50 - 39)) - 1)) << 39 - va50 = (upper | low39) & ((1 << 50) - 1) - if page_align: - va50 &= ~0xFFF - return va50 - -async def do_sfence(env, *, hv=False, hg=False, rs1=False, addr=0, rs2=False, id_=0, settle_cycles=10): - sf = env.bundle.sfence - sf.bits_hv.value = 1 if hv else 0 - sf.bits_hg.value = 1 if hg else 0 - sf.bits_rs1.value = 1 if rs1 else 0 - sf.bits_rs2.value = 1 if rs2 else 0 - - sf.bits_addr.value = _canon_sv39_to_50b(addr, page_align=rs1) - sf.bits_id.value = int(id_) & ((1 << 16) - 1) # VMA: ASID;GVMA: VMID;VVMA: 实际忽略 - sf.bits_flushPipe.value = 0 - - sf.valid.value = 1 - await env.bundle.step() - sf.valid.value = 0 - - # 给硬件若干拍时间完成写口失效/遍历 - for _ in range(settle_cycles): - await env.bundle.step() - - -# ========================= -# 1) SFENCE.VMA 全量清(非 G) -# ========================= -@toffee_test.testcase -async def test_sfence_vma_global_noG(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 0 - va = 0x0000_0000_8020_1000 - pa = 0x0000_0001_0000_9000 - asid = 0x11 - - csr = env.bundle.csr - csr.priv_virt.value = 0 - csr.Satp.mode.value = 8 - csr.Satp.asid.value = asid - await env.bundle.step() - - - - # miss → 回填(非 G)→ hit - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, va) - await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, - s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, - s2xlate=s2x) - expect = (pa & ~0xFFF) | (va & 0xFFF) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == expect - - # 全量清(rs1=0, rs2=0) - await do_sfence(env, hv=False, hg=False, rs1=False, rs2=False) - - # 应 miss - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 2) SFENCE.VMA 按 ASID 清 -# ========================= -@toffee_test.testcase -async def test_sfence_vma_by_asid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 0 - va = 0x0000_0000_8020_1000 - pa = 0x0000_0001_0000_9000 - asid = 0x22 - - csr = env.bundle.csr - csr.priv_virt.value = 0 - csr.Satp.mode.value = 8 - csr.Satp.asid.value = asid - await env.bundle.step() - - - - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, va) - await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, - s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, - s2xlate=s2x) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) - - # 按当前 satp.asid 清(id 用 CSR.Satp.asid) - await do_sfence(env, hv=False, hg=False, rs1=False, rs2=True, id_=asid) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 3) SFENCE.VMA 按 VA 清 -# ========================= -@toffee_test.testcase -async def test_sfence_vma_by_va(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 1 - va = 0x0000_0000_8020_1000 - pa = 0x0000_0001_0000_9000 - asid = 0x33 - - csr = env.bundle.csr - csr.priv_virt.value = 0 - csr.Satp.mode.value = 8 - csr.Satp.asid.value = asid - await env.bundle.step() - - - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, va) - await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, - s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, - s2xlate=s2x) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) - - await do_sfence(env, hv=False, hg=False, rs1=True, addr=va, rs2=False) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 4) SFENCE.VMA 按 (VA, ASID) 清 -# ========================= -@toffee_test.testcase -async def test_sfence_vma_by_va_asid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 2 - va = 0x0000_0000_8020_1000 - pa = 0x0000_0001_0000_9000 - asid = 0x44 - - csr = env.bundle.csr - csr.priv_virt.value = 0 - csr.Satp.mode.value = 8 - csr.Satp.asid.value = asid - await env.bundle.step() - - - - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, va) - await env.req.set_ptw_resp(vaddr=va, paddr=pa, level=0, - s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, - s2xlate=s2x) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) - - await do_sfence(env, hv=False, hg=False, rs1=True, addr=va, rs2=True, id_=asid) - assert await env.req.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 5) HFENCE.VVMA:按 VMID(全 GVA) -# ========================= -@toffee_test.testcase -async def test_hfence_vvma_by_vmid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 0 - gva = 0x0000_0000_8020_1000 - gpa = 0x0000_0001_0000_9000 - asid = 0x12 - vmid = 0xAA - - csr = env.bundle.csr - csr.priv_virt.value = 1 - csr.Vsatp.mode.value = 8 # VS-S1 开启 - csr.HGatp.mode.value = 0 # S2 关闭(only VS-S1) - csr.Vsatp.asid.value = asid - csr.HGatp.vmid.value = vmid # 关键:VVMA 用 CSR.HGATP.vmid 过滤 - await env.bundle.step() - - - - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, gva) - await env.req.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, - s1_asid=asid, s1_vmid=vmid, - s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, - s2xlate=s2x) - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) - - # VVMA:hv=1,通常按 VMID 过滤需 rs2=1;VMID 来源于 CSR.HGATP.vmid(id 忽略) - await do_sfence(env, hv=True, hg=False, rs1=False, rs2=True, id_=vmid) - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 6) HFENCE.VVMA:按 (GVA, VMID) 清 -# ========================= -@toffee_test.testcase -async def test_hfence_vvma_by_gva_vmid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 1 - gva = 0x0000_0000_8020_1000 - gpa = 0x0000_0001_0000_9000 - asid = 0x21 - vmid = 0xBB - - csr = env.bundle.csr - csr.priv_virt.value = 1 - csr.Vsatp.mode.value = 8 - csr.HGatp.mode.value = 0 - csr.Vsatp.asid.value = asid - csr.HGatp.vmid.value = vmid - await env.bundle.step() - - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None - _, s2x, _ = await _wait_ptw_req_and_capture(env, gva) - await env.req.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, - s1_asid=asid, s1_vmid=vmid, - s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, - s2xlate=s2x) - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) - - await do_sfence(env, hv=True, hg=False, rs1=True, addr=gva, rs2=True, id_=vmid) - assert await env.req.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 7) HFENCE.GVMA:按 VMID 清 S2(GPA 全范围) -# ========================= -@toffee_test.testcase -async def test_hfence_gvma_by_vmid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 2 - gpa_in = 0x0000_0000_8020_1000 - hpa = 0x0000_0002_2000_0000 - vmid = 0x66 - - csr = env.bundle.csr - csr.priv_virt.value = 1 - csr.Vsatp.mode.value = 0 - csr.HGatp.mode.value = 8 - csr.HGatp.vmid.value = vmid - await env.bundle.step() - - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None - _, s2x, getGpa_req = await _wait_ptw_req_and_capture(env, gpa_in) - await env.req.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, - s2xlate=s2x, getGpa=getGpa_req, - s2_tag=(gpa_in >> 12) & ((1<<27)-1), - s2_ppn=(hpa >> 12), s2_level=0, - s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) - - # GVMA:hg=1,按 VMID(来自 bits_id)清 S2 - await do_sfence(env, hv=False, hg=True, rs1=False, rs2=True, id_=vmid) - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None - - -# ========================= -# 8) HFENCE.GVMA:按 (GPA, VMID) 清 S2 -# ========================= -@toffee_test.testcase -async def test_hfence_gvma_by_gpa_vmid(dtlb_env): - env = dtlb_env - env.dut.reset.value = 1; await env.bundle.step() - env.dut.reset.value = 0; await env.bundle.step() - await env.set_sv39_defaults(); await env.bundle.step() - - port = 3 - gpa_in = 0x0000_0000_8020_1000 - hpa = 0x0000_0002_2000_1000 - vmid = 0x77 - - csr = env.bundle.csr - csr.priv_virt.value = 1 - csr.Vsatp.mode.value = 0 - csr.HGatp.mode.value = 8 - csr.HGatp.vmid.value = vmid - await env.bundle.step() - - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None - _, s2x, getGpa_req = await _wait_ptw_req_and_capture(env, gpa_in) - await env.req.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, - s2xlate=s2x, getGpa=getGpa_req, - s2_tag=(gpa_in >> 12) & ((1<<27)-1), - s2_ppn=(hpa >> 12), s2_level=0, - s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) - - await do_sfence(env, hv=False, hg=True, rs1=True, addr=gpa_in, rs2=True, id_=vmid) - assert await env.req.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None diff --git a/ut_mem_block/dtlb/pf_tlb/__init__.py b/ut_mem_block/dtlb/pf_tlb/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/pf_tlb/agent/__init__.py b/ut_mem_block/dtlb/pf_tlb/agent/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/pf_tlb/bundle/__init__.py b/ut_mem_block/dtlb/pf_tlb/bundle/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/pf_tlb/env/__init__.py b/ut_mem_block/dtlb/pf_tlb/env/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/pf_tlb/scripts/__init__.py b/ut_mem_block/dtlb/pf_tlb/scripts/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/pf_tlb/scripts/bundle_code_gen.py b/ut_mem_block/dtlb/pf_tlb/scripts/bundle_code_gen.py deleted file mode 100644 index 66b24fe4..00000000 --- a/ut_mem_block/dtlb/pf_tlb/scripts/bundle_code_gen.py +++ /dev/null @@ -1,160 +0,0 @@ -import re - -from toffee import Bundle - - -def __gen_bundle_code(bundle_name: str, signals, max_width: int): - """ - Generates bundle code using a list of signals. - - Args: - bundle_name: The name of the bundle. - signals: The list of signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals_num = len(signals) - - if signals_num == 0: - end_code = f" = Signal()" - else: - end_code = f" = Signals({signals_num})" - - code = f"from toffee import Bundle\nfrom toffee import Signals, Signal\n\nclass {bundle_name}(Bundle):\n" - code_line = "\t" - index = 0 - - TAB_SIZE = 4 - while index < signals_num: - code_line = "\t" - - code_line += f"{signals[index]}, " - current_width = TAB_SIZE + len(signals[index]) + 2 + 1 - index += 1 - - while ( - index < signals_num and current_width + len(signals[index]) + 2 <= max_width - ): - code_line += f"{signals[index]}, " - current_width += len(signals[index]) + 2 - index += 1 - - if index == signals_num: - code_line = code_line[:-2] - current_width -= 3 - - if current_width + len(end_code) <= max_width: - code_line += end_code + "\n" - else: - code_line += " \\\n\t" + end_code[1:] + "\n" - else: - code_line += "\\\n" - - code += code_line - - return code - - -def gen_bundle_code_from_prefix( - bundle_name: str, dut, prefix: str = "", max_width: int = 120 -): - """ - Generates a bundle using all the signals with the specified prefix. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - prefix: The prefix of the signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - for dict in Bundle.dut_all_signals(dut): - name = dict["name"] - if name.startswith(prefix): - signals.append(name[len(prefix) :]) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found with prefix {prefix}" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f'bundle = {bundle_name}.from_prefix("{prefix}")\n' - - return code - - -def gen_bundle_code_from_regex(bundle_name: str, dut, regex: str, max_width: int = 120): - """ - Generates a bundle using all the signals that match the specified regex. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - regex: The regex of the signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - for dict in Bundle.dut_all_signals(dut): - name = dict["name"] - match = re.search(regex, name) - - if match is not None: - groups = ["" if x is None else x for x in match.groups()] - name = "".join(groups) - signals.append(name) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found with regex {regex}" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f'bundle = {bundle_name}.from_regex(r"{regex}")\n' - - return code - - -def gen_bundle_code_from_dict(bundle_name: str, dut, dict: dict, max_width: int = 120): - """ - Generates a bundle using a dictionary. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - dict: The dictionary of signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - dut_signals = [signal["name"] for signal in Bundle.dut_all_signals(dut)] - for key, value in dict.items(): - if value in dut_signals: - signals.append(key) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found in the dictionary" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f"bundle = {bundle_name}.from_dict({dict})\n" - - return code diff --git a/ut_mem_block/dtlb/pf_tlb/test/__init__.py b/ut_mem_block/dtlb/pf_tlb/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/ld_tlb/env/__init__.py b/ut_mem_block/dtlb/scripts/__init__.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/env/__init__.py rename to ut_mem_block/dtlb/scripts/__init__.py diff --git a/ut_mem_block/dtlb/ld_tlb/scripts/bundle_code_gen.py b/ut_mem_block/dtlb/scripts/bundle_code_gen.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/scripts/bundle_code_gen.py rename to ut_mem_block/dtlb/scripts/bundle_code_gen.py diff --git a/ut_mem_block/dtlb/st_tlb/__init__.py b/ut_mem_block/dtlb/st_tlb/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/st_tlb/agent/__init__.py b/ut_mem_block/dtlb/st_tlb/agent/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/st_tlb/bundle/__init__.py b/ut_mem_block/dtlb/st_tlb/bundle/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/st_tlb/env/__init__.py b/ut_mem_block/dtlb/st_tlb/env/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/st_tlb/scripts/__init__.py b/ut_mem_block/dtlb/st_tlb/scripts/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/st_tlb/scripts/bundle_code_gen.py b/ut_mem_block/dtlb/st_tlb/scripts/bundle_code_gen.py deleted file mode 100644 index 66b24fe4..00000000 --- a/ut_mem_block/dtlb/st_tlb/scripts/bundle_code_gen.py +++ /dev/null @@ -1,160 +0,0 @@ -import re - -from toffee import Bundle - - -def __gen_bundle_code(bundle_name: str, signals, max_width: int): - """ - Generates bundle code using a list of signals. - - Args: - bundle_name: The name of the bundle. - signals: The list of signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals_num = len(signals) - - if signals_num == 0: - end_code = f" = Signal()" - else: - end_code = f" = Signals({signals_num})" - - code = f"from toffee import Bundle\nfrom toffee import Signals, Signal\n\nclass {bundle_name}(Bundle):\n" - code_line = "\t" - index = 0 - - TAB_SIZE = 4 - while index < signals_num: - code_line = "\t" - - code_line += f"{signals[index]}, " - current_width = TAB_SIZE + len(signals[index]) + 2 + 1 - index += 1 - - while ( - index < signals_num and current_width + len(signals[index]) + 2 <= max_width - ): - code_line += f"{signals[index]}, " - current_width += len(signals[index]) + 2 - index += 1 - - if index == signals_num: - code_line = code_line[:-2] - current_width -= 3 - - if current_width + len(end_code) <= max_width: - code_line += end_code + "\n" - else: - code_line += " \\\n\t" + end_code[1:] + "\n" - else: - code_line += "\\\n" - - code += code_line - - return code - - -def gen_bundle_code_from_prefix( - bundle_name: str, dut, prefix: str = "", max_width: int = 120 -): - """ - Generates a bundle using all the signals with the specified prefix. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - prefix: The prefix of the signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - for dict in Bundle.dut_all_signals(dut): - name = dict["name"] - if name.startswith(prefix): - signals.append(name[len(prefix) :]) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found with prefix {prefix}" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f'bundle = {bundle_name}.from_prefix("{prefix}")\n' - - return code - - -def gen_bundle_code_from_regex(bundle_name: str, dut, regex: str, max_width: int = 120): - """ - Generates a bundle using all the signals that match the specified regex. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - regex: The regex of the signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - for dict in Bundle.dut_all_signals(dut): - name = dict["name"] - match = re.search(regex, name) - - if match is not None: - groups = ["" if x is None else x for x in match.groups()] - name = "".join(groups) - signals.append(name) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found with regex {regex}" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f'bundle = {bundle_name}.from_regex(r"{regex}")\n' - - return code - - -def gen_bundle_code_from_dict(bundle_name: str, dut, dict: dict, max_width: int = 120): - """ - Generates a bundle using a dictionary. - - Args: - bundle_name: The name of the bundle. - dut: The DUT. - dict: The dictionary of signals. - max_width: The maximum width of the line. - - Returns: - The bundle code. - """ - - signals = [] - - dut_signals = [signal["name"] for signal in Bundle.dut_all_signals(dut)] - for key, value in dict.items(): - if value in dut_signals: - signals.append(key) - - signals.sort() - signals_num = len(signals) - assert signals_num > 0, f"No signals found in the dictionary" - - code = __gen_bundle_code(bundle_name, signals, max_width) - code += "\n" - code += f"bundle = {bundle_name}.from_dict({dict})\n" - - return code diff --git a/ut_mem_block/dtlb/st_tlb/test/__init__.py b/ut_mem_block/dtlb/st_tlb/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ut_mem_block/dtlb/ld_tlb/scripts/__init__.py b/ut_mem_block/dtlb/test/__init__.py similarity index 100% rename from ut_mem_block/dtlb/ld_tlb/scripts/__init__.py rename to ut_mem_block/dtlb/test/__init__.py diff --git a/ut_mem_block/dtlb/test/funcov_dtlb.py b/ut_mem_block/dtlb/test/funcov_dtlb.py new file mode 100644 index 00000000..bb4ab332 --- /dev/null +++ b/ut_mem_block/dtlb/test/funcov_dtlb.py @@ -0,0 +1,178 @@ +from dut.TLBNonBlock import DUTTLBNonBlock +import toffee.funcov as fc +from toffee.funcov import CovGroup + +def init_dtlb_funcov(dut, g: fc.CovGroup): + # ---------------- 功能点1:接收请求(valid/resp/miss-hit) ---------------- + for i in range(4): + g.add_watch_point(dut, { + f"F1.{i}.req_valid": lambda d, i=i: getattr(d, f"io_requestor_{i}_req_valid").value == 1, + f"F1.{i}.resp_valid": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_valid").value == 1, + f"F1.{i}.hit": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_valid").value == 1 + and getattr(d, f"io_requestor_{i}_resp_bits_miss").value == 0, + f"F1.{i}.miss": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_valid").value == 1 + and getattr(d, f"io_requestor_{i}_resp_bits_miss").value == 1, + }, name=f"F1_REQ_RESP_P{i}") + + # ---------------- 功能点2:miss 处理 & PTW 交互 ------------------------- + # 各端口 PTW 请求 valid(valid-ready 这层多数后端抽象不到,这里只看 valid) + for i in range(4): + g.add_watch_point(dut, { + f"F2.{i}.ptw_req_valid": lambda d, i=i: getattr(d, f"io_ptw_req_{i}_valid").value == 1, + }, name=f"F2_PTW_REQ_P{i}") + + # s2xlate 模式覆盖:0(bare?) / 1(onlyS1) / 2(onlyS2)(以你的 RTL 约定为准) + g.add_watch_point(dut, { + "F2.s2xlate==0": lambda d: any(getattr(d, f"io_ptw_req_{i}_valid").value == 1 + and getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 0 for i in range(4)), + "F2.s2xlate==1": lambda d: any(getattr(d, f"io_ptw_req_{i}_valid").value == 1 + and getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 1 for i in range(4)), + "F2.s2xlate==2": lambda d: any(getattr(d, f"io_ptw_req_{i}_valid").value == 1 + and getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 2 for i in range(4)), + "F2.s2xlate==3": lambda d: any(getattr(d, f"io_ptw_req_{i}_valid").value == 1 + and getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 3 for i in range(4)), + }, name="F2_S2XLATE_MODES") + + # getGpa 路径(GPF 需要先走 getGpa,不入 TLBuffer 的 resp) + g.add_watch_point(dut, { + "F2.getGpa==1_seen": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_getGpa").value == 1 for i in range(4)), + }, name="F2_GETGPA") + + # PTW resp/fault 标志 + g.add_watch_point(dut, { + "F2.ptw_resp_valid": lambda d: getattr(d, "io_ptw_resp_valid").value == 1, + "F10.s1_pf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_pf").value == 1, + "F10.s1_af": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_af").value == 1, + "F10.s2_gpf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s2_gpf").value == 1, + }, name="F2_PTW_RESP_FAULTS") + + # ---------------- 功能点3:hit 返回(paddr/gpaddr/页内偏移一致) ---------- + for i in range(4): + g.add_watch_point(dut, { + f"F3.{i}.paddr_seen": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_valid").value == 1 \ + and getattr(d, f"io_requestor_{i}_resp_bits_miss").value == 0 \ + and getattr(d, f"io_requestor_{i}_resp_bits_paddr_0").value != 0, + }, name=f"F3_RET_P{i}") + for i in range(3): + g.add_watch_point(dut, { + f"F3.{i}.gpaddr_seen": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_valid").value == 1 \ + and getattr(d, f"io_requestor_{i}_resp_bits_gpaddr_0").value != 0, + }, name=f"F3_RET_gpaddr_P{i}") + + + + # ---------------- 功能点6:TLB 压缩(valididx 统计) -------------------- + # io_ptw_resp_bits_s1_valididx_0..7 为 8 位 one-hot/稀疏集合 + def _sum_valididx(d): + return sum(getattr(d, f"io_ptw_resp_bits_s1_valididx_{k}").value for k in range(8)) + g.add_watch_point(dut, { + "F6.valididx_onehot": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 and _sum_valididx(d) == 1, + "F6.valididx_full8": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 and _sum_valididx(d) == 8, + "F6.valididx_mid": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 and 1 < _sum_valididx(d) < 8, + }, name="F6_COMPRESSION_IDX") + + # ---------------- 功能点7:刷新(sfence & 管道) ----------------------- + g.add_watch_point(dut, { + "F7.sfence_all(0,0)": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_rs1").value == 0 + and getattr(d, "io_sfence_bits_rs2").value == 0, + "F7.sfence_by_va(1,0)": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_rs1").value == 1 + and getattr(d, "io_sfence_bits_rs2").value == 0, + "F7.sfence_by_id(0,1)": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_rs1").value == 0 + and getattr(d, "io_sfence_bits_rs2").value == 1, + "F7.sfence_va_id(1,1)": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_rs1").value == 1 + and getattr(d, "io_sfence_bits_rs2").value == 1, + "F7.hv==1": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_hv").value == 1, + "F7.hg==1": lambda d: getattr(d, "io_sfence_valid").value == 1 + and getattr(d, "io_sfence_bits_hg").value == 1, + }, name="F7_SFENCE") + + # ---------------- 功能点8:Reset -------------------------------------- + g.add_watch_point(dut, { + "F8.reset_high": lambda d: getattr(d, "reset").value == 1, + "F8.reset_low": lambda d: getattr(d, "reset").value == 0, + }, name="F8_RESET") + + # ---------------- 功能点9:权限检查(CSR + resp 异常位) ---------------- + g.add_watch_point(dut, { + "F9.mxr==1": lambda d: getattr(d, "io_csr_priv_mxr").value == 1, + "F9.sum==1": lambda d: getattr(d, "io_csr_priv_sum").value == 1, + "F9.vmxr==1": lambda d: getattr(d, "io_csr_priv_vmxr").value == 1, + "F9.vsum==1": lambda d: getattr(d, "io_csr_priv_vsum").value == 1, + }, name="F9_PRIV_SWITCHES") + for i in range(4): + g.add_watch_point(dut, { + f"F9.{i}.pf.ld": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_bits_excp_0_pf_ld").value == 1, + f"F9.{i}.af.ld": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_bits_excp_0_af_ld").value == 1, + }, name=f"F9_EXCP_ld_P{i}") + g.add_watch_point(dut, { + f"F9.0.pf.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_pf_st").value == 1, + f"F9.0.af.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_af_st").value == 1, + }, name=f"F9_EXCP_st_P0") + # ---------------- 功能点10:异常(GPF/GAF) ---------------------------- + for i in range(4): + g.add_watch_point(dut, { + f"F10.{i}.gpf.ld": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_bits_excp_0_gpf_ld").value == 1, + }, name=f"F10_GPF_ld_P{i}") + g.add_watch_point(dut, { + f"F9.0.gpf.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_gpf_st").value == 1, + }, name=f"F10_GPF_st_P0") + + # ---------------- 功能点11:隔离(ASID/VMID/changed) ------------------- + g.add_watch_point(dut, { + "F11.asid!=0": lambda d: getattr(d, "io_csr_satp_asid").value != 0, + "F11.vmid!=0": lambda d: getattr(d, "io_csr_hgatp_vmid").value != 0, + "F11.satp.changed": lambda d: getattr(d, "io_csr_satp_changed").value == 1, + "F11.vsatp.changed": lambda d: getattr(d, "io_csr_vsatp_changed").value == 1, + "F11.hgatp.changed": lambda d: getattr(d, "io_csr_hgatp_changed").value == 1, + }, name="F11_ISOLATION") + + # ---------------- 功能点12:并行访问(同拍多端口) --------------------- + g.add_watch_point(dut, { + "F12.simul_req>=2": lambda d: sum(getattr(d, f"io_requestor_{i}_req_valid").value for i in range(4)) >= 2, + "F12.simul_miss>=2": lambda d: sum( + getattr(d, f"io_requestor_{i}_resp_valid").value == 1 + and getattr(d, f"io_requestor_{i}_resp_bits_miss").value == 1 + for i in range(4) + ) >= 2, + "F12.simul_hit>=2": lambda d: sum( + getattr(d, f"io_requestor_{i}_resp_valid").value == 1 + and getattr(d, f"io_requestor_{i}_resp_bits_miss").value == 0 + for i in range(4) + ) >= 2, + }, name="F12_PARALLEL") + + # ---------------- 功能点13:大小页(level 分布) ------------------------ + g.add_watch_point(dut, { + "F13.s1_level==0": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_entry_level").value == 0, + "F13.s1_level==1": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_entry_level").value == 1, + "F13.s1_level==2": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_entry_level").value == 2, + "F13.s2_level==0": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s2_entry_level").value == 0, + "F13.s2_level==1": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s2_entry_level").value == 1, + "F13.s2_level==2": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s2_entry_level").value == 2, + }, name="F13_LEVELS") + + # ---------------- 功能点14: redirect ------------------------ + g.add_watch_point(dut, { + "F14.redirect_seen": lambda d: getattr(d, "io_redirect_valid").value == 1, + "F14.redirect_bits_level==0": lambda d: getattr(d, "io_redirect_valid").value == 1 + and getattr(d, "io_redirect_bits_level").value == 0, + "F14.redirect_bits_level==1": lambda d: getattr(d, "io_redirect_valid").value == 1 + and getattr(d, "io_redirect_bits_level").value == 1, + + }, name="F14_REDIRECT") + + return g \ No newline at end of file diff --git a/ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py b/ut_mem_block/dtlb/test/ld_tlb_fixture.py similarity index 90% rename from ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py rename to ut_mem_block/dtlb/test/ld_tlb_fixture.py index 84d52722..77965c66 100644 --- a/ut_mem_block/dtlb/ld_tlb/test/ld_tlb_fixture.py +++ b/ut_mem_block/dtlb/test/ld_tlb_fixture.py @@ -1,14 +1,15 @@ import toffee import toffee_test +import toffee.funcov as fc from ..env.dtlb_env import DTLBEnv, DTLBEnv_PLRU from dut.TLBNonBlock import DUTTLBNonBlock +from .funcov_dtlb import init_dtlb_funcov @toffee_test.fixture async def dtlb_env_plru(toffee_request: toffee_test.ToffeeRequest): toffee.setup_logging(toffee.ERROR) dut = toffee_request.create_dut(DUTTLBNonBlock) - dut.InitClock("clock") toffee.start_clock(dut) @@ -30,24 +31,24 @@ async def dtlb_env_plru(toffee_request: toffee_test.ToffeeRequest): except asyncio.CancelledError: pass - +g = fc.CovGroup("DTLB_FCOV_CASE") @toffee_test.fixture async def dtlb_env(toffee_request: toffee_test.ToffeeRequest): toffee.setup_logging(toffee.ERROR) dut = toffee_request.create_dut(DUTTLBNonBlock) - dut.InitClock("clock") toffee.start_clock(dut) env = DTLBEnv(dut) + toffee_request.add_cov_groups(init_dtlb_funcov(dut, g)) # env.req.start_monitor("monitor_req", 50) # env.req.start_monitor("monitor_resp", 50) # env.req.start_monitor("monitor_ptw_resp", 50) # env.req.start_monitor("monitor_ptw_req", 50) - yield env + import asyncio loop = asyncio.get_event_loop() for task in asyncio.all_tasks(loop): diff --git a/ut_mem_block/dtlb/test/test_ld_dtlb.py b/ut_mem_block/dtlb/test/test_ld_dtlb.py new file mode 100644 index 00000000..dfee0950 --- /dev/null +++ b/ut_mem_block/dtlb/test/test_ld_dtlb.py @@ -0,0 +1,906 @@ +import toffee +import toffee_test +import random +from .ld_tlb_fixture import dtlb_env + +LOAD = 0 + +async def _wait_ptw_req_and_capture(dtlb_env, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = dtlb_env.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await dtlb_env.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) + +def _canon_sv39_vaddr(va: int) -> int: + """把 64 位 VA 规范化为 Sv39 canonical 形式(按 bit[38] 符号扩展)""" + va = int(va) & ((1 << 64) - 1) + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (64 - 39)) - 1)) << 39 + return (upper | low39) & ((1 << 64) - 1) +@toffee_test.testcase +async def test_ptwresp_s1_pf_propagates_to_requestor(dtlb_env): + for i in range(4): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + await dtlb_env.bundle.step() + + port =i + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s1_pf=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_pf_ld.value) == 1 + +@toffee_test.testcase +async def test_ptwresp_s1_af_propagates_to_requestor(dtlb_env): + for i in range(4): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + await dtlb_env.bundle.step() + + port = i + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s1_af=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_af_ld.value) == 1 + +@toffee_test.testcase +async def test_ptwresp_s2_gpf_propagates_to_requestor(dtlb_env): + for i in range(4): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp(vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_gpf=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_gpf_ld.value) == 1 + +@toffee_test.testcase +async def test_priv_mxr_allows_read_exec_only(dtlb_env): + + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = 0x1 + csr.priv_mxr.value = 0 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_asid=0x1, + s1_perm_r=False, s1_perm_x=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + csr.priv_mxr.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = 0x2 + csr.priv_dmode.value = 1 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_asid=0x2, + s1_perm_u=True, s1_perm_r=True, s1_perm_a=True, + s2xlate=s2x + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + csr.priv_sum.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_priv_vmxr_vs_allows_read_exec_only(dtlb_env): + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = 0x12 + csr.HGatp.vmid.value = 0xA + await dtlb_env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_3000 + gpa = 0x0000_0002_2222_3000 + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_asid=0x12, s1_vmid=0xA, + s1_perm_r=False, s1_perm_x=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + csr.priv_vmxr.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_priv_vsum_vs_supervisor_can_read_user_page(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = 0x34 + csr.HGatp.vmid.value = 0xB + csr.priv_dmode.value = 1 + await dtlb_env.bundle.step() + + port = 1 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_asid=0x34, s1_vmid=0xB, + s1_perm_u=True, s1_perm_r=True, s1_perm_a=True, + s2xlate=s2x + ) + + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + assert r1 == -1 + + csr.priv_vsum.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_asid_isolation_bare(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = 0x10 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_asid=0x10, s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + csr.Satp.asid.value = 0x21 + csr.Satp.changed.value = True + await dtlb_env.bundle.step() + csr.Satp.changed.value = False + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r2 is None + +@toffee_test.testcase +async def test_asid_isolation_onlyStage1(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = 0x33 + csr.HGatp.vmid.value = 0xA + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_asid=0x33, s1_vmid=0xA, s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + + csr.Vsatp.asid.value = 0x44 + csr.Vsatp.changed.value = True + await dtlb_env.bundle.step() + csr.Vsatp.changed.value = False + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r2 is None + + csr.Vsatp.asid.value = 0x33 + csr.HGatp.vmid.value = 0xB + csr.Vsatp.changed.value = True + csr.HGatp.changed.value = True + await dtlb_env.bundle.step() + csr.Vsatp.changed.value = False + csr.HGatp.changed.value = False + + r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r3 is None + +@toffee_test.testcase +async def test_vmid_isolation_onlyStage2(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = 0x55 + await dtlb_env.bundle.step() + + port = 0 + gpa_in = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa_in, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=0x55, s2_perm_r=True, s2_perm_a=True + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) + expect = (hpa & ~0xFFF) | (gpa_in & 0xFFF) + assert r1 == expect + + csr.HGatp.vmid.value = 0x66 + csr.HGatp.changed.value = True + await dtlb_env.bundle.step() + csr.HGatp.changed.value = False + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) + assert r2 is None + +@toffee_test.testcase +async def test_hit_onlyStage1(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD ,return_on_miss=True) + assert r0 is None + + ptw_port, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x, getGpa=getGpa_req + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + + +@toffee_test.testcase +async def test_hit_onlyStage2_4k(dtlb_env): + + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 1 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_r=True, s2_perm_a=True + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) + expect = (hpa & ~0xFFF) | (gpa & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_onlyStage2_2m(dtlb_env): + + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 1 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=1, + s2_perm_r=True, s2_perm_a=True + ) + for off in (0x000, 0x1000, 0x1FF000): + va = gpa + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + mask = (1 << 21) - 1 + expect = (hpa & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_onlyStage2_1g(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 1 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=2, + s2_perm_r=True, s2_perm_a=True + ) + for off in (0x0, 0x21_000, 0x3FF_F000): + va = gpa + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + mask = (1 << 30) - 1 + expect = (hpa & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_allStage(dtlb_env): + + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 2 + gva = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 -1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x, getGpa=getGpa_ptw, + s2_tag=(gpa>>12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_r=True, s2_perm_a=True + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) + expect = (hpa & ~0xFFF) | (gva & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_allStage_with_getGpa(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + gva = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 -1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=LOAD, return_on_miss=True) + _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) + + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x, getGpa=getGpa_ptw, + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_r=False, s2_perm_a=True + ) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=LOAD) + + _, s2x_req, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gva) + assert getGpa_req == 1 + + +@toffee_test.testcase +async def test_parallel_simul_req_miss(dtlb_env): + """ + 覆盖 F12.simul_req>=2:同一拍向多个端口同时打 req.valid=1 + """ + requestor = dtlb_env.bundle.requestor + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + VA0 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA1 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA2 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + + requestor[0].req.valid.value = 1 + requestor[0].req.bits_vaddr.value = VA0 + requestor[0].req.bits_fullva.value = VA0 + requestor[0].req.bits_cmd.value = LOAD + requestor[0].req.bits_no_translate.value = 0 + + requestor[1].req.valid.value = 1 + requestor[1].req.bits_vaddr.value = VA1 + requestor[1].req.bits_fullva.value = VA1 + requestor[1].req.bits_cmd.value = LOAD + requestor[1].req.bits_no_translate.value = 0 + + requestor[2].req.valid.value = 1 + requestor[2].req.bits_vaddr.value = VA2 + requestor[2].req.bits_fullva.value = VA2 + requestor[2].req.bits_cmd.value = LOAD + requestor[2].req.bits_no_translate.value = 0 + await dtlb_env.bundle.step() + requestor[0].req.valid.value = 0 + requestor[1].req.valid.value = 0 + requestor[2].req.valid.value = 0 + await dtlb_env.bundle.step() + + +@toffee_test.testcase +async def test_parallel_simul_req_hit(dtlb_env): + requestor = dtlb_env.bundle.requestor + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + VA0 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA1 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA2 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + PA0 = random.randint(2 ** 12, 2** 36 - 1) + PA1 = random.randint(2 ** 12, 2** 36 - 1) + PA2 = random.randint(2 ** 12, 2** 36 - 1) + + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=LOAD) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA0,paddr=PA0,level=0) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=LOAD) == ((VA0 & (0xFFF)) | (PA0 & ~(0xFFF))) + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA1, cmd=LOAD) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA1,paddr=PA1,level=0) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA1, cmd=LOAD) == ((VA1 & (0xFFF)) | (PA1 & ~(0xFFF))) + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA2, cmd=LOAD) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA2,paddr=PA2,level=0) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA2, cmd=LOAD) == ((VA2 & (0xFFF)) | (PA2 & ~(0xFFF))) + await dtlb_env.bundle.step() + fullva_0 = int(VA0) & ((1 << 64) - 1) # 完整 64 位 + VA0 = _canon_sv39_vaddr(fullva_0) # Sv39 规范化(再按端口位宽截取) + requestor[0].req.valid.value = 1 + requestor[0].req.bits_vaddr.value = VA0 + requestor[0].req.bits_fullva.value = fullva_0 + requestor[0].req.bits_cmd.value = LOAD + requestor[0].req.bits_no_translate.value = 0 + fullva_1 = int(VA1) & ((1 << 64) - 1) # 完整 64 位 + VA1 = _canon_sv39_vaddr(fullva_1) # Sv39 规范化(再按端口位宽截取) + requestor[1].req.valid.value = 1 + requestor[1].req.bits_vaddr.value = VA1 + requestor[1].req.bits_fullva.value = fullva_1 + requestor[1].req.bits_cmd.value = LOAD + requestor[1].req.bits_no_translate.value = 0 + fullva_2 = int(VA2) & ((1 << 64) - 1) # 完整 64 位 + VA2 = _canon_sv39_vaddr(fullva_2) # Sv39 规范化(再按端口位宽截取) + requestor[2].req.valid.value = 1 + requestor[2].req.bits_vaddr.value = VA2 + requestor[2].req.bits_fullva.value = fullva_2 + requestor[2].req.bits_cmd.value = LOAD + requestor[2].req.bits_no_translate.value = 0 + + await dtlb_env.bundle.step() + + requestor[0].req.valid.value = 0 + requestor[1].req.valid.value = 0 + requestor[2].req.valid.value = 0 + await dtlb_env.bundle.step() +@toffee_test.testcase +async def test_store_2mb_page(dtlb_env): + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) + pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=va_base, paddr=pa_base, level=1, s1_asid=0, + s1_ppn_low=[0]*8, s1_valididx=[1]*8, s1_pteidx=[0]*8 + ) + for off in (0x000, 0x1000, 0x1FF000): + va = va_base + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + mask = (1 << 21) - 1 + expect = (pa_base & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_store_1gb_page(dtlb_env): + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) + pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=va_base, paddr=pa_base, level=2, s1_asid=0, + s1_ppn_low=[0]*8, s1_valididx=[1]*8, s1_pteidx=[0]*8 + ) + + for off in (0x0, 0x21_000, 0x3FF_F000): + va = va_base + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + mask = (1 << 30) - 1 + expect = (pa_base & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_express_random(dtlb_env): + + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + vpn_low = (va >> 12) & 0x7 + rand_valididx = [0]*8 + rand_ppn_low = [0]*8 + pteidx = [0]*8 + for i in range(8): + rand_valididx[i] = random.randint(0,1) + rand_ppn_low[i] = i + rand_valididx[vpn_low] = 1 + pteidx[vpn_low] = 1 + await dtlb_env.agent.set_ptw_resp( + vaddr=va, + paddr=pa, + level=0, + s1_asid=0, + s1_ppn_low=rand_ppn_low, + s1_valididx=rand_valididx, + s1_pteidx=pteidx + ) + va_base = va & ~((1<<15)-1) + pa_base = pa & ~((1<<15)-1) + for i in range(8): + va = va_base | (i << 12) + pa = pa_base | (rand_ppn_low[i] << 12) + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + if rand_valididx[i] != 0: + expect = (pa & ~0xFFF) | (va & 0xFFF) + else: + expect = None + assert r1 == expect + +@toffee_test.testcase +async def test_express_full(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + vpn_low = (va >> 12) & 0x7 + pteidx = [0]*8 + pteidx[vpn_low] = 1 + await dtlb_env.agent.set_ptw_resp( + vaddr=va, + paddr=pa, + level=0, + s1_asid=0, + s1_ppn_low=[0,1,2,3,4,5,6,7], + s1_valididx=[1,1,1,1,1,1,1,1], + s1_pteidx=pteidx + ) + va_base = va & ~((1<<15)-1) + pa_base = pa & ~((1<<15)-1) + for i in range(8): + va = va_base | (i << 12) + pa = pa_base | (i << 12) + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_req_kill(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_9000 + + req = dtlb_env.bundle.requestor[port].req + req.bits_vaddr.value = va & ((1<<50)-1) + req.bits_fullva.value = va + req.bits_cmd.value = 0 + req.bits_kill.value = 1 + req.valid.value = 1 + + req.valid.value = 0 + + N = 32 + for _ in range(N): + assert dtlb_env.bundle.requestor[port].resp.valid.value == 0 + for i in range(4): + assert dtlb_env.bundle.ptw.req[i].valid.value == 0 + await dtlb_env.bundle.step() + +@toffee_test.testcase +async def test_req_notranslate(dtlb_env): + + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = 0x0000_0000_8020_1000 + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, no_translate = 1) + assert r0 == va + + +@toffee_test.testcase +async def test_hit_smoke(dtlb_env): + + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=va, + paddr=pa, + level=0, + s1_asid=0, + ) + for i in range(3): + r1 = await dtlb_env.agent.drive_request(port=i, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_miss_smoke(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=LOAD, kill=False ,no_translate=False ,return_on_miss=True) + + assert r0 is None diff --git a/ut_mem_block/dtlb/test/test_plru.py b/ut_mem_block/dtlb/test/test_plru.py new file mode 100644 index 00000000..58a88465 --- /dev/null +++ b/ut_mem_block/dtlb/test/test_plru.py @@ -0,0 +1,103 @@ +import toffee +import toffee_test +import random +from .ld_tlb_fixture import dtlb_env_plru + +LOAD = 0 +STORE = 1 + +async def _wait_ptw_req_and_capture(dtlb_env_plru, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = dtlb_env_plru.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await dtlb_env_plru.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) + +def _canon_sv39_vaddr(va: int) -> int: + """把 64 位 VA 规范化为 Sv39 形式""" + va = int(va) & ((1 << 64) - 1) + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (64 - 39)) - 1)) << 39 + return (upper | low39) & ((1 << 64) - 1) + +@toffee_test.testcase +async def test_plru_random(dtlb_env_plru): + dtlb_env_plru.dut.reset.value = 1; await dtlb_env_plru.bundle.step() + dtlb_env_plru.dut.reset.value = 0; await dtlb_env_plru.bundle.step() + await dtlb_env_plru.set_sv39_defaults(); await dtlb_env_plru.bundle.step() + va = [0]*100 + pa = [0]*100 + for i in range(100): + va[i] = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa[i] = random.randint(2 ** 12, 2 ** 36 - 1) + for i in range(200): + index = random.randint(0, 99) + vaddr = va[index] + paddr = pa[index] + + r0 = await dtlb_env_plru.agent.drive_request(port=0, vaddr=vaddr, cmd=LOAD, return_on_miss=True) + + if r0 == None: + await dtlb_env_plru.agent.set_ptw_resp( + vaddr=vaddr, + paddr=paddr, + level=0 + ) + await dtlb_env_plru.agent.drive_request(port=0, vaddr=vaddr, cmd=LOAD) + else: + continue + +@toffee_test.testcase +async def test_plru_sweep(dtlb_env_plru): + dtlb_env_plru.dut.reset.value = 1; await dtlb_env_plru.bundle.step() + dtlb_env_plru.dut.reset.value = 0; await dtlb_env_plru.bundle.step() + await dtlb_env_plru.set_sv39_defaults(); await dtlb_env_plru.bundle.step() + + BASE_VA = 0x0000_0000_8020_0000 + BASE_PA = 0x0000_0001_2340_0000 + for i in range(48): + va = BASE_VA + i * 0x8000 + pa = BASE_PA + i * 0x1000 + + r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env_plru, va) + await dtlb_env_plru.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + + r2 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + + new_va = BASE_VA + 0x1000 * 50 + new_pa = BASE_PA + 0x1000 * 50 + r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=new_va, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env_plru, new_va) + await dtlb_env_plru.agent.set_ptw_resp( + vaddr=new_va, paddr=new_pa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x + ) + + r2 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=new_va, cmd=LOAD) + expect = (new_pa & ~0xFFF) | (new_va & 0xFFF) + assert r2 == expect + + + miss_cnt = 0 + for i in range(48): + va = BASE_VA + i * 0x8000 + ret = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD) + if ret is None: + miss_cnt += 1 + + print(f"After inserting 49th entry, total miss when accessing original 48 entries: {miss_cnt}") + diff --git a/ut_mem_block/dtlb/test/test_redirect.py b/ut_mem_block/dtlb/test/test_redirect.py new file mode 100644 index 00000000..5b364fba --- /dev/null +++ b/ut_mem_block/dtlb/test/test_redirect.py @@ -0,0 +1,128 @@ +import toffee +import toffee_test +from .ld_tlb_fixture import dtlb_env + +LOAD = 0 +async def _wait_ptw_req_and_capture(dtlb_env, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = dtlb_env.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await dtlb_env.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) + + +@toffee_test.testcase +async def test_redirect_masks_miss_via_lastCycleRedirect(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + rob = 0x5C + gva = 0x0000_0000_8020_5000 + gpa = 0x0000_0001_2345_0000 + hpa = 0x0000_0003_ABCD_0000 + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=0, return_on_miss=True) + assert r0 is None + _, s2x, getGpa_flag = await _wait_ptw_req_and_capture(dtlb_env, gva) + + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x, getGpa=getGpa_flag, + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_r=False, s2_perm_a=True + ) + + req = dtlb_env.bundle.requestor[port].req + req.bits_vaddr.value = gva & ((1<<50)-1) + req.bits_fullva.value = gva + req.bits_cmd.value = 0 # LOAD + req.bits_isPrefetch.value = 0 + req.bits_no_translate.value = 0 + req.bits_debug_robIdx_flag.value = 1 + req.bits_debug_robIdx_value.value = rob + req.valid.value = 1 + + redir = dtlb_env.bundle.redirect + redir.valid.value = 1 + redir.bits_robIdx_flag.value = 1 + redir.bits_robIdx_value.value = rob + redir.bits_level.value = 1 + + await dtlb_env.bundle.step() + + + req.valid.value = 0 + redir.valid.value = 0 + + for _ in range(32): + for i in range(4): + assert dtlb_env.bundle.ptw.req[i].valid.value == 0 + await dtlb_env.bundle.step() + + +@toffee_test.testcase +async def test_redirect_level0_kill_younger(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + rob = 0x50 + pivot= 0x4A + gva = 0x0000_0000_8020_5000 + gpa = 0x0000_0001_2345_0000 + hpa = 0x0000_0003_ABCD_0000 + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, + s2xlate=s2x, getGpa=False, + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_r=False, s2_perm_a=True + ) + + req = dtlb_env.bundle.requestor[port].req + req.bits_vaddr.value = gva & ((1<<50)-1) + req.bits_fullva.value = gva + req.bits_cmd.value = LOAD + req.bits_isPrefetch.value = 0 + req.bits_no_translate.value = 0 + req.bits_debug_robIdx_flag.value = 1 + req.bits_debug_robIdx_value.value = rob + req.valid.value = 1 + + redir = dtlb_env.bundle.redirect + redir.valid.value = 1 + redir.bits_robIdx_flag.value = 1 + redir.bits_robIdx_value.value = pivot + redir.bits_level.value = 0 + + await dtlb_env.bundle.step() + + req.valid.value = 0 + redir.valid.value = 0 + + for _ in range(32): + for i in range(4): + assert dtlb_env.bundle.ptw.req[i].valid.value == 0 + await dtlb_env.bundle.step() \ No newline at end of file diff --git a/ut_mem_block/dtlb/test/test_sfence.py b/ut_mem_block/dtlb/test/test_sfence.py new file mode 100644 index 00000000..f1532a14 --- /dev/null +++ b/ut_mem_block/dtlb/test/test_sfence.py @@ -0,0 +1,328 @@ +# -*- coding: utf-8 -*- +import toffee +import toffee_test +from .ld_tlb_fixture import dtlb_env + +LOAD = 0 +STORE = 1 + +async def _wait_ptw_req_and_capture(dtlb_env, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = dtlb_env.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await dtlb_env.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) + +def _canon_sv39_to_50b(va: int, page_align: bool) -> int: + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (50 - 39)) - 1)) << 39 + va50 = (upper | low39) & ((1 << 50) - 1) + if page_align: + va50 &= ~0xFFF + return va50 + +async def do_sfence(dtlb_env, *, hv=False, hg=False, rs1=False, addr=0, rs2=False, id_=0, settle_cycles=10): + sf = dtlb_env.bundle.sfence + sf.bits_hv.value = 1 if hv else 0 + sf.bits_hg.value = 1 if hg else 0 + sf.bits_rs1.value = 1 if rs1 else 0 + sf.bits_rs2.value = 1 if rs2 else 0 + + sf.bits_addr.value = _canon_sv39_to_50b(addr, page_align=rs1) + sf.bits_id.value = int(id_) & ((1 << 16) - 1) + sf.bits_flushPipe.value = 0 + + sf.valid.value = 1 + await dtlb_env.bundle.step() + sf.valid.value = 0 + + for _ in range(settle_cycles): + await dtlb_env.bundle.step() + + +# ========================= +# 1) SFENCE.VMA 全量清(非 G) +# ========================= +@toffee_test.testcase +async def test_sfence_vma_global_noG(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x11 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await dtlb_env.bundle.step() + + # miss → 回填(非 G)→ hit + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == expect + + # 全量清(rs1=0, rs2=0) + await do_sfence(dtlb_env, hv=False, hg=False, rs1=False, rs2=False) + + # 应 miss + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 2) SFENCE.VMA 按 ASID 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_asid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 0 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x22 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await dtlb_env.bundle.step() + + + + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + # 按当前 satp.asid 清(id 用 CSR.Satp.asid) + await do_sfence(dtlb_env, hv=False, hg=False, rs1=False, rs2=True, id_=asid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 3) SFENCE.VMA 按 VA 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_va(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 1 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x33 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await dtlb_env.bundle.step() + + + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + await do_sfence(dtlb_env, hv=False, hg=False, rs1=True, addr=va, rs2=False) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 4) SFENCE.VMA 按 (VA, ASID) 清 +# ========================= +@toffee_test.testcase +async def test_sfence_vma_by_va_asid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 2 + va = 0x0000_0000_8020_1000 + pa = 0x0000_0001_0000_9000 + asid = 0x44 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = asid + await dtlb_env.bundle.step() + + + + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, + s2xlate=s2x) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) + + await do_sfence(dtlb_env, hv=False, hg=False, rs1=True, addr=va, rs2=True, id_=asid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 5) HFENCE.VVMA:按 VMID(全 GVA) +# ========================= +@toffee_test.testcase +async def test_hfence_vvma_by_vmid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 0 + gva = 0x0000_0000_8020_1000 + gpa = 0x0000_0001_0000_9000 + asid = 0x12 + vmid = 0xAA + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 # VS-S1 开启 + csr.HGatp.mode.value = 0 # S2 关闭(only VS-S1) + csr.Vsatp.asid.value = asid + csr.HGatp.vmid.value = vmid # 关键:VVMA 用 CSR.HGATP.vmid 过滤 + await dtlb_env.bundle.step() + + + + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) + await dtlb_env.agent.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, + s1_asid=asid, s1_vmid=vmid, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, + s2xlate=s2x) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) + + # VVMA:hv=1,通常按 VMID 过滤需 rs2=1;VMID 来源于 CSR.HGATP.vmid(id 忽略) + await do_sfence(dtlb_env, hv=True, hg=False, rs1=False, rs2=True, id_=vmid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 6) HFENCE.VVMA:按 (GVA, VMID) 清 +# ========================= +@toffee_test.testcase +async def test_hfence_vvma_by_gva_vmid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 1 + gva = 0x0000_0000_8020_1000 + gpa = 0x0000_0001_0000_9000 + asid = 0x21 + vmid = 0xBB + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = asid + csr.HGatp.vmid.value = vmid + await dtlb_env.bundle.step() + + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) + await dtlb_env.agent.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, + s1_asid=asid, s1_vmid=vmid, + s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s1_perm_g=False, + s2xlate=s2x) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) + + await do_sfence(dtlb_env, hv=True, hg=False, rs1=True, addr=gva, rs2=True, id_=vmid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 7) HFENCE.GVMA:按 VMID 清 S2(GPA 全范围) +# ========================= +@toffee_test.testcase +async def test_hfence_gvma_by_vmid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 2 + gpa_in = 0x0000_0000_8020_1000 + hpa = 0x0000_0002_2000_0000 + vmid = 0x66 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = vmid + await dtlb_env.bundle.step() + + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) + await dtlb_env.agent.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) + + # GVMA:hg=1,按 VMID(来自 bits_id)清 S2 + await do_sfence(dtlb_env, hv=False, hg=True, rs1=False, rs2=True, id_=vmid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + + +# ========================= +# 8) HFENCE.GVMA:按 (GPA, VMID) 清 S2 +# ========================= +@toffee_test.testcase +async def test_hfence_gvma_by_gpa_vmid(dtlb_env): + dtlb_env = dtlb_env + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 3 + gpa_in = 0x0000_0000_8020_1000 + hpa = 0x0000_0002_2000_1000 + vmid = 0x77 + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = vmid + await dtlb_env.bundle.step() + + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) + await dtlb_env.agent.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=vmid, s2_perm_r=True, s2_perm_a=True) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) + + await do_sfence(dtlb_env, hv=False, hg=True, rs1=True, addr=gpa_in, rs2=True, id_=vmid) + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None diff --git a/ut_mem_block/dtlb/test/test_st_dtlb.py b/ut_mem_block/dtlb/test/test_st_dtlb.py new file mode 100644 index 00000000..55ef158d --- /dev/null +++ b/ut_mem_block/dtlb/test/test_st_dtlb.py @@ -0,0 +1,833 @@ +import toffee +import toffee_test +import random +from .ld_tlb_fixture import dtlb_env + +LOAD = 0 +STORE = 1 + +async def _wait_ptw_req_and_capture(dtlb_env, vaddr, max_cycles=32): + vpn_expect = (int(vaddr) >> 12) & ((1 << 27) - 1) + for _ in range(max_cycles): + for i in range(4): + req = dtlb_env.bundle.ptw.req[i] + if int(req.valid.value) == 1 and int(req.bits_vpn.value) == vpn_expect: + return i, int(req.bits_s2xlate.value), int(req.bits_getGpa.value) + await dtlb_env.bundle.step() + raise AssertionError("Timed out waiting for ptw.req on vpn=0x%x" % vpn_expect) +def _canon_sv39_vaddr(va: int) -> int: + va = int(va) & ((1 << 64) - 1) + low39 = va & ((1 << 39) - 1) + sign = (low39 >> 38) & 1 + upper = ((-sign) & ((1 << (64 - 39)) - 1)) << 39 + return (upper | low39) & ((1 << 64) - 1) + +@toffee_test.testcase +async def test_ptwresp_s1_pf_propagates_to_requestor(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s1_pf=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_pf_st.value) == 1 + +@toffee_test.testcase +async def test_ptwresp_s1_af_propagates_to_requestor(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s1_af=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_af_st.value) == 1 + +@toffee_test.testcase +async def test_ptwresp_s2_gpf_propagates_to_requestor(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) + assert r0 is None + + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp(vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + s2_gpf=True, + s2xlate=s2x) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) + assert r1 == -1 + + resp = dtlb_env.bundle.requestor[port].resp + assert int(resp.bits_excp_0_gpf_st.value) == 1 + +@toffee_test.testcase +async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = 0x2 + csr.priv_dmode.value = 1 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_asid=0x2, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r1 == -1 + + csr.priv_sum.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_priv_vsum_vs_supervisor_can_read_user_page(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = 0x34 + csr.HGatp.vmid.value = 0xB + csr.priv_dmode.value = 1 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_asid=0x34, s1_vmid=0xB, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + assert r1 == -1 + + csr.priv_vsum.value = 1 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r2 == expect + +@toffee_test.testcase +async def test_asid_isolation_bare(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 0 + csr.Satp.mode.value = 8 + csr.Satp.asid.value = 0x10 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=pa, level=0, + s1_asid=0x10, s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + + csr.Satp.asid.value = 0x21 + await dtlb_env.bundle.step() + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r2 is None + +@toffee_test.testcase +async def test_asid_isolation_onlyStage1(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + csr.Vsatp.asid.value = 0x33 + csr.HGatp.vmid.value = 0xA + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_asid=0x33, s1_vmid=0xA, s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + + csr.Vsatp.asid.value = 0x44 + csr.Vsatp.changed.value = True + await dtlb_env.bundle.step() + csr.Vsatp.changed.value = False + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r2 is None + + csr.Vsatp.asid.value = 0x33 + csr.HGatp.vmid.value = 0xB + csr.Vsatp.changed.value = True + csr.HGatp.changed.value = True + await dtlb_env.bundle.step() + csr.Vsatp.changed.value = False + csr.HGatp.changed.value = False + + r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + assert r3 is None + +@toffee_test.testcase +async def test_vmid_isolation_onlyStage2(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + csr.HGatp.vmid.value = 0x55 + await dtlb_env.bundle.step() + + port = 0 + gpa_in = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE, return_on_miss=True) + assert r0 is None + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa_in, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=getGpa_req, + s2_tag=(gpa_in >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s1_vmid=0x55, s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE) + expect = (hpa & ~0xFFF) | (gpa_in & 0xFFF) + assert r1 == expect + + csr.HGatp.vmid.value = 0x66 + csr.HGatp.changed.value = True + await dtlb_env.bundle.step() + csr.HGatp.changed.value = False + + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE, return_on_miss=True) + assert r2 is None + +@toffee_test.testcase +async def test_hit_onlyStage1(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 0 + await dtlb_env.bundle.step() + + port = 0 + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE ,return_on_miss=True) + assert r0 is None + + ptw_port, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, va) + await dtlb_env.agent.set_ptw_resp( + vaddr=va, paddr=gpa, level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x, getGpa=getGpa_req + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + expect = (gpa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + + +@toffee_test.testcase +async def test_hit_onlyStage2_4k(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) + expect = (hpa & ~0xFFF) | (gpa & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_onlyStage2_2m(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) + + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=1, + s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + for off in (0x000, 0x1000, 0x1FF000): + va = gpa + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) + mask = (1 << 21) - 1 + expect = (hpa & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_onlyStage2_1g(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 0 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) + + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) + await dtlb_env.agent.set_ptw_resp( + vaddr=gpa, paddr=0, level=0, + s1_v=False, + s2xlate=s2x, getGpa=False, + s2_tag=(gpa >> 12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=2, + s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + for off in (0x0, 0x21_000, 0x3FF_F000): + va = gpa + off + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) + mask = (1 << 30) - 1 + expect = (hpa & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_allStage(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + port = 0 + gva = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 -1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=STORE, return_on_miss=True) + assert r0 is None + + _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x, getGpa=getGpa_ptw, + s2_tag=(gpa>>12) & ((1<<27)-1), + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_u=True, s2_perm_w=True, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + + r1 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=STORE) + expect = (hpa & ~0xFFF) | (gva & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_hit_allStage_with_getGpa(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + csr = dtlb_env.bundle.csr + csr.priv_virt.value = 1 + csr.Vsatp.mode.value = 8 + csr.HGatp.mode.value = 8 + await dtlb_env.bundle.step() + + gva = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + gpa = random.randint(2 ** 12, 2 ** 41 -1) + hpa = random.randint(2 ** 12, 2 ** 36 - 1) + + _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=STORE, return_on_miss=True) + _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) + + await dtlb_env.agent.set_ptw_resp( + vaddr=gva, paddr=gpa, level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s2xlate=s2x, getGpa=getGpa_ptw, + s2_ppn=(hpa >> 12), s2_level=0, + s2_perm_u=True, s2_perm_w=False, s2_perm_a=True, + s2_perm_d=True, s2_perm_r=False, + ) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=STORE) + + _, s2x_req, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gva) + assert getGpa_req == 1 + + +@toffee_test.testcase +async def test_parallel_simul_req_miss(dtlb_env): + requestor = dtlb_env.bundle.requestor + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + VA0 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA1 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA2 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + + requestor[0].req.valid.value = 1 + requestor[0].req.bits_vaddr.value = VA0 + requestor[0].req.bits_fullva.value = VA0 + requestor[0].req.bits_cmd.value = STORE + requestor[0].req.bits_no_translate.value = 0 + requestor[1].req.valid.value = 1 + requestor[1].req.bits_vaddr.value = VA1 + requestor[1].req.bits_fullva.value = VA1 + requestor[1].req.bits_cmd.value = STORE + requestor[1].req.bits_no_translate.value = 0 + requestor[2].req.valid.value = 1 + requestor[2].req.bits_vaddr.value = VA2 + requestor[2].req.bits_fullva.value = VA2 + requestor[2].req.bits_cmd.value = STORE + requestor[2].req.bits_no_translate.value = 0 + + await dtlb_env.bundle.step() + + requestor[0].req.valid.value = 0 + requestor[1].req.valid.value = 0 + requestor[2].req.valid.value = 0 + await dtlb_env.bundle.step() + + +@toffee_test.testcase +async def test_parallel_simul_req_hit(dtlb_env): + requestor = dtlb_env.bundle.requestor + + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + VA0 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA1 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + VA2 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + PA0 = random.randint(2 ** 12, 2** 36 - 1) + PA1 = random.randint(2 ** 12, 2** 36 - 1) + PA2 = random.randint(2 ** 12, 2** 36 - 1) + + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=STORE) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA0,paddr=PA0,level=0,s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=STORE) == ((VA0 & (0xFFF)) | (PA0 & ~(0xFFF))) + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA1, cmd=LOAD) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA1,paddr=PA1,level=0,s1_perm_u=True, s1_perm_r=True, s1_perm_a=True) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA1, cmd=LOAD) == ((VA1 & (0xFFF)) | (PA1 & ~(0xFFF))) + + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA2, cmd=LOAD) == None + await dtlb_env.agent.set_ptw_resp(vaddr=VA2,paddr=PA2,level=0,s1_perm_u=True, s1_perm_r=True, s1_perm_a=True) + assert await dtlb_env.agent.drive_request(port=0, vaddr=VA2, cmd=LOAD) == ((VA2 & (0xFFF)) | (PA2 & ~(0xFFF))) + await dtlb_env.bundle.step() + requestor[0].req.valid.value = 1 + requestor[0].req.bits_vaddr.value = VA0 + requestor[0].req.bits_fullva.value = VA0 + requestor[0].req.bits_cmd.value = STORE + requestor[0].req.bits_no_translate.value = 0 + requestor[1].req.valid.value = 1 + requestor[1].req.bits_vaddr.value = VA1 + requestor[1].req.bits_fullva.value = VA1 + requestor[1].req.bits_cmd.value = LOAD + requestor[1].req.bits_no_translate.value = 0 + requestor[2].req.valid.value = 1 + requestor[2].req.bits_vaddr.value = VA2 + requestor[2].req.bits_fullva.value = VA2 + requestor[2].req.bits_cmd.value = LOAD + requestor[2].req.bits_no_translate.value = 0 + + await dtlb_env.bundle.step() + + requestor[0].req.valid.value = 0 + requestor[1].req.valid.value = 0 + requestor[2].req.valid.value = 0 + await dtlb_env.bundle.step() + +@toffee_test.testcase +async def test_store_2mb_page(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) + pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) + + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=va_base, paddr=pa_base, level=1, s1_asid=0, + s1_ppn_low=[0]*8, s1_valididx=[1]*8, s1_pteidx=[0]*8, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + ) + + for off in (0x000, 0x1000, 0x1FF000): + va = va_base + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) + mask = (1 << 21) - 1 + expect = (pa_base & ~mask) | (va & mask) + assert r1 == expect + + +@toffee_test.testcase +async def test_store_1gb_page(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) + pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=va_base, paddr=pa_base, level=2, s1_asid=0, + s1_ppn_low=[0]*8, s1_valididx=[1]*8, s1_pteidx=[0]*8, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + ) + + for off in (0x0, 0x21_000, 0x3FF_F000): + va = va_base + off + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) + mask = (1 << 30) - 1 + expect = (pa_base & ~mask) | (va & mask) + assert r1 == expect + +@toffee_test.testcase +async def test_express_random(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + vpn_low = (va >> 12) & 0x7 + ppn_low = (pa >> 12) & 0x7 + rand_valididx = [0]*8 + rand_ppn_low = [0]*8 + pteidx = [0]*8 + for i in range(8): + rand_valididx[i] = random.randint(0,1) + rand_ppn_low[i] = i + rand_valididx[vpn_low] = 1 + pteidx[vpn_low] = 1 + await dtlb_env.agent.set_ptw_resp( + vaddr=va, + paddr=pa, + level=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s1_asid=0, + s1_ppn_low=rand_ppn_low, + s1_valididx=rand_valididx, + s1_pteidx=pteidx + ) + va_base = va & ~((1<<15)-1) + pa_base = pa & ~((1<<15)-1) + for i in range(8): + va = va_base | (i << 12) + pa = pa_base | (rand_ppn_low[i] << 12) + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) + if rand_valididx[i] != 0: + expect = (pa & ~0xFFF) | (va & 0xFFF) + else: + expect = None + assert r1 == expect + +@toffee_test.testcase +async def test_express_full(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) + pa = random.randint(2 ** 12, 2 ** 36 - 1) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE, return_on_miss=True) + assert r0 is None + vpn_low = (va >> 12) & 0x7 + pteidx = [0]*8 + pteidx[vpn_low] = 1 + await dtlb_env.agent.set_ptw_resp( + vaddr=va, + paddr=pa, + level=0, + s1_asid=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + s1_ppn_low=[0,1,2,3,4,5,6,7], + s1_valididx=[1,1,1,1,1,1,1,1], + s1_pteidx=pteidx + ) + va_base = va & ~((1<<15)-1) + pa_base = pa & ~((1<<15)-1) + for i in range(8): + va = va_base | (i << 12) + pa = pa_base | (i << 12) + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) + expect = (pa & ~0xFFF) | (va & 0xFFF) + assert r1 == expect + +@toffee_test.testcase +async def test_req_kill(dtlb_env): + dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() + + port = 0 + rob = 0x3A + va = 0x0000_0000_8020_9000 + + req = dtlb_env.bundle.requestor[port].req + req.bits_vaddr.value = va & ((1<<50)-1) + req.bits_fullva.value = va + req.bits_cmd.value = 0 + req.bits_kill.value = 1 + req.valid.value = 1 + + req.valid.value = 0 + + N = 32 + for _ in range(N): + assert dtlb_env.bundle.requestor[port].resp.valid.value == 0 + for i in range(4): + assert dtlb_env.bundle.ptw.req[i].valid.value == 0 + await dtlb_env.bundle.step() + +@toffee_test.testcase +async def test_req_notranslate(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + va = 0x0000_0000_8020_1000 + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE, no_translate = 1) + assert r0 == va + + +@toffee_test.testcase +async def test_hit_smoke(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE, return_on_miss=True) + assert r0 is None + + await dtlb_env.agent.set_ptw_resp( + vaddr=0x0000_0000_8020_1000, + paddr=0x0000_0001_2345_6000, + level=0, + s1_asid=0, + s1_perm_u=True, s1_perm_w=True, s1_perm_a=True, + s1_perm_d=True, s1_perm_r=False, + ) + + r1 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE) + expect = (0x0000_0001_2345_6000 & ~0xFFF) | (0x0000_0000_8020_1000 & 0xFFF) + assert r1 == expect + + +@toffee_test.testcase +async def test_miss_smoke(dtlb_env): + dtlb_env.dut.reset.value = 1 + await dtlb_env.bundle.step() + dtlb_env.dut.reset.value = 0 + await dtlb_env.bundle.step() + + await dtlb_env.set_sv39_defaults() + await dtlb_env.bundle.step() + + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE, kill=False ,no_translate=False ,return_on_miss=True) + + assert r0 is None \ No newline at end of file From 5a406901b6c2dc41dd7bc33b313f116c712a1a99 Mon Sep 17 00:00:00 2001 From: kenny Date: Fri, 19 Sep 2025 22:24:52 +0800 Subject: [PATCH 4/4] Content optimisation --- ut_mem_block/dtlb/agent/dtlb_agent.py | 84 +++--------------------- ut_mem_block/dtlb/env/dtlb_env.py | 1 - ut_mem_block/dtlb/env/dtlb_mdl.py | 45 +++---------- ut_mem_block/dtlb/test/funcov_dtlb.py | 39 ++++++----- ut_mem_block/dtlb/test/test_ld_dtlb.py | 86 +++++++++++-------------- ut_mem_block/dtlb/test/test_plru.py | 11 +--- ut_mem_block/dtlb/test/test_redirect.py | 4 +- ut_mem_block/dtlb/test/test_sfence.py | 32 ++++----- ut_mem_block/dtlb/test/test_st_dtlb.py | 42 ++++++------ 9 files changed, 120 insertions(+), 224 deletions(-) diff --git a/ut_mem_block/dtlb/agent/dtlb_agent.py b/ut_mem_block/dtlb/agent/dtlb_agent.py index 9f4c4b95..6a46f32b 100644 --- a/ut_mem_block/dtlb/agent/dtlb_agent.py +++ b/ut_mem_block/dtlb/agent/dtlb_agent.py @@ -34,13 +34,7 @@ async def drive_request( debug_robIdx_flag: int = 0, debug_robIdx_value: int = 0, debug_isFirstIssue: int = 0, - return_on_miss: bool = False, ): - """ - 命中且无异常 => 返回 paddr_0 (int) - miss / 异常 => 返回 None - return_on_miss=True: 一旦看到 miss 就立即返回 None(便于“下一拍注入”) - """ if not 0 <= port < 4: raise ValueError("Port must be 0..N-1") @@ -74,11 +68,8 @@ async def drive_request( await self.bundle.step() req.valid.value = 1 - # print("resp_miss before request : ",self.requestor[port].resp.bits_miss.value, flush=True) - await Value(self.requestor[port].resp.valid, 1) # 发起 + await Value(self.requestor[port].resp.valid, 1) req.valid.value = 0 - # print("resp_miss after request : ",self.requestor[port].resp.bits_miss.value, flush=True) - resp = self.requestor[port].resp @@ -86,7 +77,6 @@ async def drive_request( if miss == 1: return None - # 汇总异常位(ld/st 都看一遍更稳) # print("resp_excp_0_pf_ld : ",resp.bits_excp_0_pf_ld.value, flush=True) # print("resp_excp_0_pf_st : ",resp.bits_excp_0_pf_st.value, flush=True) # print("resp_excp_0_af_ld : ",resp.bits_excp_0_af_ld.value, flush=True) @@ -105,7 +95,6 @@ async def drive_request( @driver_method() async def set_ptw_resp(self, vaddr, paddr, level, *, - # S1/S2 选择 valid: bool = True, s2xlate: int = 0, getGpa: bool = False, @@ -114,13 +103,12 @@ async def set_ptw_resp(self, vaddr, paddr, level, *, s1_vmid: int = 0, s1_n: bool = False, s1_pbmt: int = 0, - # 权限位 s1_perm_d: bool = False, s1_perm_a: bool = True, s1_perm_g: bool = False, s1_perm_u: bool = True, s1_perm_x: bool = False, s1_perm_w: bool = False, s1_perm_r: bool = True, - s1_v: bool = True, # 表项有效位 - s1_ppn_low: list[int] | None = None, # 直接给 ppn_low[8] 列表 - s1_valididx: list[int] | None = None, # 直接给 valididx[8] 列表 - s1_pteidx: list[int] | None = None, # 直接给 pteidx[8] 列表 + s1_v: bool = True, + s1_ppn_low: list[int] | None = None, + s1_valididx: list[int] | None = None, + s1_pteidx: list[int] | None = None, s1_pf: bool = False, s1_af: bool = False, # ---------- S2 entry ---------- s2_tag: int = 0, @@ -133,23 +121,14 @@ async def set_ptw_resp(self, vaddr, paddr, level, *, s2_level: int = 0, s2_gpf: bool = False, s2_gaf: bool = False, ): - """ - 依据 vaddr/paddr 自动拼好 PTWResp:addr_low/entry_tag/entry_ppn/ppn_low/valididx/pteidx 等, - 并在观测到 ptw.req[i] 匹配的当下打一拍 resp.valid。 - 约定(Sv39): - - vpn = va>>12(27 位),addr_low = vpn[2:0],entry_tag = vpn>>3 - - ppn = pa>>12,entry_ppn = ppn>>3,ppn_low[addr_low] = ppn[2:0] - - 4KB 页 level=2(2MB=1,1GB=0) - """ - # -------- 计算索引/字段 -------- vaddr = int(vaddr) & ((1 << 64) - 1) - paddr = int(paddr) & ((1 << 56) - 1) # 物理位宽保守截断 - vpn = (vaddr >> 12) & ((1 << 27) - 1) # Sv39 VPN + paddr = int(paddr) & ((1 << 56) - 1) + vpn = (vaddr >> 12) & ((1 << 27) - 1) ppn = (paddr >> 12) - addr_low = vpn & 0b111 # vpn[2:0] - entry_tag = vpn >> 3 # 与硬件压缩槽对齐 + addr_low = vpn & 0b111 + entry_tag = vpn >> 3 if s2xlate == 0: - entry_ppn = (ppn >> 3) & ((1 << 21) - 1) # 高 21 位(低 3 位走 ppn_low[]) + entry_ppn = (ppn >> 3) & ((1 << 21) - 1) else: entry_ppn = (ppn >> 3) & ((1 << 26) - 1) ppn_low_val = ppn & 0b111 @@ -221,49 +200,6 @@ async def set_ptw_resp(self, vaddr, paddr, level, *, await self.bundle.step() self.bundle.ptw.resp.valid.value = 0 - # @driver_method() - # async def set_csr(self,*, - # priv_mxr = 0, priv_sum = 0, - # priv_vmxr = 0, priv_vsum = 0, - # priv_virt = 0, priv_spvp = 0, - # priv_imode = 0, priv_dmode = 0, - - # Satp_mode = 8, # Sv39 常见编码 - # Satp_asid = 0, - # Satp_ppn = 0, - # Satp_changed = 0, - - # Vsatp_mode = 0, - # Vsatp_asid = 0, - # Vsatp_ppn = 0, - # Vsatp_changed = 0, - - # HGatp_mode = 0, - # HGatp_vmid = 0, - # HGatp_ppn = 0, - # HGatp_changed = 0,): - # csr = self.bundle.csr - # csr.bits_priv_mxr.value = priv_mxr - # csr.bits_priv_sum.value = priv_sum - # csr.bits_priv_vmxr.value = priv_vmxr - # csr.bits_priv_vsum.value = priv_vsum - # csr.bits_priv_virt.value = priv_virt - # csr.bits_priv_spvp.value = priv_spvp - # csr.bits_priv_imode.value = priv_imode - # csr.bits_priv_dmode.value = priv_dmode - # csr.bits_Satp_mode.value = Satp_mode - # csr.bits_Satp_asid.value = Satp_asid - # csr.bits_Satp_ppn.value = Satp_ppn - # csr.bits_Satp_changed.value = Satp_changed - # csr.bits_Vsatp_mode.value = Vsatp_mode - # csr.bits_Vsatp_asid.value = Vsatp_asid - # csr.bits_Vsatp_ppn.value = Vsatp_ppn - # csr.bits_Vsatp_changed.value = Vsatp_changed - # csr.bits_HGatp_mode.value = HGatp_mode - # csr.bits_HGatp_vmid.value = HGatp_vmid - # csr.bits_HGatp_ppn.value = HGatp_ppn - # csr.bits_HGatp_changed.value = HGatp_changed - # await self.bundle.step() @monitor_method() async def monitor_ptw_req(self): diff --git a/ut_mem_block/dtlb/env/dtlb_env.py b/ut_mem_block/dtlb/env/dtlb_env.py index 2451002d..17340e72 100644 --- a/ut_mem_block/dtlb/env/dtlb_env.py +++ b/ut_mem_block/dtlb/env/dtlb_env.py @@ -47,7 +47,6 @@ def __init__(self, dut): self.bundle = DTLBBundle.from_prefix("io_").bind(dut) self.agent = DTLBAgent(self.bundle) - async def set_sv39_defaults(self): csr = self.bundle.csr csr.priv_mxr.value = 0; csr.priv_sum.value = 0 diff --git a/ut_mem_block/dtlb/env/dtlb_mdl.py b/ut_mem_block/dtlb/env/dtlb_mdl.py index 3c101f0f..e22b94f2 100644 --- a/ut_mem_block/dtlb/env/dtlb_mdl.py +++ b/ut_mem_block/dtlb/env/dtlb_mdl.py @@ -2,7 +2,6 @@ from __future__ import annotations from toffee.model import Model, driver_hook -# ---------------------- Sv39 规范化 + page key ---------------------- def _canon_sv39_vaddr(va: int) -> int: va = int(va) & ((1 << 64) - 1) low39 = va & ((1 << 39) - 1) @@ -13,19 +12,15 @@ def _canon_sv39_vaddr(va: int) -> int: def _page_key_from_va(va: int) -> int: canon = _canon_sv39_vaddr(va) va39 = canon & ((1 << 39) - 1) - return va39 & ~0xFFF # 清 4KB 偏移 + return va39 & ~0xFFF # ---------------------- 不平衡 48-way Tree-PLRU(根 32/16) ---------------------- class TreePLRU48: - """ - 48 路 Tree-PLRU(根拆成 左32/右16,不平衡) - 规则:victim 时 bit=0 走左、bit=1 走右;touch 某 way 时,沿路径把该结点位改成“指向另一侧”为冷。 - """ class Node: __slots__ = ("L", "R", "bit", "lch", "rch") def __init__(self, L, R): - self.L, self.R = L, R # 左/右子树包含的叶子数 - self.bit = 0 # 0=左冷(选左)、1=右冷(选右) + self.L, self.R = L, R + self.bit = 0 self.lch = None self.rch = None @@ -41,34 +36,23 @@ def build(n): build(self.root) def pick_victim(self) -> int: - """ - 无条件由 PLRU 选路(不做 invalid 优先)。当选择命中“叶子侧”时不再下探,直接终止。 - 返回 0..47 的 way 索引。 - """ n = self.root idx = 0 while True: - # 到叶(单侧 1 个元素) if n.L + n.R == 1: break if n.bit == 1: - # 走右侧 idx += n.L if n.R == 1: break # 右侧是叶,不再往下 n = n.rch else: - # 走左侧 if n.L == 1: break # 左侧是叶,不再往下 n = n.lch return idx def touch(self, i: int) -> None: - """ - 命中/回填后:沿着 i 的路径把结点位改成“指向另一侧”为冷。 - 当命中的是叶子侧时,同样不再向下走。 - """ n = self.root idx = i while n and (n.L + n.R > 1): @@ -94,13 +78,8 @@ def walk(n): walk(self.root) -# ---------------------- 参考模型:48 项全相联(无 invalid 优先) ---------------------- +# ---------------------- 参考模型:48 项全相联 ---------------------- class DTLBPLRURefModel(Model): - """ - - 48 项全相联缓存:每项保存 {valid, va_page_key(39b), pa_page_base} - - 替换:无条件 PLRU 选 way(不做 invalid 优先);写入后 touch - - 命中:返回 (pa_page_base | (vaddr & 0xFFF)) - """ CAP = 48 def __init__(self): @@ -108,7 +87,6 @@ def __init__(self): self.entries = [{"valid": False, "va": 0, "pa": 0} for _ in range(self.CAP)] self.plru = TreePLRU48() - # ---------------- driver_hook #1:命中查询 ---------------- @driver_hook(agent_name="agent", driver_name="drive_request") def drive_request( self, @@ -135,7 +113,6 @@ def drive_request( return int(e["pa"] | (int(vaddr) & 0xFFF)) return None - # ---------------- driver_hook #2:PTW 回填(无 invalid 优先) ---------------- @driver_hook(agent_name="agent", driver_name="set_ptw_resp") def set_ptw_resp(self, vaddr, paddr, level, *, # S1/S2 选择 @@ -147,15 +124,13 @@ def set_ptw_resp(self, vaddr, paddr, level, *, s1_vmid: int = 0, s1_n: bool = False, s1_pbmt: int = 0, - # 权限位(按 D/A/G/U/X/W/R 的顺序给) s1_perm_d: bool = False, s1_perm_a: bool = True, s1_perm_g: bool = False, s1_perm_u: bool = True, s1_perm_x: bool = False, s1_perm_w: bool = False, s1_perm_r: bool = True, - s1_v: bool = True, # 表项有效位 - s1_ppn_low: list[int] | None = None, # 直接给 ppn_low[8] 列表 - s1_valididx: list[int] | None = None, # 直接给 valididx[8] 列表 - s1_pteidx: list[int] | None = None, # 直接给 pteidx[8] 列表 + s1_v: bool = True, + s1_ppn_low: list[int] | None = None, + s1_valididx: list[int] | None = None, + s1_pteidx: list[int] | None = None, s1_pf: bool = False, s1_af: bool = False, - # ---------- S2 entry(当 s2xlate=1 时生效) ---------- s2_tag: int = 0, s2_vmid: int = 0, s2_n: bool = False, @@ -166,10 +141,6 @@ def set_ptw_resp(self, vaddr, paddr, level, *, s2_level: int = 0, s2_gpf: bool = False, s2_gaf: bool = False, ): - """ - 与 DUT 对齐:不找空槽,始终由 PLRU 选 way。 - 若已存在同 VA,做覆写并 touch(不新增)。 - """ if not valid: return None diff --git a/ut_mem_block/dtlb/test/funcov_dtlb.py b/ut_mem_block/dtlb/test/funcov_dtlb.py index bb4ab332..8f54df73 100644 --- a/ut_mem_block/dtlb/test/funcov_dtlb.py +++ b/ut_mem_block/dtlb/test/funcov_dtlb.py @@ -33,21 +33,7 @@ def init_dtlb_funcov(dut, g: fc.CovGroup): and getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 3 for i in range(4)), }, name="F2_S2XLATE_MODES") - # getGpa 路径(GPF 需要先走 getGpa,不入 TLBuffer 的 resp) - g.add_watch_point(dut, { - "F2.getGpa==1_seen": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_getGpa").value == 1 for i in range(4)), - }, name="F2_GETGPA") - - # PTW resp/fault 标志 - g.add_watch_point(dut, { - "F2.ptw_resp_valid": lambda d: getattr(d, "io_ptw_resp_valid").value == 1, - "F10.s1_pf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 - and getattr(d, "io_ptw_resp_bits_s1_pf").value == 1, - "F10.s1_af": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 - and getattr(d, "io_ptw_resp_bits_s1_af").value == 1, - "F10.s2_gpf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 - and getattr(d, "io_ptw_resp_bits_s2_gpf").value == 1, - }, name="F2_PTW_RESP_FAULTS") + # ---------------- 功能点3:hit 返回(paddr/gpaddr/页内偏移一致) ---------- for i in range(4): @@ -62,7 +48,18 @@ def init_dtlb_funcov(dut, g: fc.CovGroup): and getattr(d, f"io_requestor_{i}_resp_bits_gpaddr_0").value != 0, }, name=f"F3_RET_gpaddr_P{i}") - + # ---------------- 功能点4:getGpa 功能测试 ---------- + g.add_watch_point(dut, { + "F4.getGpa==1_seen": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_getGpa").value == 1 for i in range(4)), + }, name="F4_GETGPA") + + # ---------------- 功能点5:H扩展功能测试 ---------- + g.add_watch_point(dut, { + "F5.Bare": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 0 for i in range(4)), + "F5.onlyStage1": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 1 for i in range(4)), + "F5.onlyStage2": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 2 for i in range(4)), + "F5.allStage": lambda d: any(getattr(d, f"io_ptw_req_{i}_bits_s2xlate").value == 3 for i in range(4)), + }, name="F5_S2XLATE_MODES") # ---------------- 功能点6:TLB 压缩(valididx 统计) -------------------- # io_ptw_resp_bits_s1_valididx_0..7 为 8 位 one-hot/稀疏集合 @@ -117,12 +114,20 @@ def _sum_valididx(d): f"F9.0.af.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_af_st").value == 1, }, name=f"F9_EXCP_st_P0") # ---------------- 功能点10:异常(GPF/GAF) ---------------------------- + g.add_watch_point(dut, { + "F10.s1_pf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_pf").value == 1, + "F10.s1_af": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s1_af").value == 1, + "F10.s2_gpf": lambda d: getattr(d, "io_ptw_resp_valid").value == 1 + and getattr(d, "io_ptw_resp_bits_s2_gpf").value == 1, + }, name="F10_PTW_RESP_FAULTS") for i in range(4): g.add_watch_point(dut, { f"F10.{i}.gpf.ld": lambda d, i=i: getattr(d, f"io_requestor_{i}_resp_bits_excp_0_gpf_ld").value == 1, }, name=f"F10_GPF_ld_P{i}") g.add_watch_point(dut, { - f"F9.0.gpf.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_gpf_st").value == 1, + f"F10.0.gpf.st": lambda d: getattr(d, f"io_requestor_0_resp_bits_excp_0_gpf_st").value == 1, }, name=f"F10_GPF_st_P0") # ---------------- 功能点11:隔离(ASID/VMID/changed) ------------------- diff --git a/ut_mem_block/dtlb/test/test_ld_dtlb.py b/ut_mem_block/dtlb/test/test_ld_dtlb.py index dfee0950..91ee0677 100644 --- a/ut_mem_block/dtlb/test/test_ld_dtlb.py +++ b/ut_mem_block/dtlb/test/test_ld_dtlb.py @@ -100,7 +100,7 @@ async def test_ptwresp_s2_gpf_propagates_to_requestor(dtlb_env): port = 0 gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -118,8 +118,6 @@ async def test_ptwresp_s2_gpf_propagates_to_requestor(dtlb_env): @toffee_test.testcase async def test_priv_mxr_allows_read_exec_only(dtlb_env): - - dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() @@ -135,7 +133,7 @@ async def test_priv_mxr_allows_read_exec_only(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -157,7 +155,6 @@ async def test_priv_mxr_allows_read_exec_only(dtlb_env): @toffee_test.testcase async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): - dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() @@ -173,7 +170,7 @@ async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -195,7 +192,6 @@ async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): @toffee_test.testcase async def test_priv_vmxr_vs_allows_read_exec_only(dtlb_env): - dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() @@ -211,7 +207,7 @@ async def test_priv_vmxr_vs_allows_read_exec_only(dtlb_env): va = 0x0000_0000_8020_3000 gpa = 0x0000_0002_2222_3000 - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -250,7 +246,7 @@ async def test_priv_vsum_vs_supervisor_can_read_user_page(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -288,7 +284,7 @@ async def test_asid_isolation_bare(dtlb_env): pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -304,7 +300,7 @@ async def test_asid_isolation_bare(dtlb_env): await dtlb_env.bundle.step() csr.Satp.changed.value = False - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r2 is None @toffee_test.testcase @@ -324,7 +320,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): port = 0 va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -340,7 +336,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): csr.Vsatp.changed.value = True await dtlb_env.bundle.step() csr.Vsatp.changed.value = False - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r2 is None csr.Vsatp.asid.value = 0x33 @@ -351,7 +347,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): csr.Vsatp.changed.value = False csr.HGatp.changed.value = False - r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) + r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r3 is None @toffee_test.testcase @@ -371,7 +367,7 @@ async def test_vmid_isolation_onlyStage2(dtlb_env): gpa_in = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) await dtlb_env.agent.set_ptw_resp( @@ -391,7 +387,7 @@ async def test_vmid_isolation_onlyStage2(dtlb_env): await dtlb_env.bundle.step() csr.HGatp.changed.value = False - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) assert r2 is None @toffee_test.testcase @@ -410,7 +406,7 @@ async def test_hit_onlyStage1(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD ,return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) assert r0 is None ptw_port, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, va) @@ -442,7 +438,7 @@ async def test_hit_onlyStage2_4k(dtlb_env): gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -477,7 +473,7 @@ async def test_hit_onlyStage2_2m(dtlb_env): gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -513,7 +509,7 @@ async def test_hit_onlyStage2_1g(dtlb_env): gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=LOAD) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -553,7 +549,7 @@ async def test_hit_allStage(dtlb_env): - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) assert r0 is None _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) @@ -586,7 +582,7 @@ async def test_hit_allStage_with_getGpa(dtlb_env): gpa = random.randint(2 ** 12, 2 ** 41 -1) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=LOAD, return_on_miss=True) + _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=LOAD) _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) await dtlb_env.agent.set_ptw_resp( @@ -601,7 +597,6 @@ async def test_hit_allStage_with_getGpa(dtlb_env): _, s2x_req, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gva) assert getGpa_req == 1 - @toffee_test.testcase async def test_parallel_simul_req_miss(dtlb_env): """ @@ -640,7 +635,6 @@ async def test_parallel_simul_req_miss(dtlb_env): requestor[2].req.valid.value = 0 await dtlb_env.bundle.step() - @toffee_test.testcase async def test_parallel_simul_req_hit(dtlb_env): requestor = dtlb_env.bundle.requestor @@ -648,14 +642,13 @@ async def test_parallel_simul_req_hit(dtlb_env): dtlb_env.dut.reset.value = 1; await dtlb_env.bundle.step() dtlb_env.dut.reset.value = 0; await dtlb_env.bundle.step() await dtlb_env.set_sv39_defaults(); await dtlb_env.bundle.step() - VA0 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) - VA1 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) - VA2 = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) - PA0 = random.randint(2 ** 12, 2** 36 - 1) - PA1 = random.randint(2 ** 12, 2** 36 - 1) - PA2 = random.randint(2 ** 12, 2** 36 - 1) + VA0 = 0x0000_0000_8000_0000 + VA1 = 0x0000_0000_8000_1000 + VA2 = 0x0000_0000_8000_2000 + PA0 = 0x0000_0001_0000_0000 + PA1 = 0x0000_0001_0000_1000 + PA2 = 0x0000_0001_0000_2000 - assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=LOAD) == None await dtlb_env.agent.set_ptw_resp(vaddr=VA0,paddr=PA0,level=0) assert await dtlb_env.agent.drive_request(port=0, vaddr=VA0, cmd=LOAD) == ((VA0 & (0xFFF)) | (PA0 & ~(0xFFF))) @@ -668,25 +661,22 @@ async def test_parallel_simul_req_hit(dtlb_env): await dtlb_env.agent.set_ptw_resp(vaddr=VA2,paddr=PA2,level=0) assert await dtlb_env.agent.drive_request(port=0, vaddr=VA2, cmd=LOAD) == ((VA2 & (0xFFF)) | (PA2 & ~(0xFFF))) await dtlb_env.bundle.step() - fullva_0 = int(VA0) & ((1 << 64) - 1) # 完整 64 位 - VA0 = _canon_sv39_vaddr(fullva_0) # Sv39 规范化(再按端口位宽截取) + requestor[0].req.valid.value = 1 requestor[0].req.bits_vaddr.value = VA0 - requestor[0].req.bits_fullva.value = fullva_0 + requestor[0].req.bits_fullva.value = VA0 requestor[0].req.bits_cmd.value = LOAD requestor[0].req.bits_no_translate.value = 0 - fullva_1 = int(VA1) & ((1 << 64) - 1) # 完整 64 位 - VA1 = _canon_sv39_vaddr(fullva_1) # Sv39 规范化(再按端口位宽截取) + requestor[1].req.valid.value = 1 requestor[1].req.bits_vaddr.value = VA1 - requestor[1].req.bits_fullva.value = fullva_1 + requestor[1].req.bits_fullva.value = VA1 requestor[1].req.bits_cmd.value = LOAD requestor[1].req.bits_no_translate.value = 0 - fullva_2 = int(VA2) & ((1 << 64) - 1) # 完整 64 位 - VA2 = _canon_sv39_vaddr(fullva_2) # Sv39 规范化(再按端口位宽截取) + requestor[2].req.valid.value = 1 requestor[2].req.bits_vaddr.value = VA2 - requestor[2].req.bits_fullva.value = fullva_2 + requestor[2].req.bits_fullva.value = VA2 requestor[2].req.bits_cmd.value = LOAD requestor[2].req.bits_no_translate.value = 0 @@ -696,6 +686,7 @@ async def test_parallel_simul_req_hit(dtlb_env): requestor[1].req.valid.value = 0 requestor[2].req.valid.value = 0 await dtlb_env.bundle.step() + @toffee_test.testcase async def test_store_2mb_page(dtlb_env): @@ -706,7 +697,7 @@ async def test_store_2mb_page(dtlb_env): va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<21)-1) pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -730,7 +721,7 @@ async def test_store_1gb_page(dtlb_env): va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=LOAD) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -758,7 +749,7 @@ async def test_express_random(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) assert r0 is None vpn_low = (va >> 12) & 0x7 rand_valididx = [0]*8 @@ -801,7 +792,7 @@ async def test_express_full(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) assert r0 is None vpn_low = (va >> 12) & 0x7 pteidx = [0]*8 @@ -863,7 +854,6 @@ async def test_req_notranslate(dtlb_env): r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, no_translate = 1) assert r0 == va - @toffee_test.testcase async def test_hit_smoke(dtlb_env): @@ -877,7 +867,7 @@ async def test_hit_smoke(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=LOAD) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -901,6 +891,6 @@ async def test_miss_smoke(dtlb_env): await dtlb_env.set_sv39_defaults() await dtlb_env.bundle.step() - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=LOAD, kill=False ,no_translate=False ,return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=LOAD, kill=False ,no_translate=False) - assert r0 is None + assert r0 is None \ No newline at end of file diff --git a/ut_mem_block/dtlb/test/test_plru.py b/ut_mem_block/dtlb/test/test_plru.py index 58a88465..6aa88380 100644 --- a/ut_mem_block/dtlb/test/test_plru.py +++ b/ut_mem_block/dtlb/test/test_plru.py @@ -39,7 +39,7 @@ async def test_plru_random(dtlb_env_plru): vaddr = va[index] paddr = pa[index] - r0 = await dtlb_env_plru.agent.drive_request(port=0, vaddr=vaddr, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env_plru.agent.drive_request(port=0, vaddr=vaddr, cmd=LOAD) if r0 == None: await dtlb_env_plru.agent.set_ptw_resp( @@ -63,7 +63,7 @@ async def test_plru_sweep(dtlb_env_plru): va = BASE_VA + i * 0x8000 pa = BASE_PA + i * 0x1000 - r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env_plru, va) await dtlb_env_plru.agent.set_ptw_resp( @@ -71,14 +71,12 @@ async def test_plru_sweep(dtlb_env_plru): s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s2xlate=s2x ) - r2 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=va, cmd=LOAD) expect = (pa & ~0xFFF) | (va & 0xFFF) assert r2 == expect - new_va = BASE_VA + 0x1000 * 50 new_pa = BASE_PA + 0x1000 * 50 - r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=new_va, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=new_va, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env_plru, new_va) await dtlb_env_plru.agent.set_ptw_resp( @@ -86,12 +84,9 @@ async def test_plru_sweep(dtlb_env_plru): s1_perm_r=True, s1_perm_a=True, s1_perm_u=True, s2xlate=s2x ) - r2 = await dtlb_env_plru.agent.drive_request(port=1, vaddr=new_va, cmd=LOAD) expect = (new_pa & ~0xFFF) | (new_va & 0xFFF) assert r2 == expect - - miss_cnt = 0 for i in range(48): va = BASE_VA + i * 0x8000 diff --git a/ut_mem_block/dtlb/test/test_redirect.py b/ut_mem_block/dtlb/test/test_redirect.py index 5b364fba..1acfdb1a 100644 --- a/ut_mem_block/dtlb/test/test_redirect.py +++ b/ut_mem_block/dtlb/test/test_redirect.py @@ -32,7 +32,7 @@ async def test_redirect_masks_miss_via_lastCycleRedirect(dtlb_env): gpa = 0x0000_0001_2345_0000 hpa = 0x0000_0003_ABCD_0000 - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=0, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) assert r0 is None _, s2x, getGpa_flag = await _wait_ptw_req_and_capture(dtlb_env, gva) @@ -90,7 +90,7 @@ async def test_redirect_level0_kill_younger(dtlb_env): gpa = 0x0000_0001_2345_0000 hpa = 0x0000_0003_ABCD_0000 - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) await dtlb_env.agent.set_ptw_resp( diff --git a/ut_mem_block/dtlb/test/test_sfence.py b/ut_mem_block/dtlb/test/test_sfence.py index f1532a14..d2bfed1e 100644 --- a/ut_mem_block/dtlb/test/test_sfence.py +++ b/ut_mem_block/dtlb/test/test_sfence.py @@ -65,7 +65,7 @@ async def test_sfence_vma_global_noG(dtlb_env): await dtlb_env.bundle.step() # miss → 回填(非 G)→ hit - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, @@ -77,7 +77,7 @@ async def test_sfence_vma_global_noG(dtlb_env): await do_sfence(dtlb_env, hv=False, hg=False, rs1=False, rs2=False) # 应 miss - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None # ========================= @@ -103,7 +103,7 @@ async def test_sfence_vma_by_asid(dtlb_env): - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, @@ -112,7 +112,7 @@ async def test_sfence_vma_by_asid(dtlb_env): # 按当前 satp.asid 清(id 用 CSR.Satp.asid) await do_sfence(dtlb_env, hv=False, hg=False, rs1=False, rs2=True, id_=asid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None # ========================= @@ -137,7 +137,7 @@ async def test_sfence_vma_by_va(dtlb_env): await dtlb_env.bundle.step() - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, @@ -145,7 +145,7 @@ async def test_sfence_vma_by_va(dtlb_env): assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) await do_sfence(dtlb_env, hv=False, hg=False, rs1=True, addr=va, rs2=False) - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None # ========================= @@ -171,7 +171,7 @@ async def test_sfence_vma_by_va_asid(dtlb_env): - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp(vaddr=va, paddr=pa, level=0, s1_asid=asid, s1_perm_r=True, s1_perm_a=True, s1_perm_g=False, @@ -179,7 +179,7 @@ async def test_sfence_vma_by_va_asid(dtlb_env): assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) == ((pa & ~0xFFF) | (va & 0xFFF)) await do_sfence(dtlb_env, hv=False, hg=False, rs1=True, addr=va, rs2=True, id_=asid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=LOAD) is None # ========================= @@ -208,7 +208,7 @@ async def test_hfence_vvma_by_vmid(dtlb_env): - assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) await dtlb_env.agent.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, s1_asid=asid, s1_vmid=vmid, @@ -218,7 +218,7 @@ async def test_hfence_vvma_by_vmid(dtlb_env): # VVMA:hv=1,通常按 VMID 过滤需 rs2=1;VMID 来源于 CSR.HGATP.vmid(id 忽略) await do_sfence(dtlb_env, hv=True, hg=False, rs1=False, rs2=True, id_=vmid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) is None # ========================= @@ -245,7 +245,7 @@ async def test_hfence_vvma_by_gva_vmid(dtlb_env): csr.HGatp.vmid.value = vmid await dtlb_env.bundle.step() - assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, gva) await dtlb_env.agent.set_ptw_resp(vaddr=gva, paddr=gpa, level=0, s1_asid=asid, s1_vmid=vmid, @@ -254,7 +254,7 @@ async def test_hfence_vvma_by_gva_vmid(dtlb_env): assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) == ((gpa & ~0xFFF) | (gva & 0xFFF)) await do_sfence(dtlb_env, hv=True, hg=False, rs1=True, addr=gva, rs2=True, id_=vmid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=LOAD) is None # ========================= @@ -279,7 +279,7 @@ async def test_hfence_gvma_by_vmid(dtlb_env): csr.HGatp.vmid.value = vmid await dtlb_env.bundle.step() - assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) await dtlb_env.agent.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, s2xlate=s2x, getGpa=getGpa_req, @@ -290,7 +290,7 @@ async def test_hfence_gvma_by_vmid(dtlb_env): # GVMA:hg=1,按 VMID(来自 bits_id)清 S2 await do_sfence(dtlb_env, hv=False, hg=True, rs1=False, rs2=True, id_=vmid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) is None # ========================= @@ -315,7 +315,7 @@ async def test_hfence_gvma_by_gpa_vmid(dtlb_env): csr.HGatp.vmid.value = vmid await dtlb_env.bundle.step() - assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) await dtlb_env.agent.set_ptw_resp(vaddr=gpa_in, paddr=0, level=0, s1_v=False, s2xlate=s2x, getGpa=getGpa_req, @@ -325,4 +325,4 @@ async def test_hfence_gvma_by_gpa_vmid(dtlb_env): assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) == ((hpa & ~0xFFF) | (gpa_in & 0xFFF)) await do_sfence(dtlb_env, hv=False, hg=True, rs1=True, addr=gpa_in, rs2=True, id_=vmid) - assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD, return_on_miss=True) is None + assert await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=LOAD) is None diff --git a/ut_mem_block/dtlb/test/test_st_dtlb.py b/ut_mem_block/dtlb/test/test_st_dtlb.py index 55ef158d..37f278d9 100644 --- a/ut_mem_block/dtlb/test/test_st_dtlb.py +++ b/ut_mem_block/dtlb/test/test_st_dtlb.py @@ -132,7 +132,7 @@ async def test_priv_sum_supervisor_can_read_user_page(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -172,7 +172,7 @@ async def test_priv_vsum_vs_supervisor_can_read_user_page(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -209,7 +209,7 @@ async def test_asid_isolation_bare(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -225,7 +225,7 @@ async def test_asid_isolation_bare(dtlb_env): csr.Satp.asid.value = 0x21 await dtlb_env.bundle.step() - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r2 is None @toffee_test.testcase @@ -246,7 +246,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r0 is None _, s2x, _ = await _wait_ptw_req_and_capture(dtlb_env, va) await dtlb_env.agent.set_ptw_resp( @@ -263,7 +263,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): csr.Vsatp.changed.value = True await dtlb_env.bundle.step() csr.Vsatp.changed.value = False - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r2 is None csr.Vsatp.asid.value = 0x33 @@ -274,7 +274,7 @@ async def test_asid_isolation_onlyStage1(dtlb_env): csr.Vsatp.changed.value = False csr.HGatp.changed.value = False - r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE, return_on_miss=True) + r3 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r3 is None @toffee_test.testcase @@ -294,7 +294,7 @@ async def test_vmid_isolation_onlyStage2(dtlb_env): gpa_in = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa_in) await dtlb_env.agent.set_ptw_resp( @@ -315,7 +315,7 @@ async def test_vmid_isolation_onlyStage2(dtlb_env): await dtlb_env.bundle.step() csr.HGatp.changed.value = False - r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE, return_on_miss=True) + r2 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa_in, cmd=STORE) assert r2 is None @toffee_test.testcase @@ -334,7 +334,7 @@ async def test_hit_onlyStage1(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) gpa = random.randint(2 ** 12, 2 ** 41 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE ,return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=va, cmd=STORE) assert r0 is None ptw_port, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, va) @@ -366,7 +366,7 @@ async def test_hit_onlyStage2_4k(dtlb_env): gpa = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -401,7 +401,7 @@ async def test_hit_onlyStage2_2m(dtlb_env): hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -438,7 +438,7 @@ async def test_hit_onlyStage2_1g(dtlb_env): hpa = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gpa, cmd=STORE) assert r0 is None _, s2x, getGpa_req = await _wait_ptw_req_and_capture(dtlb_env, gpa) @@ -475,7 +475,7 @@ async def test_hit_allStage(dtlb_env): gpa = random.randint(2 ** 12, 2 ** 41 -1) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=port, vaddr=gva, cmd=STORE) assert r0 is None _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) @@ -510,7 +510,7 @@ async def test_hit_allStage_with_getGpa(dtlb_env): gpa = random.randint(2 ** 12, 2 ** 41 -1) hpa = random.randint(2 ** 12, 2 ** 36 - 1) - _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=STORE, return_on_miss=True) + _ = await dtlb_env.agent.drive_request(port=0, vaddr=gva, cmd=STORE) _, s2x, getGpa_ptw = await _wait_ptw_req_and_capture(dtlb_env, gva) await dtlb_env.agent.set_ptw_resp( @@ -627,7 +627,7 @@ async def test_store_2mb_page(dtlb_env): pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<21)-1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -654,7 +654,7 @@ async def test_store_1gb_page(dtlb_env): va_base = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) & ~((1<<30)-1) pa_base = random.randint(2 ** 12, 2 ** 36 - 1) & ~((1<<30)-1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va_base, cmd=STORE) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -681,7 +681,7 @@ async def test_express_random(dtlb_env): await dtlb_env.bundle.step() va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) assert r0 is None vpn_low = (va >> 12) & 0x7 ppn_low = (pa >> 12) & 0x7 @@ -727,7 +727,7 @@ async def test_express_full(dtlb_env): va = _canon_sv39_vaddr(random.randint(2 ** 12, 2 ** 39 - 1)) pa = random.randint(2 ** 12, 2 ** 36 - 1) - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=va, cmd=STORE) assert r0 is None vpn_low = (va >> 12) & 0x7 pteidx = [0]*8 @@ -801,7 +801,7 @@ async def test_hit_smoke(dtlb_env): await dtlb_env.set_sv39_defaults() await dtlb_env.bundle.step() - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE, return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE) assert r0 is None await dtlb_env.agent.set_ptw_resp( @@ -828,6 +828,6 @@ async def test_miss_smoke(dtlb_env): await dtlb_env.set_sv39_defaults() await dtlb_env.bundle.step() - r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE, kill=False ,no_translate=False ,return_on_miss=True) + r0 = await dtlb_env.agent.drive_request(port=0, vaddr=0x0000_0000_8020_1000, cmd=STORE, kill=False ,no_translate=False) assert r0 is None \ No newline at end of file