From 921e6bd5a19ecd1c14ac1e17d79d1b4b7cf1e2fa Mon Sep 17 00:00:00 2001 From: kenny Date: Sun, 17 Aug 2025 15:58:08 +0800 Subject: [PATCH] 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