# Copyright 2025 Apheleia
#
# Description:
# Apheleia Verification Library Types
from collections.abc import Callable
from typing import Any
import avl
[docs]
class axi_burst_t(avl.Logic):
FIXED = 0
INCR = 1
WRAP = 2
RESERVED = 3
[docs]
def __init__(self, value : Any, width : int = 1, auto_random : bool=False, fmt: Callable[..., int] = None) -> None:
"""
Enumeration for the AXI Burst type
- 0 : FIXED
- 1 : INCR
- 2 : WRAP
- 3 : RESERVED
:param value: The value to assign to the AXI Burst type.
:param auto_random: Whether to use automatic randomization.
:param fmt: The format string for the AXI Burst type.
:return: None
"""
super().__init__(value, width=width, auto_random=auto_random, fmt=fmt)
# Avoid randomizing to reserve value
self.add_constraint("c_reserved", lambda x: x != axi_burst_t.RESERVED)
if self._fmt_ is None:
self._fmt_ = self.fmt
[docs]
def fmt(self, value : int) -> str:
"""
Custom format
:param value: The value to format.
:return: The formatted string.
"""
return self.values()[value]
[docs]
def values(self) -> dict[str, int]:
"""
Return a dictionary of types
:return dict
:rtype: dict[str, int]
"""
d = {
axi_burst_t.FIXED : "FIXED",
axi_burst_t.INCR : "INCR",
axi_burst_t.WRAP : "WRAP",
axi_burst_t.RESERVED : "RESERVED",
}
for i in range(axi_burst_t.FIXED, axi_burst_t.RESERVED, 1):
if i > (2**self.width)-1:
del d[i]
return d
def _cast_(self, other : Any) -> bool:
"""
Casts the given value to the AXI Burst type.
:param other: The value to cast.
:return: True if the cast was successful, False otherwise.
"""
if int(other) == axi_burst_t.RESERVED:
raise ValueError("Cannot assign RESERVED value to axi_burst_t")
return super()._cast_(other)
[docs]
class axi_resp_t(avl.Logic):
OKAY = 0
EXOKAY = 1
SLVERR = 2
DECERR = 3
DEFER = 4
TRANSFAULT = 5
RESERVED = 6
UNSUPPORTED = 7
[docs]
def __init__(self, value : Any, width : int = 1, auto_random : bool=False, fmt: Callable[..., int] = None) -> None:
"""
Enumeration for the AXI Response type
- 0 : OKAY
- 1 : EXOKAY
- 2 : SLVERR
- 3 : DECERR
- 4 : DEFER
- 5 : TRANSFAULT
- 6 : RESERVED
- 7 : UNSUPPORTED
:param value: The value to assign to the AXI Burst type.
:param auto_random: Whether to use automatic randomization.
:param fmt: The format string for the AXI Burst type.
:return: None
"""
super().__init__(value, width=width, auto_random=auto_random, fmt=fmt)
# Avoid randomizing to reserve value
self.add_constraint("c_reserved", lambda x: x != axi_resp_t.RESERVED)
if self._fmt_ is None:
self._fmt_ = self.fmt
[docs]
def fmt(self, value : int) -> str:
"""
Custom format
:param value: The value to format.
:return: The formatted string.
"""
return self.values()[value]
[docs]
def values(self) -> dict[str, int]:
"""
Return a dictionary of types
:return dict
:rtype: dict[str, int]
"""
d = {
axi_resp_t.OKAY : "OKAY",
axi_resp_t.EXOKAY : "EXOKAY",
axi_resp_t.SLVERR : "SLVERR",
axi_resp_t.DECERR : "DECERR",
axi_resp_t.DEFER : "DEFER",
axi_resp_t.TRANSFAULT : "TRANSFAULT",
axi_resp_t.RESERVED : "RESERVED",
axi_resp_t.UNSUPPORTED : "UNSUPPORTED",
}
for i in range(axi_resp_t.OKAY, axi_resp_t.UNSUPPORTED, 1):
if i > (2**self.width)-1:
del d[i]
return d
def _cast_(self, other : Any) -> bool:
"""
Casts the given value to the AXI Burst type.
:param other: The value to cast.
:return: True if the cast was successful, False otherwise.
"""
if int(other) == axi_resp_t.RESERVED:
raise ValueError("Cannot assign RESERVED value to axi_resp_t")
return super()._cast_(other)
[docs]
class axi_domain_t(avl.Logic):
NON_SHAREABLE = 0
INNER_SHAREABLE = 1
OUTER_SHAREABLE = 2
SYSTEM = 3
[docs]
def __init__(self, value : Any, width : int = 1, auto_random : bool=False, fmt: Callable[..., int] = None) -> None:
"""
Enumeration for the AXI domain type
- 0 : NON_SHAREABLE
- 1 : SHAREABLE (INNER)
- 2 : SHAREABLE (OUTER)
- 3 : SYSTEM
:param value: The value to assign to the AXI domain type.
:param auto_random: Whether to use automatic randomization.
:param fmt: The format string for the AXI domain type.
:return: None
"""
super().__init__(value, width=width, auto_random=auto_random, fmt=fmt)
if self._fmt_ is None:
self._fmt_ = self.fmt
[docs]
def fmt(self, value : int) -> str:
"""
Custom format
:param value: The value to format.
:return: The formatted string.
"""
return self.values()[value]
[docs]
def values(self) -> dict[str, int]:
"""
Return a dictionary of types
:return dict
:rtype: dict[str, int]
"""
d = {
axi_domain_t.NON_SHAREABLE : "NON_SHAREABLE",
axi_domain_t.INNER_SHAREABLE : "INNER_SHAREABLE",
axi_domain_t.OUTER_SHAREABLE : "OUTER_SHAREABLE",
axi_domain_t.SYSTEM : "SYSTEM",
}
for i in range(axi_domain_t.NON_SHAREABLE, axi_domain_t.SYSTEM, 1):
if i > (2**self.width)-1:
del d[i]
return d
[docs]
class axi_atomic_t(avl.Logic):
NON_ATOMIC = 0b000000
STORE_LE_ADD = 0b010000
STORE_LE_CLR = 0b010001
STORE_LE_EOR = 0b010010
STORE_LE_SET = 0b010011
STORE_LE_SMAX = 0b010100
STORE_LE_SMIN = 0b010101
STORE_LE_UMAX = 0b010110
STORE_LE_UMIN = 0b010111
LOAD_LE_ADD = 0b100000
LOAD_LE_CLR = 0b100001
LOAD_LE_EOR = 0b100010
LOAD_LE_SET = 0b100011
LOAD_LE_SMAX = 0b100100
LOAD_LE_SMIN = 0b100101
LOAD_LE_UMAX = 0b100110
LOAD_LE_UMIN = 0b100111
SWAP = 0b110000
COMPARE = 0b110001
STORE_BE_ADD = 0b011000
STORE_BE_CLR = 0b011001
STORE_BE_EOR = 0b011010
STORE_BE_SET = 0b011011
STORE_BE_SMAX = 0b011100
STORE_BE_SMIN = 0b011101
STORE_BE_UMAX = 0b011110
STORE_BE_UMIN = 0b011111
LOAD_BE_ADD = 0b101000
LOAD_BE_CLR = 0b101001
LOAD_BE_EOR = 0b101010
LOAD_BE_SET = 0b101011
LOAD_BE_SMAX = 0b101100
LOAD_BE_SMIN = 0b101101
LOAD_BE_UMAX = 0b101110
LOAD_BE_UMIN = 0b101111
[docs]
def __init__(self, value : Any, width : int = 1, auto_random : bool=False, fmt: Callable[..., int] = None) -> None:
"""
Enumeration for the AXI Atomic type
:param value: The value to assign to the AXI Burst type.
:param auto_random: Whether to use automatic randomization.
:param fmt: The format string for the AXI Burst type.
:return: None
"""
super().__init__(value, width=width, auto_random=auto_random, fmt=fmt)
if self._fmt_ is None:
self._fmt_ = self.fmt
[docs]
def fmt(self, value : int) -> str:
"""
Custom format
:param value: The value to format.
:return: The formatted string.
"""
return self.values()[value]
[docs]
def values(self) -> dict[str, int]:
"""
Return a dictionary of types
:return dict
:rtype: dict[str, int]
"""
d = {
axi_atomic_t.NON_ATOMIC : "NON_ATOMIC",
axi_atomic_t.STORE_LE_ADD : "STORE_LE_ADD",
axi_atomic_t.STORE_LE_CLR : "STORE_LE_CLR",
axi_atomic_t.STORE_LE_EOR : "STORE_LE_EOR",
axi_atomic_t.STORE_LE_SET : "STORE_LE_SET",
axi_atomic_t.STORE_LE_SMAX : "STORE_LE_SMAX",
axi_atomic_t.STORE_LE_SMIN : "STORE_LE_SMIN",
axi_atomic_t.STORE_LE_UMAX : "STORE_LE_UMAX",
axi_atomic_t.STORE_LE_UMIN : "STORE_LE_UMIN",
axi_atomic_t.LOAD_LE_ADD : "LOAD_LE_ADD",
axi_atomic_t.LOAD_LE_CLR : "LOAD_LE_CLR",
axi_atomic_t.LOAD_LE_EOR : "LOAD_LE_EOR",
axi_atomic_t.LOAD_LE_SET : "LOAD_LE_SET",
axi_atomic_t.LOAD_LE_SMAX : "LOAD_LE_SMAX",
axi_atomic_t.LOAD_LE_SMIN : "LOAD_LE_SMIN",
axi_atomic_t.LOAD_LE_UMAX : "LOAD_LE_UMAX",
axi_atomic_t.LOAD_LE_UMIN : "LOAD_LE_UMIN",
axi_atomic_t.SWAP : "SWAP",
axi_atomic_t.COMPARE : "COMPARE",
axi_atomic_t.STORE_BE_ADD : "STORE_BE_ADD",
axi_atomic_t.STORE_BE_CLR : "STORE_BE_CLR",
axi_atomic_t.STORE_BE_EOR : "STORE_BE_EOR",
axi_atomic_t.STORE_BE_SET : "STORE_BE_SET",
axi_atomic_t.STORE_BE_SMAX : "STORE_BE_SMAX",
axi_atomic_t.STORE_BE_SMIN : "STORE_BE_SMIN",
axi_atomic_t.STORE_BE_UMAX : "STORE_BE_UMAX",
axi_atomic_t.STORE_BE_UMIN : "STORE_BE_UMIN",
axi_atomic_t.LOAD_BE_ADD : "LOAD_BE_ADD",
axi_atomic_t.LOAD_BE_CLR : "LOAD_BE_CLR",
axi_atomic_t.LOAD_BE_EOR : "LOAD_BE_EOR",
axi_atomic_t.LOAD_BE_SET : "LOAD_BE_SET",
axi_atomic_t.LOAD_BE_SMAX : "LOAD_BE_SMAX",
axi_atomic_t.LOAD_BE_SMIN : "LOAD_BE_SMIN",
axi_atomic_t.LOAD_BE_UMAX : "LOAD_BE_UMAX",
axi_atomic_t.LOAD_BE_UMIN : "LOAD_BE_UMIN",
}
for i in range(axi_atomic_t.NON_ATOMIC, axi_atomic_t.LOAD_BE_UMIN, 1):
if i > (2**self.width)-1:
del d[i]
return d
[docs]
def has_bresp(self) -> bool:
"""
Returns True if the operation generates a BRESP response, False otherwise.
Currently all atomic operations return bresp - however implementing explicitly
for symmetry and future proofing
:return: bool
:rtype: bool
"""
return True
[docs]
def has_rresp(self) -> bool:
"""
Returns True if the operation generates a RRESP response, False otherwise.
:return: bool
:rtype: bool
"""
if self.value & 0b100000 != 0:
return True
return False
[docs]
def endianness(self) -> str:
"""
Returns the endianness of the operation.
:return: "little" or "big"
:rtype: str
"""
if self.value & 0b001000 == 0:
return "little"
else:
return "big"
[docs]
class axi_secsid_t(avl.Logic):
NON_SECURE = 0
SECURE = 1
REALM = 2
RESERVED = 3
[docs]
def __init__(self, value : Any, width : int = 1, auto_random : bool=False, fmt: Callable[..., int] = None) -> None:
"""
Enumeration for the AXI secure stream identifier type
- 0 : NON_SECURE
- 1 : SECURE
- 2 : REALM
- 3 : RESERVED
:param value: The value to assign to the AXI domain type.
:param auto_random: Whether to use automatic randomization.
:param fmt: The format string for the AXI domain type.
:return: None
"""
super().__init__(value, width=width, auto_random=auto_random, fmt=fmt)
# Avoid randomizing to reserve value
self.add_constraint("c_reserved", lambda x: x != axi_secsid_t.RESERVED)
if self._fmt_ is None:
self._fmt_ = self.fmt
[docs]
def fmt(self, value : int) -> str:
"""
Custom format
:param value: The value to format.
:return: The formatted string.
"""
return self.values()[value]
[docs]
def values(self) -> dict[str, int]:
"""
Return a dictionary of types
:return dict
:rtype: dict[str, int]
"""
d = {
axi_secsid_t.NON_SECURE : "NON_SECURE",
axi_secsid_t.SECURE : "SECURE",
axi_secsid_t.REALM : "REALM",
axi_secsid_t.RESERVED : "RESERVED",
}
for i in range(axi_secsid_t.NON_SECURE, axi_secsid_t.RESERVED, 1):
if i > (2**self.width)-1:
del d[i]
return d
[docs]
def signal_to_type(signal : str) -> Any:
"""
Converts a signal string to the corresponding type class instance.
:param signal: The signal string to convert.
:param type_class: The type class to use for conversion.
:return: An instance of the type class corresponding to the signal.
"""
if signal.endswith("burst"):
return axi_burst_t
elif signal.endswith("resp"):
return axi_resp_t
elif signal == "awatop":
return axi_atomic_t
elif signal.endswith("mmusecsid"):
return axi_secsid_t
else:
return avl.Logic
__all__ = [
"axi_burst_t",
"axi_resp_t",
"axi_domain_t",
"axi_atomic_t",
"axi_secsid_t",
"signal_to_type",
]