# Copyright 2025 Apheleia
#
# Description:
# Apheleia Verification Library Interface
from typing import Any
from cocotb.handle import HierarchyObject
parameters = [
"CLASSIFICATION",
"VERSION",
"ADDR_WIDTH",
"ARSNOOP_WIDTH",
"AWCMO_WIDTH",
"AWSNOOP_WIDTH",
"BRESP_WIDTH",
"DATA_WIDTH",
"ID_R_WIDTH",
"ID_W_WIDTH",
"LOOP_R_WIDTH",
"LOOP_W_WIDTH",
"MECID_WIDTH",
"MPAM_WIDTH",
"RCHUNKNUM_WIDTH",
"RCHUNKSTRB_WIDTH",
"RRESP_WIDTH",
"SECSID_WIDTH",
"SID_WIDTH",
"SSID_WIDTH",
"SUBSYSID_WIDTH",
"USER_DATA_WIDTH",
"USER_REQ_WIDTH",
"USER_RESP_WIDTH",
"Atomic_Transactions",
"Busy_Support",
"BURST_Present",
"CACHE_Present",
"Cache_Line_Size",
"Cache_Stash_Transactions",
"CMO_On_Read",
"CMO_On_Write",
"Coherency_Connection_Signals",
"Consistent_DECERR",
"DeAllocation_Transactions",
"Device_Normal_Independence",
"DVM_Message_Support",
"DVM_v8",
"DVM_v8_1",
"DVM_v8_4",
"DVM_v9_2",
"Exclusive_Accesses",
"Fixed_Burst_Disable",
"InvalidateHint_Transaction",
"LEN_Present",
"Loopback_Signals",
"Max_Transaction_Bytes",
"MEC_Support",
"MMUFLOW_Present",
"MPAM_Support",
"MTE_Support",
"Multi_Copy_Atomicity",
"NSAccess_Identifiers",
"Ordered_Write_Observation",
"PBHA_Support",
"Persist_CMO",
"Poison",
"Prefetch_Transaction",
"PROT_Present",
"QoS_Accept",
"QOS_Present",
"Read_Data_Chunking",
"Read_Interleaving_Disabled",
"REGION_Present",
"Regular_Transactions_Only",
"RLAST_Present",
"RME_Support",
"Shareable_Cache_Support",
"Shareable_Transactions",
"SIZE_Present",
"STASHLPID_Present",
"STASHNID_Present",
"Trace_Signals",
"Unique_ID_Support",
"UnstashTranslation_Transaction",
"Untranslated_Transactions",
"Wakeup_Signals",
"WLAST_Present",
"Write_Plus_CMO",
"WriteDeferrable_Transaction",
"WriteNoSnoopFull_Transaction",
"WriteZero_Transaction",
"WSTRB_Present",
"AXI_Transport",
"Shared_Credits_AW",
"Shared_Credits_W",
"Shared_Credits_AR",
"Num_RP_AWW",
"Num_RP_AR",
"NUM_CREDITS",
"NUM_SHARED_CREDITS",
"STRB_WIDTH",
"RUSER_WIDTH",
"CMO_WIDTH",
"TAG_WIDTH",
"TAGUPDATE_WIDTH",
"POISON_WIDTH",
"NUM_RP_AWW_WIDTH",
"NUM_RP_AR_WIDTH",
]
signals = [
"acaddr",
"aclk",
"acready",
"actrace",
"acvalid",
"acvmidext",
"acwakeup",
"araddr",
"arburst",
"arcache",
"archunken",
"arcrdt",
"arcrdtsh",
"arcredits",
"ardomain",
"aresetn",
"arid",
"aridunq",
"arlen",
"arlock",
"arloop",
"armecid",
"armmuatst",
"armmuflow",
"armmusecsid",
"armmusid",
"armmussid",
"armmussidv",
"armmuvalid",
"armpam",
"arnsaid",
"arnse",
"arpbha",
"arpending",
"arprot",
"arqos",
"arready",
"arregion",
"arrp",
"arsharedcrd",
"arsize",
"arsnoop",
"arsubsysid",
"artagop",
"artrace",
"aruser",
"arvalid",
"awaddr",
"awakeup",
"awatop",
"awburst",
"awcache",
"awcmo",
"awcrdt",
"awcrdtsh",
"awcredits",
"awdomain",
"awid",
"awidunq",
"awlen",
"awlock",
"awloop",
"awmecid",
"awmmuatst",
"awmmuflow",
"awmmusecsid",
"awmmusid",
"awmmussid",
"awmmussidv",
"awmmuvalid",
"awmpam",
"awnsaid",
"awnse",
"awpbha",
"awpending",
"awprot",
"awqos",
"awready",
"awregion",
"awrp",
"awsharedcrd",
"awsize",
"awsnoop",
"awstashlpid",
"awstashlpiden",
"awstashnid",
"awstashniden",
"awsubsysid",
"awtagop",
"awtrace",
"awuser",
"awvalid",
"bbusy",
"bcomp",
"bcrdt",
"bcredits",
"bid",
"bidunq",
"bloop",
"bpending",
"bpersist",
"bready",
"bresp",
"btagmatch",
"btrace",
"buser",
"bvalid",
"crready",
"crtrace",
"crvalid",
"rbusy",
"rchunknum",
"rchunkstrb",
"rchunkv",
"rcrdt",
"rcredits",
"rdata",
"rid",
"ridunq",
"rlast",
"rloop",
"rpending",
"rpoison",
"rready",
"rresp",
"rtag",
"rtrace",
"ruser",
"rvalid",
"syscoack",
"syscoreq",
"varqosaccept",
"vawqosaccept",
"wcrdt",
"wcrdtsh",
"wcredits",
"wdata",
"wlast",
"wpending",
"wpoison",
"wready",
"wrp",
"wsharedcrd",
"wstrb",
"wtag",
"wtagupdate",
"wtrace",
"wuser",
"wvalid",
]
[docs]
class Interface:
[docs]
def __init__(self, hdl : HierarchyObject) -> None: # noqa: C901
"""
Create an interface
Work around simulator specific issues with accessing signals inside generates.
:param hdl: The handle to the interface
:type hdl: HierarchyObject
:return: None
"""
# Parameters
for p in parameters:
# Parameters not exposed by list() in some simulators - look up explicitly
v = getattr(hdl, p)
if isinstance(v.value, bytes):
setattr(self, p, str(v.value.decode("utf-8")))
else:
setattr(self, p, int(v.value))
# Signals
for s in signals:
# Some simulators do not expose signals inside interfaces through list(hdl).
# Populate the _sub_handle cache explicitly.
child = getattr(hdl, s)
setattr(self, child._name, child)
if self.CLASSIFICATION != "AXI":
raise TypeError(f"Expected AXI classification, got {self.CLASSIFICATION}")
if self.VERSION not in [5]:
raise ValueError(f"Unsupported AXI version: {self.VERSION}")
# Remove un-configured signals
if self.ID_W_WIDTH == 0:
delattr(self, "awid")
delattr(self, "bid")
if self.REGION_Present == 0:
delattr(self, "awregion")
delattr(self, "arregion")
if self.LEN_Present == 0:
delattr(self, "awlen")
delattr(self, "arlen")
if self.SIZE_Present == 0:
delattr(self, "awsize")
delattr(self, "arsize")
if self.BURST_Present == 0:
delattr(self, "awburst")
delattr(self, "arburst")
if self.Exclusive_Accesses == 0:
delattr(self, "awlock")
delattr(self, "arlock")
if self.CACHE_Present == 0:
delattr(self, "awcache")
delattr(self, "arcache")
if self.PROT_Present == 0:
delattr(self, "awprot")
delattr(self, "arprot")
if self.RME_Support == 0:
delattr(self, "awnse")
delattr(self, "arnse")
if self.QOS_Present == 0:
delattr(self, "awqos")
delattr(self, "arqos")
if self.USER_REQ_WIDTH == 0:
delattr(self, "awuser")
delattr(self, "aruser")
if self.Shareable_Transactions == 0:
delattr(self, "awdomain")
delattr(self, "ardomain")
if self.AWSNOOP_WIDTH == 0:
delattr(self, "awsnoop")
if self.ARSNOOP_WIDTH == 0:
delattr(self, "arsnoop")
if self.STASHNID_Present == 0:
delattr(self, "awstashnid")
delattr(self, "awstashniden")
delattr(self, "awstashlpid")
delattr(self, "awstashlpiden")
if self.Trace_Signals == 0:
delattr(self, "awtrace")
delattr(self, "wtrace")
delattr(self, "btrace")
delattr(self, "artrace")
delattr(self, "rtrace")
if self.Loopback_Signals == 0 or self.LOOP_W_WIDTH == 0:
delattr(self, "awloop")
delattr(self, "bloop")
if self.Loopback_Signals == 0 or self.LOOP_R_WIDTH == 0:
delattr(self, "arloop")
delattr(self, "rloop")
if self.Untranslated_Transactions != "v3":
delattr(self, "awmmuvalid")
delattr(self, "armmuvalid")
if self.Untranslated_Transactions == "False" or self.SECSID_WIDTH == 0:
delattr(self, "awmmusecsid")
delattr(self, "armmusecsid")
if self.Untranslated_Transactions == "False" or self.SID_WIDTH == 0:
delattr(self, "awmmusid")
delattr(self, "armmusid")
if self.Untranslated_Transactions == "False" or self.SSID_WIDTH == 0:
delattr(self, "awmmussidv")
delattr(self, "awmmussid")
delattr(self, "armmussidv")
delattr(self, "armmussid")
if self.MMUFLOW_Present == 0 or (self.Untranslated_Transactions not in ["v1", "True"]):
delattr(self, "awmmuatst")
delattr(self, "armmuatst")
if self.MMUFLOW_Present == 0 or (self.Untranslated_Transactions not in ["v2", "v3"]):
delattr(self, "awmmuflow")
delattr(self, "armmuflow")
if self.PBHA_Support == 0:
delattr(self, "awpbha")
delattr(self, "arpbha")
if self.MEC_Support == 0:
delattr(self, "awmecid")
delattr(self, "armecid")
if self.NSAccess_Identifiers == 0:
delattr(self, "awnsaid")
delattr(self, "arnsaid")
if self.SUBSYSID_WIDTH == 0:
delattr(self, "awsubsysid")
delattr(self, "arsubsysid")
if self.Atomic_Transactions == 0:
delattr(self, "awatop")
if self.MPAM_Support == "False":
delattr(self, "awmpam")
delattr(self, "armpam")
if self.Unique_ID_Support == 0 or self.ID_W_WIDTH == 0:
delattr(self, "awidunq")
delattr(self, "bidunq")
if self.Unique_ID_Support == 0 or self.ID_R_WIDTH == 0:
delattr(self, "aridunq")
delattr(self, "ridunq")
if self.CMO_On_Write == 0:
delattr(self, "awcmo")
if self.MTE_Support == "False":
delattr(self, "awtagop")
delattr(self, "wtag")
delattr(self, "wtagupdate")
delattr(self, "artagop")
delattr(self, "rtag")
if self.WSTRB_Present == 0:
delattr(self, "wstrb")
if self.WLAST_Present == 0:
delattr(self, "wlast")
if self.USER_DATA_WIDTH == 0:
delattr(self, "wuser")
if self.Poison == 0:
delattr(self, "wpoison")
delattr(self, "rpoison")
if self.BRESP_WIDTH == 0:
delattr(self, "bresp")
if (self.Persist_CMO == 0 or self.CMO_On_Write == 0) and self.MTE_Support != "Standard":
delattr(self, "bcomp")
if self.Persist_CMO == 0 or self.CMO_On_Write == 0:
delattr(self, "bpersist")
if self.MTE_Support != "Standard":
delattr(self, "btagmatch")
if self.USER_RESP_WIDTH == 0:
delattr(self, "buser")
if self.Busy_Support == 0:
delattr(self, "bbusy")
delattr(self, "rbusy")
if self.ID_R_WIDTH == 0:
delattr(self, "arid")
delattr(self, "rid")
if self.RRESP_WIDTH == 0:
delattr(self, "rresp")
if self.RLAST_Present == 0:
delattr(self, "rlast")
if self.USER_DATA_WIDTH == 0 and self.USER_RESP_WIDTH == 0:
delattr(self, "ruser")
if self.Read_Data_Chunking == 0:
delattr(self, "archunken")
delattr(self, "rchunkv")
if self.Read_Data_Chunking == 0 or self.RCHUNKNUM_WIDTH == 0:
delattr(self, "rchunknum")
if self.Read_Data_Chunking == 0 or self.RCHUNKSTRB_WIDTH == 0:
delattr(self, "rchunkstrb")
if self.DVM_Message_Support == "False":
delattr(self, "acvalid")
delattr(self, "acready")
delattr(self, "acaddr")
delattr(self, "acvmidext")
delattr(self, "crvalid")
delattr(self, "crready")
if self.DVM_Message_Support == "False" or self.Trace_Signals == 0:
delattr(self, "actrace")
delattr(self, "crtrace")
if self.Wakeup_Signals == 0:
delattr(self, "awakeup")
if self.Wakeup_Signals == 0 or self.DVM_Message_Support == "False":
delattr(self, "acwakeup")
if self.QoS_Accept == 0:
delattr(self, "varqosaccept")
delattr(self, "vawqosaccept")
if self.Coherency_Connection_Signals == 0:
delattr(self, "syscoreq")
delattr(self, "syscoack")
if self.AXI_Transport != "Credited":
delattr(self, "awpending")
delattr(self, "awcrdt")
delattr(self, "awrp")
delattr(self, "wpending")
delattr(self, "wcrdt")
delattr(self, "wrp")
delattr(self, "bpending")
delattr(self, "bcrdt")
delattr(self, "arpending")
delattr(self, "arcrdt")
delattr(self, "arrp")
delattr(self, "rpending")
delattr(self, "rcrdt")
if self.Shared_Credits_AW == 0:
delattr(self, "awcrdtsh")
delattr(self, "awsharedcrd")
if self.Shared_Credits_W == 0:
delattr(self, "wcrdtsh")
delattr(self, "wsharedcrd")
if self.Shared_Credits_AR == 0:
delattr(self, "arcrdtsh")
delattr(self, "arsharedcrd")
else:
delattr(self, "awready")
delattr(self, "arready")
delattr(self, "wready")
delattr(self, "bready")
delattr(self, "rready")
# Sanity checks
if hasattr(self, "awlock"):
if not hasattr(self, "rresp") or len(self.rresp) < 2:
raise ValueError("AXI Exclusive accesses require RRESP to be 2 bits wide (minimum)")
if not hasattr(self, "bresp") or len(self.bresp) < 2:
raise ValueError("AXI Exclusive accesses require BRESP to be 2 bits wide (minimum)")
[docs]
def set(self, name : str, value : int, idx : int = None, ) -> None:
"""
Set the value of a signal (if signal exists)
:param name: The name of the signal
:type name: str
:param value: The value to set
:type value: int
:param idx: The index if array
:type idx: int
:return: None
"""
signal = getattr(self, name, None)
if signal is not None:
if idx is not None:
signal[idx].value = value
else:
signal.value = value
[docs]
def get(self, name : str, idx : int = None, default : Any = None) -> int:
"""
Get the value of a signal (if signal exists)
:param name: The name of the signal
:type name: str
:param idx: The index if array
:type idx: int
:param default: The default value to return if signal does not exist
:type default: Any
:return: The value of the signal or the default value
:rtype: int
"""
signal = getattr(self, name, None)
if signal is not None:
if idx is not None:
return signal[idx].value
else:
return signal.value
return default
__all__ = ["Interface"]