Source code for microprobe.target.isa.register

# Copyright 2011-2021 IBM Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""":mod:`microprobe.target.isa.register` module

"""

# Futures
from __future__ import absolute_import, annotations

# Built-in modules
import abc
import hashlib
import os
from typing import List, TYPE_CHECKING

# Third party modules

# Own modules
from microprobe.exceptions import MicroprobeArchitectureDefinitionError
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import Pickable
from microprobe.utils.typeguard_decorator import typeguard_testsuite
from microprobe.utils.yaml import read_yaml

# Type hinting
if TYPE_CHECKING:
    from microprobe.target.isa.register_type import RegisterType

# Constants
SCHEMA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "schemas",
                      "register.yaml")

LOG = get_logger(__name__)
__all__ = ["import_definition", "Register", "GenericRegister"]


# Functions
[docs] @typeguard_testsuite def import_definition(cls, filenames: List[str], regtypes): """ :param filenames: :param regtypes: """ LOG.debug("Start") regs = {} for filename in filenames: reg_data = read_yaml(filename, SCHEMA) if reg_data is None: continue for elem in reg_data: name = elem["Name"] descr = elem.get("Description", "No description") rtype = elem["Type"] rrepr = elem["Representation"] rcodi = elem.get("Codification", elem["Representation"]) repeat = elem.get("Repeat", None) rfrom = 0 rto = 0 replace = "0" if rtype not in regtypes: raise MicroprobeArchitectureDefinitionError( "Unknown register type in definition of " "register '%s' in file '%s'" % (name, filename)) if repeat: rfrom = repeat["From"] replace = "%s" % rfrom rto = repeat["To"] for index in range(rfrom, rto + 1): cname = name.replace(replace, "%d" % index) cdescr = descr.replace(replace, "%d" % index) crepr = rrepr.replace(replace, "%d" % index) ccodi = rcodi.replace(replace, "%d" % index) ctype = regtypes[rtype] regt = cls(cname, cdescr, ctype, crepr, ccodi) if cname in regs: raise MicroprobeArchitectureDefinitionError( "Duplicated register definition of '%s' found" " in '%s'" % (cname, filename)) LOG.debug(regt) regs[cname] = regt LOG.debug("End") return regs
# Classes
[docs] @typeguard_testsuite class Register(abc.ABC): """Abstract class to represent an architecture register."""
[docs] @abc.abstractmethod def __init__(self): pass
@property @abc.abstractmethod def type(self) -> RegisterType: """Register type (:class:`~.RegisterType` instance).""" raise NotImplementedError @property @abc.abstractmethod def name(self) -> str: """Register name (:class:`~.str` instance).""" raise NotImplementedError @property @abc.abstractmethod def description(self) -> str: """Register description (:class:`~.str` instance).""" raise NotImplementedError
[docs] @abc.abstractmethod def representation(self) -> str: """Return the assembly representation of this register.""" raise NotImplementedError
[docs] @abc.abstractmethod def codification(self) -> str: """Return the assembly representation of this register.""" raise NotImplementedError
@abc.abstractmethod def __str__(self) -> str: """Return the string representation of this register.""" raise NotImplementedError @abc.abstractmethod def __repr__(self) -> str: """Return the string representation of this register.""" raise NotImplementedError @abc.abstractmethod def __hash__(self) -> int: raise NotImplementedError
[docs] @typeguard_testsuite class GenericRegister(Register, Pickable): """A Generic architected register""" _cmp_attributes = ["type", "representation", "name"]
[docs] def __init__(self, name: str, descr: str, rtype: RegisterType, rrepr, rcodi): """ :param name: :param descr: :param rtype: :param rrepr: """ super(GenericRegister, self).__init__() self._rtype = rtype self._name = name self._descr = descr self._rrepr = rrepr self._rcodi = rcodi self._hash = int( hashlib.sha512( (self.name + self.description + self.representation + str(hash(self.type))).encode()).hexdigest(), 16)
@property def type(self): return self._rtype @property def name(self): return self._name @property def description(self): return self._descr @property def representation(self): return str(self._rrepr) @property def codification(self): return str(self._rcodi) def __hash__(self): return self._hash def _check_cmp(self, other): if not isinstance(other, self.__class__): raise NotImplementedError("%s != %s" % (other.__class__, self.__class__)) def __eq__(self, other): """x.__eq__(y) <==> x==y""" if not isinstance(other, self.__class__): return False self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if self_val != other_val: return False return True def __ne__(self, other): """x.__ne__(y) <==> x!=y""" self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if self_val != other_val: return True return False def __lt__(self, other): """x.__lt__(y) <==> x<y""" self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if self_val < other_val: return True elif self_val > other_val: return False return False def __gt__(self, other): """x.__gt__(y) <==> x>y""" self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if self_val > other_val: return True elif self_val < other_val: return False return False def __le__(self, other): """x.__le__(y) <==> x<=y""" self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if self_val > other_val: return False return True def __ge__(self, other): """x.__ge__(y) <==> x>=y""" self._check_cmp(other) for attr in self._cmp_attributes: self_val = getattr(self, attr) other_val = getattr(other, attr) if (attr == "representation" and self_val.isdigit() and other_val.isdigit()): self_val = int(self_val) other_val = int(other_val) if not self_val < other_val: return False return True def __str__(self): return "%8s : %s (Type: %s)" % (self._name, self._descr, self._rtype.name) def __repr__(self): return "%s('%s')" % (self.__class__.__name__, self.name) def __getattr__(self, name): """If attribute not found, check if register type implements it :param name: """ try: return self._rtype.__getattribute__(name) except AttributeError: raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))