# 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.dat` module
"""
# Futures
from __future__ import absolute_import, print_function
# Built-in modules
import abc
import warnings
# Third party modules
# Own modules
from microprobe.exceptions import MicroprobeAddressTranslationError, \
MicroprobeDuplicatedValueError
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import RejectingDict
# Constants
LOG = get_logger(__name__)
__all__ = ["DynamicAddressTranslation", "GenericDynamicAddressTranslation"]
# Functions
# Classes
[docs]class DynamicAddressTranslation(abc.ABC):
""" """
[docs] @abc.abstractmethod
def __init__(self, target, **kwargs):
pass
[docs] @abc.abstractmethod
def add_mapping(self, source, target, mask):
raise NotImplementedError
@property
@abc.abstractmethod
def maps(self):
raise NotImplementedError
@property
@abc.abstractmethod
def control(self):
raise NotImplementedError
[docs] @abc.abstractmethod
def copy(self, **kwargs):
raise NotImplementedError
[docs] @abc.abstractmethod
def translate(self, address):
raise NotImplementedError
[docs] @abc.abstractmethod
def raw_parse(self, raw_str):
raise NotImplementedError
[docs] @abc.abstractmethod
def raw_decorate(self, raw_str):
raise NotImplementedError
[docs] @abc.abstractmethod
def required_register_values(self):
raise NotImplementedError
[docs] @abc.abstractmethod
def required_memory_values(self):
raise NotImplementedError
[docs] @abc.abstractmethod
def update_dat(self, **kwargs):
raise NotImplementedError
[docs]class GenericDynamicAddressTranslation(DynamicAddressTranslation):
""" """
_control_keys = {'DAT': False}
[docs] def __init__(self, target, **kwargs):
super(GenericDynamicAddressTranslation,
self).__init__(target, **kwargs)
self._map = RejectingDict()
self._target = target
self._control = self._control_keys.copy()
self._control.update(kwargs)
tmaps = kwargs.pop('dat_map', False)
if tmaps:
for tmap in tmaps:
self.add_mapping(tmap[0], tmap[1], tmap[2])
@property
def control(self):
return self._control
@property
def maps(self):
return self._map
[docs] def add_mapping(self, source, target, mask):
try:
self._map[source & mask] = DATmap(source, target, mask)
except MicroprobeDuplicatedValueError:
raise MicroprobeAddressTranslationError(
"Map in '%s' already exists" % hex(source & mask))
[docs] def copy(self, **kwargs):
newargs = self.control.copy()
newargs.update(kwargs)
new_dat = GenericDynamicAddressTranslation(self._target, **newargs)
for datmap in self.maps.values():
new_dat.add_mapping(datmap.source, datmap.target, datmap.mask)
return new_dat
[docs] def translate(self, address, rev=False):
if not self.control['DAT']:
return address
tmap = [
tmap for tmap in self.maps.values()
if tmap.address_in_map(address, rev=rev)
]
if len(tmap) > 1:
raise MicroprobeAddressTranslationError(
"Multiple translation maps found for address '%s'" %
hex(address))
elif len(tmap) < 1:
raise MicroprobeAddressTranslationError(
"No translation maps found for address '%s'" % hex(address))
else:
return tmap[0].address_translate(address, rev=rev)
[docs] def raw_parse(self, raw_str):
raise NotImplementedError(
"DAT mechanisms and parameters are target dependent. Target: '%s'"
" does not implement them. " % self._target)
[docs] def raw_decorate(self, raw_str):
raise NotImplementedError(
"DAT mechanisms and parameters are target dependent. Target: '%s'"
" does not implement them. " % self._target)
[docs] def required_register_values(self):
return []
[docs] def required_memory_values(self):
return []
[docs] def update_dat(self, **kwargs):
for key, value in kwargs.items():
if key not in self._control_keys:
warnings.warn(
"DAT Control key '%s' specified but not supported. "
"Ignoring it." % key)
continue
self._control[key] = value['value']
[docs]class DATmap:
""" """
[docs] def __init__(self, source, target, mask):
self._source = source
self._target = target
self._mask = mask
@property
def mask(self):
return self._mask
@property
def source(self):
return self._source
@property
def target(self):
return self._target
[docs] def address_in_map(self, address, rev=False):
if rev:
return self.target & self.mask == address & self.mask
return self.source & self.mask == address & self.mask
[docs] def address_translate(self, address, rev=False):
if not self.address_in_map(address, rev=rev):
raise MicroprobeAddressTranslationError(
"Unable to translate address '%s' in map: %s" %
(hex(address), str(self)))
address &= (~self.mask)
if rev:
address |= (self.source & self.mask)
else:
address |= (self.target & self.mask)
return address