Source code for microprobe.code.var

# 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.code.var` module

"""

# Futures
from __future__ import absolute_import, print_function, annotations

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

# Own modules
from microprobe.exceptions import MicroprobeCodeGenerationError
from microprobe.utils.logger import get_logger
from microprobe.utils.typeguard_decorator import typeguard_testsuite

# Type hinting
if TYPE_CHECKING:
    from microprobe.code.address import Address

# Constants
__all__ = ["Variable", "VariableSingle", "VariableArray"]
LOG = get_logger(__name__)

VAR_TYPE_LEN_DICT: Dict[str, int] = {}
VAR_TYPE_LEN_DICT["char"] = 1
VAR_TYPE_LEN_DICT["signed char"] = 1
VAR_TYPE_LEN_DICT["unsigned char"] = 1
VAR_TYPE_LEN_DICT["short"] = 2
VAR_TYPE_LEN_DICT["short int"] = 2
VAR_TYPE_LEN_DICT["signed short"] = 2
VAR_TYPE_LEN_DICT["signed short int"] = 2
VAR_TYPE_LEN_DICT["unsigned short"] = 2
VAR_TYPE_LEN_DICT["unsigned short int"] = 2
VAR_TYPE_LEN_DICT["int"] = 4
VAR_TYPE_LEN_DICT["signed"] = 4
VAR_TYPE_LEN_DICT["signed int"] = 4
VAR_TYPE_LEN_DICT["unsigned"] = 4
VAR_TYPE_LEN_DICT["unsigned int"] = 4
VAR_TYPE_LEN_DICT["long"] = 8
VAR_TYPE_LEN_DICT["long int"] = 8
VAR_TYPE_LEN_DICT["signed long"] = 8
VAR_TYPE_LEN_DICT["signed long int"] = 8
VAR_TYPE_LEN_DICT["unsigned long"] = 8
VAR_TYPE_LEN_DICT["unsigned long int"] = 8
VAR_TYPE_LEN_DICT["long long"] = 8
VAR_TYPE_LEN_DICT["long long int"] = 8
VAR_TYPE_LEN_DICT["signed long long"] = 8
VAR_TYPE_LEN_DICT["signed long long int"] = 8
VAR_TYPE_LEN_DICT["float"] = 8
VAR_TYPE_LEN_DICT["double"] = 8
VAR_TYPE_LEN_DICT["long double"] = 8
VAR_TYPE_LEN_DICT["int8_t"] = 1
VAR_TYPE_LEN_DICT["int_least8_t"] = 1
VAR_TYPE_LEN_DICT["int_fast8_t"] = 1
VAR_TYPE_LEN_DICT["uint8_t"] = 1
VAR_TYPE_LEN_DICT["uint_least8_t"] = 1
VAR_TYPE_LEN_DICT["uint_fast8_t"] = 1
VAR_TYPE_LEN_DICT["int16_t"] = 2
VAR_TYPE_LEN_DICT["int_least16_t"] = 2
VAR_TYPE_LEN_DICT["int_fast16_t"] = 2
VAR_TYPE_LEN_DICT["uint16_t"] = 2
VAR_TYPE_LEN_DICT["uint_least16_t"] = 2
VAR_TYPE_LEN_DICT["uint_fast16_t"] = 2
VAR_TYPE_LEN_DICT["int32_t"] = 4
VAR_TYPE_LEN_DICT["int_least32_t"] = 4
VAR_TYPE_LEN_DICT["int_fast32_t"] = 4
VAR_TYPE_LEN_DICT["uint32_t"] = 4
VAR_TYPE_LEN_DICT["uint_least32_t"] = 4
VAR_TYPE_LEN_DICT["uint_fast32_t"] = 4
VAR_TYPE_LEN_DICT["int64_t"] = 8
VAR_TYPE_LEN_DICT["int_least64_t"] = 8
VAR_TYPE_LEN_DICT["int_fast64_t"] = 8
VAR_TYPE_LEN_DICT["uint64_t"] = 8
VAR_TYPE_LEN_DICT["uint_least64_t"] = 8
VAR_TYPE_LEN_DICT["uint_fast64_t"] = 8

# Functions


# Classes
[docs] @typeguard_testsuite class Variable(abc.ABC): """ """ _cmp_attributes: List[str] = []
[docs] def __init__(self): """ """ self._address = None self._hash = None
@property @abc.abstractmethod def type(self) -> str: """Variable type (:class:`~.str`).""" raise NotImplementedError @property @abc.abstractmethod def name(self) -> str: """Variable name (:class:`~.str`).""" raise NotImplementedError
[docs] def array(self) -> bool: """Return if the variable is an array. :rtype: :class:`~.bool` """ raise NotImplementedError
@property @abc.abstractmethod def size(self) -> int: """Variable size in bytes (::class:`~.int`).""" raise NotImplementedError @property @abc.abstractmethod def value(self): """Variable value.""" raise NotImplementedError @property @abc.abstractmethod def align(self) -> int | None: """Variable alignment (:class:`~.int`).""" raise NotImplementedError
[docs] def set_address(self, address: Address): """Set variable address. :param address: Address of the variable. """ self._address = address
@property def address(self): """Variable address (:class:`~.Address`).""" return self._address @abc.abstractmethod def __str__(self) -> str: """ """ raise NotImplementedError def __eq__(self, other: object): """x.__eq__(y) <==> x==y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return False return True def __ne__(self, other: object): """x.__ne__(y) <==> x!=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return True return False def __lt__(self, other: object): """x.__lt__(y) <==> x<y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) < getattr(other, attr): return True elif getattr(self, attr) > getattr(other, attr): return False return False def __gt__(self, other: object): """x.__gt__(y) <==> x>y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) > getattr(other, attr): return True elif getattr(self, attr) < getattr(other, attr): return False return False def __le__(self, other: object): """x.__le__(y) <==> x<=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) <= getattr(other, attr): continue else: return False return True def __ge__(self, other: object): """x.__ge__(y) <==> x>=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) >= getattr(other, attr): continue else: return False return True def __hash__(self): """ """ if self._hash is None: self._hash = int( hashlib.sha512(str(self).encode()).hexdigest(), 16) return self._hash
[docs] @typeguard_testsuite class VariableSingle(Variable): """ """ _cmp_attributes = ["name", "type", "size"]
[docs] def __init__(self, name: str, vartype: str, align: int = 1, value=None, address: Address | None = None): """ :param name: :param vartype: :param align: (Default value = 16) :param value: (Default value = None) """ super(VariableSingle, self).__init__() self._name = name self._type = vartype.lower() self._align = align self._value = value self._address = address if align is not None: if align <= 0: raise MicroprobeCodeGenerationError( "Alignment should be > 0 in definition of " "variable: '%s'" % name) val = math.log(align, 2) if val != int(val): raise MicroprobeCodeGenerationError( "Alignment should be power of 2 in definition of " "variable: '%s'" % name)
@property def type(self): """Variable type (:class:`~.str`).""" return self._type @property def name(self): """Variable name (:class:`~.str`).""" return self._name
[docs] def array(self): """Return if the variable is an array. :rtype: :class:`~.bool` """ return False
@property def value(self): """Variable value.""" return self._value @property def size(self): """Variable size in bytes (::class:`~.int`).""" if self._type in VAR_TYPE_LEN_DICT: return VAR_TYPE_LEN_DICT[self._type] elif "*" in self._type: # TODO: Assuming a 64 bits address size return 8 else: raise MicroprobeCodeGenerationError( "Unable to compute the size of type '%s' in definition " "of variable '%s'" % (self._type, self._name)) @property def align(self): """Variable alignment (:class:`~.int`).""" return self._align def __str__(self): """ """ return "(%s) %s" % (self.type, self.name) def __repr__(self): """ """ return "(%s) %s" % (self.type, self.name)
[docs] @typeguard_testsuite class VariableArray(Variable): """ """ _cmp_attributes = ["name", "type", "size"]
[docs] def __init__(self, name: str, vartype: str, size: int, align: int | None = None, value=None, address: Address | None = None): """ :param name: :param vartype: :param size: :param align: (Default value = 16) :param value: (Default value = None) """ super(VariableArray, self).__init__() self._name = name self._type = vartype.lower() self._align = align self._value = value self._address = address self._elems = size if self._elems < 1: raise MicroprobeCodeGenerationError( "Array size should be greater than 0 in definition of " "variable: '%s'" % name) if align == 0: align = None if align is not None: val = math.log(align, 2) if val != int(val): raise MicroprobeCodeGenerationError( "Alignment should be power of 2 in definition of " "variable: '%s'" % name) if align is not None and address is not None: if not address.check_alignment(align): raise MicroprobeCodeGenerationError( "Alignment requirements do not match address in definition" " of variable: '%s'" % name)
@property def type(self): """Variable type (:class:`~.str`).""" return self._type @property def name(self): """Variable name (:class:`~.str`).""" return self._name @property def value(self): """Variable value.""" return self._value
[docs] def array(self): """Return if the variable is an array. :rtype: :class:`~.bool` """ return True
@property def size(self): """Variable size in bytes (::class:`~.int`).""" if self._type in VAR_TYPE_LEN_DICT: return VAR_TYPE_LEN_DICT[self._type] * self._elems elif "*" in self._type: # TODO: Assuming a 64 bits address size return 8 * self._elems else: raise MicroprobeCodeGenerationError( "Unable to compute the size of type '%s' in definition " "of variable '%s'" % (self._type, self._name)) @property def align(self): """Variable alignment (:class:`~.int`).""" return self._align @property def elems(self): """Number of elements in the variable array (:class:`~.int`).""" return self._elems def __str__(self): """ """ return "(%s) %s[%s]" % (self.type, self.name, self._elems) def __repr__(self): """ """ return "(%s) %s[%s]" % (self.type, self.name, self._elems)