PK&NregisterMap/VERSION0.5.0 PK&N}ʑregisterMap/__init__.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """ A Python 3 framework for creating and maintaining register maps for integrated circuit design and embedded software development. """ import os.path here = os.path.abspath( os.path.dirname( __file__ ) ) versionFilePath = os.path.abspath( os.path.join( here, 'VERSION' ) ) with open( versionFilePath ) as version_file : version = version_file.read().strip() __version__ = version from .exceptions import \ ConfigurationError, \ ParseError from .registerMap import RegisterMap PK&Nn,,registerMap/exceptions.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # class ConfigurationError( Exception ) : pass class ConstraintError( Exception ) : pass class ParseError( Exception ) : pass PK&Nh5registerMap/exporter.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import sys import yaml from .registerMap import RegisterMap from .export import parseArguments log = logging.getLogger( __name__ ) def acquireLicenseText( licenseTextFile ) : if licenseTextFile is not None : with open( licenseTextFile, 'r' ) as fileObject : licenseTextLines = fileObject.readlines() else : licenseTextLines = list() return licenseTextLines def acquireRegisterMap( registerMapFile ) : with open( registerMapFile, 'r' ) as fileObject : yamlData = yaml.safe_load( fileObject ) if yamlData is None : # Register map file was empty registerMap = None else : registerMap = RegisterMap.from_yamlData( yamlData ) return registerMap def main( commandLineArguments ) : exporterOptions = parseArguments( commandLineArguments ) licenseText = acquireLicenseText( exporterOptions.licenseFile ) registerMap = acquireRegisterMap( exporterOptions.registerMapFile ) if registerMap is None : log.warning( 'Empty register map exports no code, {0}'.format( exporterOptions.registerMapFile ) ) else : thisGenerator = exporterOptions.languageOptions.generator( exporterOptions.languageOptions, licenseTextLines = licenseText ) thisGenerator.generate( registerMap, exporterOptions.registerMapName ) def entry() : main( sys.argv[ 1 : ] ) if __name__ == '__main__' : main( sys.argv[ 1 : ] ) PK&N^_registerMap/registerMap.py""" Definition of RegisterMap """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging from .base.parameters import \ ElementsParameter, \ ModulesParameter from .structure.elements.base.parameter import Parameter from .structure.elements.module import Module from .exceptions import \ ConfigurationError, \ ParseError from .structure.set import SetCollection from .structure.memory.element import AddressableMemoryElement from .structure.memory.configuration import MemoryConfiguration from .utility.observer import AddressChangeObserver log = logging.getLogger( __name__ ) class RegisterMap : __yamlName = 'registerMap' def __init__( self ) : self.__addressObserver = AddressChangeObserver( self ) self.setCollection = SetCollection() self.__initializeMemorySpace() self.__initializeElement() self.__data = { 'description' : Parameter( 'description', '' ), 'element' : ElementsParameter( self ), 'modules' : ModulesParameter( self ), 'summary' : Parameter( 'summary', '' ) } self.__sizeObserver = self.__data[ 'modules' ].sizeObserver self.__memorySpace.sizeChangeNotifier.addObserver( self.__sizeObserver ) def __initializeElement( self ) : self.__element = AddressableMemoryElement( self.__memorySpace ) self.__element.startAddress = self.__memorySpace.baseAddress self.__element.sizeMemoryUnits = None def __initializeMemorySpace( self ) : self.__memorySpace = MemoryConfiguration() self.__memorySpace.addressChangeNotifier.addObserver( self.__addressObserver ) @property def assignedMemoryUnits( self ) : """ :return: Total number of memory units assigned a definition via a register. """ totalSize = 0 for thisModule in self.__data[ 'modules' ].value.values() : totalSize += thisModule.assignedMemoryUnits return totalSize @property def memory( self ) : return self.__memorySpace @property def spanMemoryUnits( self ) : return self.__element.sizeMemoryUnits @property def startAddress( self ) : return self.__element.startAddress def addModule( self, name ) : """ Create a module with the specified name. :param name: Name of the new module. :return: The created module. """ thisModule = Module( self.__memorySpace, self.setCollection ) self.setCollection.moduleSet.add( thisModule ) thisModule[ 'name' ] = name self.__validateAddedModule( thisModule ) self.__data[ 'modules' ].value[ thisModule[ 'name' ] ] = thisModule log.debug( 'Notifying on module change in register map' ) self.reviewSizeChange() return thisModule def __validateAddedModule( self, module ) : foundModules = [ x[ 'name' ] for x in self.__data[ 'modules' ].value.values() if x[ 'name' ] == module[ 'name' ] ] if len( foundModules ) != 0 : raise ConfigurationError( 'Created module names must be unique within a register map, ' + repr( module[ 'name' ] ) ) def reviewAddressChange( self ) : """ Propagate a memory space base address change. """ if self.__data[ 'modules' ].firstElement is not None : self.__data[ 'modules' ].firstElement.endAddress = self.__memorySpace.baseAddress - 1 def reviewSizeChange( self ) : startAddress = self.__memorySpace.baseAddress # Assume the map has size 0 endAddress = startAddress - 1 for thisModule in self.__data[ 'modules' ].value.values() : if thisModule.endAddress > endAddress : endAddress = thisModule.endAddress self.__element.sizeMemoryUnits = endAddress - startAddress + 1 def __getitem__( self, item ) : return self.__data[ item ].value def __setitem__( self, key, value ) : self.__data[ key ].value = value @classmethod def from_yamlData( cls, yamlData, optional = False ) : def acquireMemorySpace( thisData ) : nonlocal thisMap thisMap.__memorySpace = MemoryConfiguration.from_yamlData( thisData ) thisMap.__memorySpace.sizeChangeNotifier.addObserver( thisMap.__sizeObserver ) thisMap.__memorySpace.addressChangeNotifier.addObserver( thisMap.__addressObserver ) def acquireDescription( thisData ) : nonlocal thisMap thisMap.__data[ 'description' ] = Parameter.from_yamlData( thisData, 'description', optional = True ) def acquireModules( thisData ) : nonlocal thisMap thisMap.__data[ 'modules' ] = ModulesParameter.from_yamlData( thisData, thisMap, thisMap.__memorySpace, thisMap.setCollection, optional = True ) def acquireSummary( thisData ) : nonlocal thisMap thisMap.__data[ 'summary' ] = Parameter.from_yamlData( thisData, 'summary', optional = True ) thisMap = cls() if (not optional) and (cls.__yamlName not in yamlData.keys()) : raise ParseError( 'RegisterMap is not defined in yaml data' ) elif cls.__yamlName in yamlData.keys() : # Memory space acquisition must occur first because it is used by module acquisition acquireMemorySpace( yamlData[ cls.__yamlName ] ) acquireDescription( yamlData[ cls.__yamlName ] ) acquireSummary( yamlData[ cls.__yamlName ] ) acquireModules( yamlData[ cls.__yamlName ] ) thisMap.reviewAddressChange() thisMap.reviewSizeChange() return thisMap def to_yamlData( self ) : yamlData = { self.__yamlName : { } } parameters = list() for parameterData in self.__data.values() : parameterYamlData = parameterData.to_yamlData() if parameterYamlData is not None : parameters.append( parameterYamlData ) yamlData[ self.__yamlName ].update( self.__memorySpace.to_yamlData() ) for thisParameter in parameters : yamlData[ self.__yamlName ].update( thisParameter ) return yamlData def __len__( self ) : thisLength = len( self.setCollection.moduleSet ) \ + len( self.setCollection.registerSet ) \ + len( self.setCollection.fieldSet ) return thisLength PK&NregisterMap/base/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NF~KregisterMap/base/parameters.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from ..structure.elements.base import ElementList from ..structure.elements.module import Module from ..structure.elements.base.parameter import Parameter from ..exceptions import ParseError from ..utility.observer import \ Observable, \ SizeChangeObserver class ElementsParameter( Parameter ) : def __init__( self, setCollection ) : self.__setCollection = setCollection def __getitem__( self, item ) : fields = [ x for x in self.__setCollection.fieldSet if x.canonicalId == item ] if len( fields ) == 0 : registers = [ x for x in self.__setCollection.registerSet if x.canonicalId == item ] if len( registers ) == 0 : modules = [ x for x in self.__setCollection.moduleSet if x.canonicalId == item ] if len( modules ) == 0 : foundItem = None else : assert len( modules ) == 1 foundItem = modules[ 0 ] else : assert len( registers ) == 1 foundItem = registers[ 0 ] else : # Canonical ID is supposed to be unique so there should be only one result. assert len( fields ) == 1 foundItem = fields[ 0 ] return foundItem def to_yamlData( self ) : # ElementParameter should not be stored in YAML. It should be built in situ when acquired from YAML. return None class ModulesParameter( Parameter ) : __parameterName = 'modules' class FirstModule : def __init__( self, endAddress = None ) : self.addressChangeNotifier = Observable() self.sizeChangeNotifier = Observable() self.__endAddress = endAddress @property def endAddress( self ) : return self.__endAddress @endAddress.setter def endAddress( self, value ) : self.__endAddress = value self.sizeChangeNotifier.notifyObservers() def __init__( self, owner ) : super().__init__( self.__parameterName, ElementList( self ) ) self.__owner = owner self.firstElement = None self.sizeObserver = SizeChangeObserver( self.__owner ) self.__createFirstModulePrevious() def __createFirstModulePrevious( self ) : assert self.__owner.memory.baseAddress >= 0 firstModule = ModulesParameter.FirstModule( endAddress = (self.__owner.memory.baseAddress - 1) ) self.firstElement = firstModule @classmethod def from_yamlData( cls, yamlData, owner, memorySpace, bitFieldSet, optional = False ) : parameter = cls( owner ) if (not optional) and (cls.__parameterName not in yamlData.keys()) : raise ParseError( 'Modules not defined in yaml data' ) elif cls.__parameterName in yamlData.keys() : for moduleYamlData in yamlData[ cls.__parameterName ] : module = Module.from_yamlData( moduleYamlData, memorySpace, bitFieldSet ) parameter.value[ module[ 'name' ] ] = module return parameter def to_yamlData( self ) : yamlData = { self.__parameterName : list() } for register in self.value.values() : yamlData[ self.__parameterName ].append( register.to_yamlData() ) return yamlData PK&N"registerMap/base/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N+q q /registerMap/base/tests/testElementsParameter.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.module import Module from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from ..parameters import ElementsParameter class TestElementsParameter( unittest.TestCase ) : def setUp( self ) : def setupSetCollection() : m = self.createModule( 'module' ) r = m.addRegister( 'register' ) lf = r.addField( 'local-field', [ 0, 3 ] ) self.assertEqual( 'module.register.local-field', lf.canonicalId ) gf = r.addField( 'global-field', [ 5, 6 ], isGlobal = True ) self.assertEqual( 'global-field', gf.canonicalId ) self.memorySpace = MemoryConfiguration() self.setCollection = SetCollection() setupSetCollection() self.testElements = ElementsParameter( self.setCollection ) def createModule( self, name ) : thisModule = Module( self.memorySpace, self.setCollection ) thisModule[ 'name' ] = name self.setCollection.moduleSet.add( thisModule ) return thisModule def testGlobalFieldFound( self ) : actualElement = self.testElements[ 'global-field' ] self.assertIsNotNone( actualElement ) self.assertEqual( actualElement[ 'name' ], 'global-field' ) def testLocalFieldFound( self ) : actualElement = self.testElements[ 'module.register.local-field' ] self.assertIsNotNone( actualElement ) self.assertEqual( actualElement[ 'name' ], 'local-field' ) def testRegisterFound( self ) : actualElement = self.testElements[ 'module.register' ] self.assertIsNotNone( actualElement ) self.assertEqual( actualElement[ 'name' ], 'register' ) def testModuleFound( self ) : actualElement = self.testElements[ 'module' ] self.assertIsNotNone( actualElement ) self.assertEqual( actualElement[ 'name' ], 'module' ) def testElementNotFound( self ) : actualElement = self.testElements[ 'not-an-element' ] self.assertIsNone( actualElement ) if __name__ == '__main__' : unittest.main() PK&N7͘ .registerMap/base/tests/testModulesParameter.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import unittest import registerMap.structure.elements.base as rmbs import registerMap.registerMap as rm import registerMap.structure.memory.configuration as rmm from registerMap.structure.set import SetCollection class TestModulesParameter( unittest.TestCase ) : def setUp( self ) : self.sourceFieldSet = SetCollection() self.testMemory = rmm.MemoryConfiguration() self.registerMap = rm.RegisterMap() self.acquiredFieldSet = SetCollection() def testInitialization( self ) : p = rm.ModulesParameter( self.registerMap ) self.assertEqual( p.name, 'modules' ) self.assertTrue( isinstance( p.value, rmbs.ElementList ) ) def testEmptyYamlLoadSave( self ) : p = rm.ModulesParameter( self.registerMap ) generatedYamlData = p.to_yamlData() decodedModules = rm.ModulesParameter.from_yamlData( generatedYamlData, self.registerMap, self.testMemory, self.acquiredFieldSet ) self.assertEqual( len( decodedModules.value ), 0 ) def testSingleModuleYamlLoadSave( self ) : module = self.createSampleModule( 'm1' ) p = rm.ModulesParameter( self.registerMap ) p.value[ module[ 'name' ] ] = module generatedYamlData = p.to_yamlData() decodedModules = rm.ModulesParameter.from_yamlData( generatedYamlData, self.registerMap, self.testMemory, self.acquiredFieldSet ) self.assertEqual( decodedModules.value[ 'm1' ][ 'description' ], p.value[ 'm1' ][ 'description' ] ) self.assertEqual( decodedModules.value[ 'm1' ][ 'name' ], p.value[ 'm1' ][ 'name' ] ) self.assertEqual( decodedModules.value[ 'm1' ][ 'summary' ], p.value[ 'm1' ][ 'summary' ] ) def createSampleModule( self, name ) : module = rm.Module( self.testMemory, self.sourceFieldSet ) module[ 'name' ] = name register = module.addRegister( 'r1' ) register.addField( 'f1', [ 3, 5 ], (3, 5) ) register.addField( 'f2', [ 7, 7 ], (7, 7) ) return module def testFromOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } decodedModules = rm.ModulesParameter.from_yamlData( yamlData, self.registerMap, self.testMemory, self.acquiredFieldSet, optional = True ) self.assertEqual( len( decodedModules.value ), 0 ) if __name__ == '__main__' : unittest.main() PK&Nrr#registerMap/constraints/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .constraints import \ AlignmentMemoryUnits, \ FixedAddress, \ FixedSizeMemoryUnits from .constraintTable import \ ConstraintError, \ ConstraintTable PK&Neo`k*registerMap/constraints/constraintTable.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections import logging import registerMap.export.io.yaml.parameters.parse as ryp import registerMap.utility.observer as rmo from registerMap.export.io import yaml from registerMap.exceptions import ConstraintError, ParseError from .constraints import \ AbstractConstraint, \ AlignmentMemoryUnits, \ FixedAddress, \ FixedSizeMemoryUnits, \ validatePositive, \ validatePositiveNonZero log = logging.getLogger( __name__ ) class ConstraintTable( yaml.Import, yaml.Export ) : """ Express constraints to be applied to RegisterMap, Module, Register or BitField. The constraint table notifies registered observers about changes to address or size. The notifications are triggered by user modification of a constraint in the table. """ VALID_CONSTRAINTS = collections.OrderedDict( [ ('fixedAddress', FixedAddress), ('alignmentMemoryUnits', AlignmentMemoryUnits), ('fixedSizeMemoryUnits', FixedSizeMemoryUnits) ] ) def __init__( self, memory, validConstraints = None ) : super().__init__() self.addressChangeNotifier = rmo.Observable() self.sizeChangeNotifier = rmo.Observable() self.__memory = memory self.__constraints = collections.OrderedDict() self.__notifiers = { 'alignmentMemoryUnits' : self.addressChangeNotifier.notifyObservers, 'fixedAddress' : self.addressChangeNotifier.notifyObservers, 'fixedSizeMemoryUnits' : self.sizeChangeNotifier.notifyObservers } if validConstraints is None : self.currentlyValidConstraints = self.VALID_CONSTRAINTS.keys() else : assert all( { x in self.VALID_CONSTRAINTS for x in validConstraints } ), \ 'Constraints must be in the master constraint list, {0}'.format( validConstraints ) self.currentlyValidConstraints = validConstraints @property def isEmpty( self ) : return len( self.__constraints ) == 0 def __delitem__( self, key ) : log.debug( 'Deleting constraint, ' + repr( key ) ) self.__validateGetItem( key ) del self.__constraints[ key ] self.__notifiers[ key ]( self ) def __getitem__( self, item ) : self.__validateGetItem( item ) return self.__constraints[ item ].value def __validateGetItem( self, item ) : self.__validateConstraintName( item ) try : self.__constraints[ item ] except KeyError as e : raise ConstraintError( 'Constraint not applied, {0}'.format( repr( item ) ) ) from e def __len__( self ) : return len( self.__constraints ) def __setitem__( self, key, value ) : log.debug( 'Setting constraint value, ' + repr( key ) + ', ' + repr( value ) ) self.__validateConstraintName( key ) self.__constraints[ key ] = self.VALID_CONSTRAINTS[ key ]( self.__memory, value ) self.__validateAddressConstraintConsistency() self.__notifiers[ key ]( key ) def __validateConstraintName( self, name ) : if name not in self.VALID_CONSTRAINTS.keys() : raise ConstraintError( 'Not a valid constraint, {0}'.format( name ) ) if name not in self.currentlyValidConstraints : raise ConstraintError( 'Constraint has been excluded from this ConstraintTable, {0}'.format( name ) ) def __validateAddressConstraintConsistency( self ) : if FixedAddress.name in self.__constraints.keys() : testAddress = self.__constraints[ FixedAddress.name ].value else : testAddress = 0 collectedAddresses = [ ] for constraint in self.__constraints.values() : if constraint.type == AbstractConstraint.constraintTypes[ 'address' ] : collectedAddresses.append( constraint.calculate( testAddress ) ) if not all( collectedAddresses[ 0 ] == x for x in collectedAddresses ) : raise ConstraintError( 'Address constraints conflict' ) def applyAddressConstraints( self, addressValue ) : newAddress = addressValue for constraint in self.__constraints.values() : if constraint.type == AbstractConstraint.constraintTypes[ 'address' ] : newAddress = constraint.calculate( addressValue ) addressValue = newAddress return newAddress def applySizeConstraints( self, sizeValue ) : newSize = sizeValue for constraint in self.__constraints.values() : if constraint.type == AbstractConstraint.constraintTypes[ 'size' ] : newSize = constraint.calculate( sizeValue ) sizeValue = newSize return newSize @classmethod def from_yamlData( cls, yamlData, memorySpace, optional = False ) : thisConstraints = cls( memorySpace ) goodResult = thisConstraints.__decodeConstraintTable( yamlData, memorySpace, optional = optional ) if (not goodResult) and (not optional) : raise ParseError( 'Processing constraint data failed. Check log for details. ' + repr( yamlData ) ) return thisConstraints def __decodeConstraintTable( self, yamlData, memorySpace, optional = False ) : def recordConstraint( name, value ) : nonlocal self self[ name ] = value def getParameters( thisData ) : nonlocal self, memorySpace # All constraints are optional # Expecting a list of constraints for constraintClass in self.VALID_CONSTRAINTS.values() : constraint = constraintClass.from_yamlData( thisData, memorySpace, optional = True ) if constraint is not None : self.__constraints[ constraint.name ] = constraint return True keyName = 'constraints' return ryp.complexParameter( yamlData, keyName, getParameters, optional = optional ) def to_yamlData( self ) : parameters = list() for constraint in self.__constraints.values() : parameters.append( constraint.to_yamlData() ) keyName = 'constraints' yamlData = { keyName : { } } for thisParameter in parameters : yamlData[ keyName ].update( thisParameter ) return yamlData PK&N2'eD)D)&registerMap/constraints/constraints.py""" Definition of constraints on register map artifacts. """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import abc import logging import math import registerMap.export.io.yaml.parameters.parse as ryp from registerMap.export.io import yaml from registerMap.exceptions import ConstraintError, ParseError log = logging.getLogger( __name__ ) class AbstractConstraint( metaclass = abc.ABCMeta ) : constraintTypes = { 'size' : 0, 'address' : 1 } @property @abc.abstractmethod def value( self ) : pass @value.setter @abc.abstractmethod def value( self, v ) : pass @abc.abstractmethod def calculate( self, value ) : pass @abc.abstractmethod def validate( self, value ) : pass class ConstraintObserver : def __init__( self, owner ) : self.__owner = owner def update( self, notifier, arguments ) : currentConstraint = self.__owner.value # The constraint can initially be None until it is set by the users and while this is true, validation should # not be done. if currentConstraint is not None : # Redundantly setting the value to its current value will still trigger the validation method. self.__owner.value = currentConstraint class AlignmentMemoryUnits( AbstractConstraint, yaml.Import, yaml.Export ) : """ Alignment memory units means that the address will be aligned to the next highest multiple of the specified number of memory units. """ name = 'alignmentMemoryUnits' type = AbstractConstraint.constraintTypes[ 'address' ] __yamlName = 'alignment' def __init__( self, memorySpace, constraintValue = None ) : super().__init__() self.__observer = ConstraintObserver( self ) self.__memory = memorySpace self.__memory.addressChangeNotifier.addObserver( self.__observer ) if constraintValue is not None : self.__validateConstraint( constraintValue ) self.__alignmentConstraint = constraintValue @property def value( self ) : return self.__alignmentConstraint @value.setter def value( self, v ) : self.__validateConstraint( v ) self.__alignmentConstraint = v @staticmethod def __validateConstraint( value ) : assert isinstance( value, int ) validatePositiveNonZero( value, 'Alignment' ) def calculate( self, value ) : self.validate( value ) assert isinstance( self.__alignmentConstraint, int ) if value is not None : modifiedValue = int( math.ceil( float( value ) / self.__alignmentConstraint ) * self.__alignmentConstraint ) else : modifiedValue = None return modifiedValue def validate( self, value ) : if value is not None : assert isinstance( value, int ) validatePositive( value, 'Address' ) @classmethod def from_yamlData( cls, yamlData, memorySpace, optional = False ) : def recordValue( yamlValue ) : nonlocal constraint constraint.__alignmentConstraint = yamlValue constraint = cls( memorySpace ) goodResult = False if cls.__yamlName in yamlData : goodResult = ryp.integerParameter( yamlData, cls.__yamlName, recordValue, optional = optional ) else : constraint = None if (not optional) and (not goodResult) : raise ParseError( 'Yaml data does not contain alignment constraint' ) return constraint def to_yamlData( self ) : yamlData = { self.__yamlName : self.__alignmentConstraint } return yamlData class FixedAddress( AbstractConstraint ) : """ Fixed address means that the address will never change from the specified value. """ name = 'fixedAddress' type = AbstractConstraint.constraintTypes[ 'address' ] __yamlName = 'fixedAddress' def __init__( self, memorySpace, constraintValue = None ) : super().__init__() self.__observer = ConstraintObserver( self ) self.__memory = memorySpace self.__memory.addressChangeNotifier.addObserver( self.__observer ) if constraintValue is not None : self.__validateConstraint( constraintValue ) self.__addressConstraint = constraintValue @property def value( self ) : return self.__addressConstraint @value.setter def value( self, v ) : self.__validateConstraint( v ) self.__addressConstraint = v def __validateConstraint( self, value ) : assert isinstance( value, int ) validatePositive( value, 'Fixed address constraint' ) if self.__memory.pageSize is not None : if self.__memory.isPageRegister( value ) : raise ConstraintError( 'Cannot constrain address to page register' ) def calculate( self, value ) : self.validate( value ) assert isinstance( self.__addressConstraint, int ) fixedAddress = self.__addressConstraint currentAddress = value if (currentAddress is not None) and (currentAddress > fixedAddress) : raise ConstraintError( 'Fixed address exceeded, ' + hex( currentAddress ) + ' (current), ' + hex( fixedAddress ) + ' (constraint)' ) return fixedAddress def validate( self, value ) : if value is not None : validatePositive( value, 'Fixed address' ) @classmethod def from_yamlData( cls, yamlData, memorySpace, optional = False ) : def recordValue( yamlValue ) : nonlocal constraint constraint.__addressConstraint = yamlValue constraint = cls( memorySpace ) goodResult = False if cls.__yamlName in yamlData : goodResult = ryp.integerParameter( yamlData, cls.__yamlName, recordValue, optional = optional ) else : constraint = None if (not optional) and (not goodResult) : raise ParseError( 'Yaml data does not contain fixed address constraint' ) return constraint def to_yamlData( self ) : yamlData = { self.__yamlName : self.__addressConstraint } return yamlData class FixedSizeMemoryUnits( AbstractConstraint ) : """ Fixed size constraint means that the size will never change from the specified value. The size is defined as the number of memory units. eg. In a memory space with 32 bit memory units, a fixed size of 2 memory units means a size of 8 bytes. """ name = 'fixedSizeMemoryUnits' type = AbstractConstraint.constraintTypes[ 'size' ] __yamlName = 'fixedSize' def __init__( self, memorySpace, constraintValue = None ) : super().__init__() self.__observer = ConstraintObserver( self ) self.__memory = memorySpace self.__memory.sizeChangeNotifier.addObserver( self.__observer ) if constraintValue is not None : self.validate( constraintValue ) self.__sizeConstraint = constraintValue @property def value( self ) : return self.__sizeConstraint @value.setter def value( self, v ) : self.validate( v ) self.__sizeConstraint = v def calculate( self, value ) : self.validate( value ) assert isinstance( self.__sizeConstraint, int ) fixedSize = self.__sizeConstraint currentSize = value if currentSize > fixedSize : raise ConstraintError( 'Fixed size exceeded, ' + repr( currentSize ) + ' (current), ' + repr( fixedSize ) + ' (constraint)' ) modifiedValue = self.__sizeConstraint return modifiedValue def validate( self, value ) : # Unlike an address, a size value can never be None. assert isinstance( value, int ) validatePositive( value, 'Fixed size' ) @classmethod def from_yamlData( cls, yamlData, memorySpace, optional = False ) : def recordValue( yamlValue ) : nonlocal constraint constraint.__sizeConstraint = yamlValue constraint = cls( memorySpace ) goodResult = False if cls.__yamlName in yamlData : goodResult = ryp.integerParameter( yamlData, cls.__yamlName, recordValue, optional = optional ) else : constraint = None if (not optional) and (not goodResult) : raise ParseError( 'Yaml data does not contain fixed size constraint' ) return constraint def to_yamlData( self ) : yamlData = { self.__yamlName : self.__sizeConstraint } return yamlData def validatePositive( value, idText ) : """ Test a value for positive integer, raising an exception if false. :param value: The value to be tested :param idText: Short text identifying the class of value for the exception """ if (not isinstance( value, int )) \ or (value < 0) : raise ConstraintError( idText + ' must be a positive integer' ) def validatePositiveNonZero( value, idText ) : """ Test a value for positive, non-zero integer, raising an exception if false. :param value: The value to be tested :param idText: Short text identifying the class of value for the exception """ if (not isinstance( value, int )) \ or (value < 1) : raise ConstraintError( idText + ' must be a positive non-zero integer' ) PK&N)registerMap/constraints/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NH8registerMap/constraints/tests/testAlignmentConstraint.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest from registerMap.structure.memory.configuration import MemoryConfiguration from ..constraints import \ AbstractConstraint, \ AlignmentMemoryUnits, \ ConstraintError, \ ParseError log = logging.getLogger( __name__ ) class TestAlignmentMemoryUnits( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraint = AlignmentMemoryUnits( self.memory ) def testName( self ) : self.assertEqual( self.constraint.name, AlignmentMemoryUnits.name ) def testType( self ) : self.assertEqual( self.constraint.type, AbstractConstraint.constraintTypes[ 'address' ] ) def doNoneConstraintValueAsserts( self, methodUnderTest ) : with self.assertRaises( AssertionError ) : methodUnderTest( 0xa ) def doNonIntAddressRaises( self, methodUnderTest ) : with self.assertRaises( AssertionError ) : methodUnderTest( '0xa' ) def doNegativeAddressRaises( self, methodUnderTest ) : with self.assertRaises( AssertionError ) : methodUnderTest( '-12' ) def doZeroAddressNoRaise( self, methodUnderTest ) : methodUnderTest( 0 ) class TestAlignmentMemoryUnitsConstructor( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() def testDefaultConstructorNoRaise( self ) : c = AlignmentMemoryUnits( self.memory ) def testZeroConstraintValueRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Alignment must be a positive non-zero integer' ) : AlignmentMemoryUnits( self.memory, constraintValue = 0 ) def testNonIntConstraintValueAsserts( self ) : with self.assertRaises( AssertionError ) : AlignmentMemoryUnits( self.memory, constraintValue = '1' ) def testNoneConstraintValueNoRaise( self ) : c = AlignmentMemoryUnits( self.memory, constraintValue = None ) class TestAlignmentMemoryUnitsCalculation( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraint = AlignmentMemoryUnits( self.memory ) def testNoneConstraintAsserts( self ) : doNoneConstraintValueAsserts( self, self.constraint.calculate ) def testNonIntAddressRaises( self ) : doNonIntAddressRaises( self, self.constraint.calculate ) def testNegativeAddressRaises( self ) : doNegativeAddressRaises( self, self.constraint.calculate ) def testZeroAddressNoRaise( self ) : self.constraint.value = 4 doZeroAddressNoRaise( self, self.constraint.calculate ) def testAlignAddress( self ) : expectedAddress = 0xc self.constraint.value = 4 actualAddress = self.constraint.calculate( 0xa ) self.assertEqual( actualAddress, expectedAddress ) def testNoneAddress( self ) : self.constraint.value = 4 self.assertIsNone( self.constraint.calculate( None ) ) def testZeroAddress( self ) : expectedAddress = 0 self.constraint.value = 4 actualAddress = self.constraint.calculate( expectedAddress ) self.assertEqual( actualAddress, expectedAddress ) class TestAlignmentMemoryUnitsValidation( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraint = AlignmentMemoryUnits( self.memory ) def testNonIntAddressRaises( self ) : doNonIntAddressRaises( self, self.constraint.validate ) def testNegativeAddressRaises( self ) : doNegativeAddressRaises( self, self.constraint.validate ) def testZeroAddressNoRaise( self ) : doZeroAddressNoRaise( self, self.constraint.validate ) class TestAlignmentMemoryUnitsValueProperty( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraint = AlignmentMemoryUnits( self.memory ) def testGetProperty( self ) : expectedValue = 14 self.constraint.value = expectedValue actualValue = self.constraint.value self.assertEqual( actualValue, expectedValue ) def testZeroValueRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Alignment must be a positive non-zero integer' ) : self.constraint.value = 0 def testNonIntValueAsserts( self ) : with self.assertRaises( AssertionError ) : self.constraint.value = '1' class TestLoadSave( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraint = AlignmentMemoryUnits( self.memory ) def testEncodeDecode( self ) : self.constraint.value = 4 encodedYamlData = self.constraint.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = AlignmentMemoryUnits.from_yamlData( encodedYamlData, self.memory ) self.assertEqual( decodedData.value, self.constraint.value ) def testDecodeNonAlignmentConstraintRaises( self ) : with self.assertRaisesRegex( ParseError, '^Yaml data does not contain alignment constraint' ) : AlignmentMemoryUnits.from_yamlData( { }, self.memory ) def testDecodeOptionalAlignmentConstraintRaises( self ) : constraint = AlignmentMemoryUnits.from_yamlData( { }, self.memory, optional = True ) self.assertIsNone( constraint ) if __name__ == '__main__' : unittest.main() PK&N@O884registerMap/constraints/tests/testConstraintTable.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import math import unittest from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.tests.mockObserver import MockObserver from ..constraintTable import \ ConstraintError, \ ConstraintTable log = logging.getLogger( __name__ ) class MockItem : """ Mock the interfaces of RegisterMap, Module, Register, BitField that are used by constraints. """ def __init__( self, initialAddress, sizeValue, memory = MemoryConfiguration() ) : self.__memory = memory @property def memory( self ) : return self.__memory class TestConstraintTable( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testQueryEmptyConstraintTableRaises( self ) : for thisName in ConstraintTable.VALID_CONSTRAINTS.keys() : with self.assertRaisesRegex( ConstraintError, '^Constraint not applied' ) : self.constraints[ thisName ] def testInvalidConstraintNameRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Not a valid constraint' ) : self.constraints[ 'badName' ] def testAddValidConstraint( self ) : expectedValue = 0x10 self.constraints[ 'fixedAddress' ] = expectedValue self.assertEqual( self.constraints[ 'fixedAddress' ], expectedValue ) self.assertEqual( self.observer.updateCount, 1 ) def testAddInvalidConstraintRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Not a valid constraint' ) : self.constraints[ 'badName' ] = 0x10 def testDeleteConstraint( self ) : constraintName = 'fixedAddress' expectedValue = 0x10 self.constraints[ constraintName ] = expectedValue self.assertEqual( self.constraints[ constraintName ], expectedValue ) self.assertEqual( self.observer.updateCount, 1 ) del self.constraints[ constraintName ] self.assertEqual( self.observer.updateCount, 2 ) with self.assertRaisesRegex( ConstraintError, '^Constraint not applied' ) : self.constraints[ constraintName ] def testTwoConstraints( self ) : initialAddress = 0x10 self.constraints[ 'alignmentMemoryUnits' ] = 4 self.constraints[ 'fixedAddress' ] = initialAddress self.assertEqual( self.observer.updateCount, 2 ) # The fixed address constraint takes precedence actualAddress = self.constraints.applyAddressConstraints( initialAddress ) self.assertEqual( actualAddress, initialAddress ) def testTwoConstraintsDifferentOrder( self ) : initialAddress = 0x10 self.constraints[ 'fixedAddress' ] = initialAddress self.constraints[ 'alignmentMemoryUnits' ] = 2 self.assertEqual( self.observer.updateCount, 2 ) # The fixed address constraint takes precedence actualAddress = self.constraints.applyAddressConstraints( initialAddress ) self.assertEqual( actualAddress, initialAddress ) def testAddBadFixedAddressAgainstAlignmentRaises( self ) : expectedAddress = 0x1 self.constraints[ 'alignmentMemoryUnits' ] = 4 with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.constraints[ 'fixedAddress' ] = expectedAddress def testAddAlignmentAgainstBadFixedAddressRaises( self ) : expectedAddress = 0x1 self.constraints[ 'fixedAddress' ] = expectedAddress with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.constraints[ 'alignmentMemoryUnits' ] = 4 def testFixedAddressOnPageRegisterRaises( self ) : self.memory.pageSize = 128 numberMemoryUnits = math.ceil( float( self.memory.addressBits ) / self.memory.memoryUnitBits ) pageAddresses = [ (self.memory.pageSize - x + 0x800) for x in range( 1, (numberMemoryUnits + 1) ) ] for address in pageAddresses : with self.assertRaisesRegex( ConstraintError, '^Cannot constrain address to page register' ) : self.constraints[ 'fixedAddress' ] = address def testDeleteInvalidConstraintRaises( self ) : constraintName = 'badName' with self.assertRaisesRegex( ConstraintError, '^Not a valid constraint' ) : del self.constraints[ constraintName ] def testDeleteValidConstraintNoAppliedRaises( self ) : constraintName = 'fixedAddress' with self.assertRaisesRegex( ConstraintError, '^Constraint not applied' ) : del self.constraints[ constraintName ] def testIsEmpty( self ) : self.assertTrue( self.constraints.isEmpty ) self.constraints[ 'fixedAddress' ] = 0x10 self.assertFalse( self.constraints.isEmpty ) class TestApplyConstraints( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testApplyAddressConstraintsNoConstraints( self ) : # with no constraints, the initial address is unchanged. expectedAddress = 0x10 actualAddress = self.constraints.applyAddressConstraints( expectedAddress ) self.assertEqual( actualAddress, expectedAddress ) def testApplySizeConstraintNoConstraints( self ) : # with no constraints, the initial address is unchanged. expectedSize = 0x10 actualSize = self.constraints.applySizeConstraints( expectedSize ) self.assertEqual( actualSize, expectedSize ) class TestApplyFixedAddress( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testFixedAddressChanges( self ) : expectedAddress = 0x10 self.constraints[ 'fixedAddress' ] = expectedAddress self.assertEqual( self.constraints[ 'fixedAddress' ], expectedAddress ) self.assertTrue( self.observer.updateCount, 1 ) def testNegativeRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Fixed address constraint must be a positive integer' ) : self.constraints[ 'fixedAddress' ] = -1 def testCurrentAddressExceedsFixedAddressRaises( self ) : currentAddress = 0x11 fixedAddress = 0x10 self.constraints[ 'fixedAddress' ] = fixedAddress with self.assertRaisesRegex( ConstraintError, '^Fixed address exceeded' ) : self.constraints.applyAddressConstraints( currentAddress ) def testCurrentAddressEqualsFixedAddress( self ) : expectedAddress = 0x11 self.constraints[ 'fixedAddress' ] = expectedAddress actualAddress = self.constraints.applyAddressConstraints( expectedAddress ) self.assertEqual( actualAddress, expectedAddress ) def testCurrentAddressIsNone( self ) : expectedAddress = 0x11 self.constraints[ 'fixedAddress' ] = expectedAddress actualAddress = self.constraints.applyAddressConstraints( None ) self.assertEqual( actualAddress, expectedAddress ) class TestApplyAddressAlignment( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testAddressAlignmentChange( self ) : alignmentValue = 4 initialAddress = 0x6 expectedAddress = 0x8 self.assertTrue( (initialAddress < expectedAddress) ) self.assertTrue( (initialAddress % alignmentValue) != 0 ) self.constraints[ 'alignmentMemoryUnits' ] = alignmentValue self.assertTrue( self.observer.updateCount, 1 ) actualAddress = self.constraints.applyAddressConstraints( initialAddress ) self.assertEqual( actualAddress, expectedAddress ) def testAddressAlignmentNoChange( self ) : alignmentValue = 3 initialAddress = 0x6 expectedAddress = initialAddress self.assertTrue( (initialAddress % alignmentValue) == 0 ) self.constraints[ 'alignmentMemoryUnits' ] = alignmentValue actualAddress = self.constraints.applyAddressConstraints( initialAddress ) self.assertEqual( actualAddress, expectedAddress ) def testZeroRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Alignment must be a positive non-zero integer' ) : self.constraints[ 'alignmentMemoryUnits' ] = 0 def testNegativeRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Alignment must be a positive non-zero integer' ) : self.constraints[ 'alignmentMemoryUnits' ] = -1 class TestApplySize( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.sizeChangeNotifier.addObserver( self.observer ) def testUnderSizeOk( self ) : fixedSize = 6 self.constraints[ 'fixedSizeMemoryUnits' ] = fixedSize self.assertEqual( self.observer.updateCount, 1 ) def testZeroNoRaise( self ) : self.constraints[ 'fixedSizeMemoryUnits' ] = 0 def testNegativeRaises( self ) : with self.assertRaisesRegex( ConstraintError, '^Fixed size must be a positive integer' ) : self.constraints[ 'fixedSizeMemoryUnits' ] = -1 def testOverSizeRaises( self ) : fixedSize = 6 currentSize = 8 self.assertGreater( currentSize, fixedSize ) self.constraints[ 'fixedSizeMemoryUnits' ] = fixedSize with self.assertRaisesRegex( ConstraintError, '^Fixed size exceeded' ) : self.constraints.applySizeConstraints( currentSize ) class TestConstraintTableLen( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testEmptyEqualsZero( self ) : self.assertEqual( len( self.constraints ), 0 ) def testAddOneConstraintLenEqualsOne( self ) : self.assertEqual( len( self.constraints ), 0 ) self.constraints[ 'fixedAddress' ] = 0x10 self.assertEqual( len( self.constraints ), 1 ) class TestLoadSave( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.constraints = ConstraintTable( self.memory ) self.observer = MockObserver() self.constraints.addressChangeNotifier.addObserver( self.observer ) def testEncodeDecode( self ) : self.constraints[ 'fixedAddress' ] = 0x10 self.constraints[ 'fixedSizeMemoryUnits' ] = 0x7 self.constraints[ 'alignmentMemoryUnits' ] = 2 encodedYamlData = self.constraints.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = ConstraintTable.from_yamlData( encodedYamlData, self.memory ) self.assertEqual( decodedData[ 'fixedAddress' ], self.constraints[ 'fixedAddress' ] ) self.assertEqual( decodedData[ 'fixedSizeMemoryUnits' ], self.constraints[ 'fixedSizeMemoryUnits' ] ) self.assertEqual( decodedData[ 'alignmentMemoryUnits' ], self.constraints[ 'alignmentMemoryUnits' ] ) def testDecodeEmpty( self ) : emptyConstraintsYamlData = { 'constraints' : { } } table = ConstraintTable.from_yamlData( emptyConstraintsYamlData, self.memory ) self.assertTrue( table.isEmpty ) class TestLimitedConstraintSet( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() def testDefaultValidConstraints( self ) : self.constraints = ConstraintTable( self.memory ) self.assertEqual( set( self.constraints.VALID_CONSTRAINTS.keys() ), self.constraints.currentlyValidConstraints ) def testLimitedConstraintAppliesConstraint( self ) : """ Applying a constraint in the limited constraint set applies the constraint. """ limitedConstraints = { 'fixedAddress' } self.constraints = ConstraintTable( self.memory, validConstraints = limitedConstraints ) expectedAddress = 0x11 self.constraints[ 'fixedAddress' ] = expectedAddress actualAddress = self.constraints.applyAddressConstraints( expectedAddress ) self.assertEqual( actualAddress, expectedAddress ) def testExcludedConstraintRaises( self ) : """ Applying a constraint that has been excluded raises an exception """ excludedConstraint = 'fixedSizeMemoryUnits' limitedConstraints = { 'fixedAddress' } self.assertNotIn( excludedConstraint, limitedConstraints ) self.constraints = ConstraintTable( self.memory, validConstraints = limitedConstraints ) with self.assertRaisesRegex( ConstraintError, '^Constraint has been excluded from this ConstraintTable' ) : self.constraints[ excludedConstraint ] = 10 if __name__ == '__main__' : unittest.main() PK&N ;registerMap/constraints/tests/testFixedAddressConstraint.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import math import unittest import registerMap.constraints.constraints as rmc import registerMap.structure.memory.configuration as rmm log = logging.getLogger( __name__ ) class TestFixedAddress( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedAddress( self.memory ) def testName( self ) : self.assertEqual( self.constraint.name, rmc.FixedAddress.name ) def testType( self ) : self.assertEqual( self.constraint.type, rmc.AbstractConstraint.constraintTypes[ 'address' ] ) class TestFixedAddressCalculation( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedAddress( self.memory ) def testAddressOverRaises( self ) : expectedAddress = 0x12 self.constraint.value = expectedAddress with self.assertRaisesRegex( rmc.ConstraintError, '^Fixed address exceeded' ) : self.constraint.calculate( 0x14 ) def testConstraintCalculation( self ) : expectedAddress = 0x12 self.constraint.value = expectedAddress actualAddress = self.constraint.calculate( 0x10 ) self.assertEqual( actualAddress, expectedAddress ) def testFixedAddressOnPageRegisterRaises( self ) : self.memory.pageSize = 128 numberMemoryUnits = math.ceil( float( self.memory.addressBits ) / self.memory.memoryUnitBits ) pageAddresses = [ (self.memory.pageSize - x + 0x800) for x in range( 1, (numberMemoryUnits + 1) ) ] for address in pageAddresses : with self.assertRaisesRegex( rmc.ConstraintError, '^Cannot constrain address to page register' ) : self.constraint.value = address def testNonIntAddressAsserts( self ) : with self.assertRaisesRegex( rmc.ConstraintError, '^Fixed address must be a positive integer' ) : self.constraint.calculate( '0x14' ) def testNoneAddress( self ) : expectedAddress = 0x12 self.constraint.value = expectedAddress actualAddress = self.constraint.calculate( None ) self.assertEqual( actualAddress, expectedAddress ) class TestFixedAddressValidation( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() # Verify that the memory defaults are what are assumed in these tests. self.assertEqual( self.memory.addressBits, 32 ) self.assertEqual( self.memory.memoryUnitBits, 8 ) self.constraint = rmc.FixedAddress( self.memory ) def testNoPageRegisterPasses( self ) : # No page register means any address should pass self.constraint.value = 0x12 self.constraint.validate( 0x14 ) def testNoneAddressPasses( self ) : self.constraint.validate( None ) def testFixedAddressOnPageRegisterRaises( self ) : self.memory.pageSize = 0x13 with self.assertRaisesRegex( rmc.ConstraintError, '^Cannot constrain address to page register' ) : self.constraint.value = 0x12 def testFixedAddressOnPageRegisterRaisesWhenPageSizeIntroduced( self ) : self.constraint.value = 0x12 with self.assertRaisesRegex( rmc.ConstraintError, '^Cannot constrain address to page register' ) : # Changing the memory page size is expected to notify the constraint which will now raise because it is no # longer valid. self.memory.pageSize = 0x13 def testFixedAddressNotOnPageRegisterPasses( self ) : self.assertEqual( self.memory.addressBits, 32 ) self.memory.pageSize = 0x13 self.constraint.value = self.memory.pageSize - 4 - 1 self.assertFalse( self.memory.isPageRegister( self.constraint.value ) ) self.constraint.validate( 0x12 ) class TestFixedAddressMemoryUnitsValueProperty( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedAddress( self.memory ) def testGetProperty( self ) : expectedValue = 14 self.constraint.value = expectedValue actualValue = self.constraint.value self.assertEqual( actualValue, expectedValue ) def testZeroValueNoRaise( self ) : expectedValue = 0 self.constraint.value = expectedValue actualValue = self.constraint.value self.assertEqual( actualValue, expectedValue ) def testNoneValueAsserts( self ) : with self.assertRaises( AssertionError ) : self.constraint.value = None class TestLoadSave( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedAddress( self.memory ) def testEncodeDecode( self ) : self.constraint.value = 4 encodedYamlData = self.constraint.to_yamlData( ) log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = rmc.FixedAddress.from_yamlData( encodedYamlData, self.memory ) self.assertEqual( decodedData.value, self.constraint.value ) def testDecodeNonAlignmentConstraintRaises( self ) : with self.assertRaisesRegex( rmc.ParseError, '^Yaml data does not contain fixed address constraint' ) : rmc.FixedAddress.from_yamlData( { }, self.memory ) def testDecodeOptionalAlignmentConstraintRaises( self ) : constraint = rmc.FixedAddress.from_yamlData( { }, self.memory, optional = True ) self.assertIsNone( constraint ) if __name__ == '__main__' : unittest.main( ) PK&N'2A8registerMap/constraints/tests/testFixedSizeConstraint.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest import registerMap.constraints.constraints as rmc import registerMap.structure.memory.configuration as rmm log = logging.getLogger( __name__ ) class TestFixedSizeMemoryUnits( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedSizeMemoryUnits( self.memory ) def testName( self ) : self.assertEqual( self.constraint.name, rmc.FixedSizeMemoryUnits.name ) def testType( self ) : self.assertEqual( self.constraint.type, rmc.AbstractConstraint.constraintTypes[ 'size' ] ) def doNoneConstraintAsserts( self, methodUnderTest ) : with self.assertRaises( AssertionError ) : methodUnderTest( 14 ) def doNonIntSizeRaises( self, methodUnderTest ) : with self.assertRaises( AssertionError ) : methodUnderTest( '12' ) def doNegativeSizeRaises( self, methodUnderTest ) : self.constraint.sizeConstraint = 12 with self.assertRaisesRegex( rmc.ConstraintError, '^Fixed size must be a positive integer' ) : methodUnderTest( -14 ) class TestFixedSizeMemoryUnitsCalculation( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedSizeMemoryUnits( self.memory ) def testNoneConstraintAsserts( self ) : doNoneConstraintAsserts( self, self.constraint.calculate ) def testNonIntSizeRaises( self ) : doNonIntSizeRaises( self, self.constraint.calculate ) def testNegativeSizeRaises( self ) : self.constraint.value = 12 doNegativeSizeRaises( self, self.constraint.calculate ) def testOverSizeRaises( self ) : expectedSize = 12 self.constraint.value = expectedSize with self.assertRaisesRegex( rmc.ConstraintError, '^Fixed size exceeded' ) : self.constraint.calculate( 14 ) def testConstraintCalculation( self ) : expectedSize = 12 self.constraint.value = expectedSize actualSize = self.constraint.calculate( 10 ) self.assertEqual( actualSize, expectedSize ) class TestFixedSizeMemoryUnitsValidation( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedSizeMemoryUnits( self.memory ) def testNonIntSizeRaises( self ) : doNonIntSizeRaises( self, self.constraint.validate ) def testNegativeSizeRaises( self ) : self.constraint.value = 12 doNegativeSizeRaises( self, self.constraint.validate ) class TestFixedSizeMemoryUnitsValueProperty( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedSizeMemoryUnits( self.memory ) def testGetProperty( self ) : expectedValue = 14 self.constraint.value = expectedValue actualValue = self.constraint.value self.assertEqual( actualValue, expectedValue ) def testNegativeConstraintRaises( self ) : with self.assertRaisesRegex( rmc.ConstraintError, '^Fixed size must be a positive integer' ) : self.constraint.value = -12 class TestLoadSave( unittest.TestCase ) : def setUp( self ) : self.memory = rmm.MemoryConfiguration() self.constraint = rmc.FixedSizeMemoryUnits( self.memory ) def testEncodeDecode( self ) : self.constraint.value = 4 encodedYamlData = self.constraint.to_yamlData( ) log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = rmc.FixedSizeMemoryUnits.from_yamlData( encodedYamlData, self.memory ) self.assertEqual( decodedData.value, self.constraint.value ) def testDecodeNonAlignmentConstraintRaises( self ) : with self.assertRaisesRegex( rmc.ParseError, '^Yaml data does not contain fixed size constraint' ) : rmc.FixedSizeMemoryUnits.from_yamlData( { }, self.memory ) def testDecodeOptionalAlignmentConstraintRaises( self ) : constraint = rmc.FixedAddress.from_yamlData( { }, self.memory, optional = True ) self.assertIsNone( constraint ) if __name__ == '__main__' : unittest.main( ) PK&NregisterMap/export/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .arguments import parseArguments PK&Nμ registerMap/export/arguments.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import argparse from .options import ExporterOptions from .exporters import exporters languages = [ 'c++', 'c', ] class MainParser : def __init__( self ) : self.parser = argparse.ArgumentParser( description = 'Export a register map to a language implementation', usage = '''export-map [] [] Supported languages include: {0} '''.format( '\n '.join( languages ) ) ) self.__applyTopLevelArguments() languageParsers = self.parser.add_subparsers( dest = 'language', help = 'Output language selection.', title = 'language' ) # All the language parser instances need to be instantiated at this point because the command line parsing # hasn't occured yet so we don't know what language is being selected. self.languageParserInstances = { x : y( languageParsers ) for x, y in exporters.items() } def __applyTopLevelArguments( self ) : self.parser.add_argument( 'registerMapFile', help = 'Append to an existing distribution package, if it exists. Created otherwise. (default disabled)' ) self.parser.add_argument( '-n', '--registermap-name', default = 'registerMap', help = 'Register map name. (default "registerMap")' ) self.parser.add_argument( '-l', '--license-file', default = None, help = 'License text file. Text must be line formatted to be incorporated into exporter generated output boilerplate.' ) def parse_args( self, commandLineArguments ) : args = self.parser.parse_args( commandLineArguments ) return args def parseArguments( arguments ) : thisParser = MainParser() parsedArguments = thisParser.parse_args( arguments ) options = ExporterOptions() options.language = parsedArguments.language options.licenseFile = parsedArguments.license_file options.registerMapFile = parsedArguments.registerMapFile options.registerMapName = parsedArguments.registermap_name if options.language is None : raise RuntimeError( 'Language must be specified' ) # Acquire language specific options options.languageOptions = thisParser.languageParserInstances[ options.language ].acquireOptions( parsedArguments ) options.output = parsedArguments.output return options PK&NAOOregisterMap/export/exporters.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .c import CArgumentParser from .cpp import CppArgumentParser exporters = { 'c++' : CppArgumentParser, 'c': CArgumentParser, } PK&NregisterMap/export/options.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # class ExporterOptions : def __init__( self ) : self.language = None self.licenseFile = None self.output = None self.registerMapFile = None self.registerMapName = None PK&N`#registerMap/export/base/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .field import FieldBase from .interface import TemplateInterface from .register import \ RegisterBase, \ RegisterContiguousFieldIntervals from .memory import MemoryBase from .module import ModuleBase from .output import OutputBase from .registerMap import RegisterMapBase from .template import TemplateBase PK&NIx registerMap/export/base/field.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class FieldBase( metaclass = abc.ABCMeta ) : """ Representation of a Field for output using jinja2. """ def __init__( self, element ) : super().__init__() self._element = element @property def name( self ) : """ The name of the bit field. """ return self._element[ 'name' ] @property def size( self ) : """ The number of bits in the bit field. """ return self._element[ 'size' ] @property @abc.abstractmethod def type( self ) : """ The data type to be used in the declaration of the bit field. Many languages require a type to be declared for the bit field element, so this method is added to provide for that. """ pass PK&N??$registerMap/export/base/interface.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class LanguageParser( metaclass = abc.ABCMeta ) : """ Interface of output language command line argument parsing for the `export-map` tool. """ @abc.abstractmethod def acquireOptions( self, parserProcessedArguments ) : pass class OutputInterface( metaclass = abc.ABCMeta ) : """ Interface for register map export to a language. """ @abc.abstractmethod def generate( self, registerMap, registerMapName ) : """ Export a child specific representation of the given register map. :param registerMap: RegisterMap object to be exported. :param registerMapName: Language specific name of register map. """ pass class TemplateInterface( metaclass = abc.ABCMeta ) : """ Interface for template management. """ @abc.abstractmethod def apply( self ) : pass PK&NB0tt!registerMap/export/base/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class MemoryBase( metaclass = abc.ABCMeta ) : """ Representation of MemorySpace for output using jinja2. """ def __init__( self, memoryElement, memorySize ) : super().__init__() self._element = memoryElement self.__memorySize = memorySize @property def baseAddress( self ) : """ The base address of the memory space. """ return hex( self._element.baseAddress ) @property def memoryUnitBits( self ) : """ The number of bits per memory unit. """ return self._element.memoryUnitBits @property def size( self ) : """ The number of memory units in the memory space. """ return self.__memorySize @property @abc.abstractmethod def sizeType( self ) : """ The language specific type to declare for the memory units. """ pass PK&N c!registerMap/export/base/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class ModuleRegistersIndirection : def __init__( self, registerElements, RegisterType, FieldType ) : self.__elements = registerElements self.__FieldType = FieldType self.__RegisterType = RegisterType def __getitem__( self, item ) : return self.__RegisterType( self.__elements[ item ], self.__FieldType ) def __len__( self ) : return len( self.__elements ) class ModuleBase( metaclass = abc.ABCMeta ) : """ Representation of a Module for output using jinja2. """ def __init__( self, moduleElement, RegisterType, FieldType ) : self._element = moduleElement self.__FieldType = FieldType self.__RegisterType = RegisterType @property def name( self ) : return self._element[ 'name' ] @property def registers( self ) : return ModuleRegistersIndirection( list( self._element[ 'registers' ].values() ), self.__RegisterType, self.__FieldType ) @property @abc.abstractmethod def address( self ) : """ The absolute base address of the module formatted for the target language. """ pass @property @abc.abstractmethod def offset( self ) : """ The offset of the module formatted for the target language, relative to the base address of the register map. """ pass PK&Nw/!registerMap/export/base/output.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import os from .interface import OutputInterface log = logging.getLogger( __name__ ) class OutputBase( OutputInterface ) : def __init__( self, outputOptions, licenseTextLines = list() ) : self.createdDirectories = list() self.createdFiles = list() self.licenseTextLines = licenseTextLines self.outputOptions = outputOptions self.__validateOutputDirectory() def __validateOutputDirectory( self ) : if not os.path.isdir( self.outputOptions.output ) : raise RuntimeError( 'Output directory is not a directory, {0}'.format( self.outputOptions.output ) ) @property def outputDirectory( self ) : return self.outputOptions.output def createDirectory( self, thisDir ) : os.makedirs( thisDir, exist_ok = True ) self.createdDirectories.append( thisDir ) log.debug( 'Created directory, {0}'.format( self.createdDirectories[ -1 ] ) ) PK&N--#registerMap/export/base/register.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc from registerMap.structure.interval import makeContiguous class RegisterFieldsIndirection : def __init__( self, fieldElements, FieldType ) : self.__elements = fieldElements self.__FieldType = FieldType def __getitem__( self, item ) : return self.__FieldType( self.__elements[ item ] ) def __len__( self ) : return len( self.__elements ) class RegisterBase( metaclass = abc.ABCMeta ) : """ Representation of a Register for output using jinja2. `RegisterBase` just represents the assigned fields in the export. See `RegisterContiguousFieldIntervals` for a representation including unassigned and reserved bit intervals. """ def __init__( self, element, FieldType ) : super().__init__() self._element = element self._FieldType = FieldType @property def name( self ) : return self._element[ 'name' ] @property def fields( self ) : return RegisterFieldsIndirection( list( self._element[ 'fields' ].values() ), self._FieldType ) @property def address( self ) : """ The absolute address of the register in the register map, formatted for text output in hexadecimal. """ return hex( self._element.startAddress ) @property def offset( self ) : """ The offset of the register in the register map, relative to the base address of the register map, formatted for text output in hexadecimal. """ return hex( self._element.offset ) @property def moduleOffset( self ) : """ The offset of the register in the register map, relative to its parent module, formatted for text output in hexadecimal. """ return hex( self._element.moduleOffset ) @property def precedingGapBytes( self ) : """ The size of any gap between the end address of the preceding register and the start address of this register. For sequential registers the start address would be one more than the end address of the preceding register, resulting in a gap of zero. """ memoryUnitBytes = int( self._element.memory.memoryUnitBits / 8 ) return (self._element.startAddress - self._element.previousElement.endAddress - 1) * memoryUnitBytes class RegisterContiguousFieldIntervals( RegisterBase ) : """ Represent the register with a field for every bit interval, including unassigned or reserved ranges. For C and C++ idiomatic export,. """ def __init__( self, element, FieldType ) : super().__init__( element, FieldType ) self.__fieldItems = element[ 'fields' ].items() @property def fields( self ) : registerIntervals = makeContiguous( self._element.bitMap.sourceIntervals, (self._element.sizeBits - 1) ) contiguousFields = list() for thisInterval in registerIntervals : try : thisField = self.__findFieldFromInterval( thisInterval ) contiguousFields.append( thisField ) except RuntimeError : # The interval must be an "unassigned" insertion so create a dummy field to capture the necessary size. # Duck typing at work... contiguousFields.append( { 'name' : '', 'size' : thisInterval.size, } ) return RegisterFieldsIndirection( contiguousFields, self._FieldType ) def __findFieldFromInterval( self, interval ) : fieldOwnsInterval = list() for name, field in self.__fieldItems : fieldIntervalValues = list() for sourceInterval, fieldDestinationInterval in field.bitMap.destinationIntervals.items() : fieldIntervalValues.append( fieldDestinationInterval.value ) assert len( fieldIntervalValues ) == 1 if interval.value == fieldIntervalValues[ 0 ] : fieldOwnsInterval.append( field ) if len( fieldOwnsInterval ) != 1 : raise RuntimeError( 'Interval not found in field destinations' ) return fieldOwnsInterval[ 0 ] PK&N&registerMap/export/base/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc import logging log = logging.getLogger( __name__ ) class RegisterMapModulesIndirection : def __init__( self, moduleElements, ModuleType, RegisterType, FieldType ) : self.__elements = moduleElements self.__FieldType = FieldType self.__ModuleType = ModuleType self.__RegisterType = RegisterType def __getitem__( self, item ) : return self.__ModuleType( self.__elements[ item ], self.__RegisterType, self.__FieldType ) def __len__( self ) : return len( self.__elements ) class RegisterMapBase( metaclass = abc.ABCMeta ) : """ Representation of a RegisterMap for output using jinja2. """ def __init__( self, name, registerMapElement, typeConfiguration ) : super().__init__() self.name = name self._element = registerMapElement self.__typeConfiguration = typeConfiguration self.__memory = self.__typeConfiguration[ 'memory' ]( self._element.memory, self._element.spanMemoryUnits ) @property def memory( self ) : return self.__memory @property def modules( self ) : return RegisterMapModulesIndirection( list( self._element[ 'modules' ].values() ), self.__typeConfiguration[ 'module' ], self.__typeConfiguration[ 'register' ], self.__typeConfiguration[ 'field' ] ) @property def spanMemoryUnits( self ) : return self._element.spanMemoryUnits PK&N] ] #registerMap/export/base/template.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import logging import os log = logging.getLogger( __name__ ) class TemplateBase : """ Base functionality for management of templates. """ class Paths : def __init__( self ) : self.includeDirectory = None self.includePrefix = None self.sourceDirectory = None self.templatePackagePath = None def __init__( self, paths, licenseTextLines = None, subdir = None, suffixes = list() ) : self.__constructTemplateDirectoryPath( subdir ) self.createdDirectories = list() self.createdFiles = list() self.licenseTextLines = licenseTextLines self.paths = paths self.environment = jinja2.Environment( autoescape = jinja2.select_autoescape( suffixes ), keep_trailing_newline = True, loader = jinja2.PackageLoader( self.paths.templatePackagePath, self.templateDirectory ) ) def __constructTemplateDirectoryPath( self, subdir ) : if subdir is None : self.templateDirectory = 'templates' else : self.templateDirectory = os.path.join( 'templates', subdir ) log.debug( 'Template directory, {0}'.format( self.templateDirectory ) ) def createDirectory( self, thisDir ) : os.makedirs( thisDir, exist_ok = True ) self.createdDirectories.append( thisDir ) log.debug( 'Created directory, {0}'.format( self.createdDirectories[ -1 ] ) ) PK&N5ֵ)registerMap/export/base/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nא&registerMap/export/base/tests/mocks.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from ..field import FieldBase from ..memory import MemoryBase from ..module import ModuleBase from ..register import RegisterBase class MockField( FieldBase ) : def __init__( self, fieldElement ) : super().__init__( fieldElement ) self.expectedType = 'something' @property def type( self ) : return self.expectedType class MockRegister( RegisterBase ) : def __init__( self, registerElement, FieldType ) : super().__init__( registerElement, FieldType ) self.expectedAddress = '0x2f0d' self.expectedOffset = '0xf0d' @property def address( self ) : return self.expectedAddress @property def offset( self ) : return self.expectedOffset class MockModule( ModuleBase ) : def __init__( self, moduleElement, RegisterType, FieldType ) : super().__init__( moduleElement, RegisterType, FieldType ) self.expectedAddress = '0x20f0' self.expectedOffset = '0xf0' @property def address( self ) : return self.expectedAddress @property def offset( self ) : return self.expectedOffset class MockMemory( MemoryBase ) : def __init__( self, memoryElement, memorySize ) : super().__init__( memoryElement, memorySize ) @property def sizeType( self ) : return 'someValue' PK&NK4registerMap/export/base/tests/testExportFieldBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field import Field as FieldElement from .mocks import MockField class TestExportFieldBase( unittest.TestCase ) : def setUp( self ) : self.field = FieldElement() self.field[ 'name' ] = 'f1' self.field[ 'size' ] = 4 self.mockField = MockField( self.field ) def testName( self ) : self.assertEqual( self.field[ 'name' ], self.mockField.name ) def testSize( self ) : self.assertEqual( self.field[ 'size' ], self.mockField.size ) def testType( self ) : self.assertEqual( self.mockField.expectedType, self.mockField.type ) if __name__ == '__main__' : unittest.main() PK&NI5registerMap/export/base/tests/testExportMemoryBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap.structure.memory.configuration import MemoryConfiguration from ..memory import MemoryBase class MockMemory( MemoryBase ) : def __init__( self, memoryElement, memorySize ) : super().__init__( memoryElement, memorySize ) self.mock_sizeType = 'std::uint_least8_t' @property def sizeType( self ) : return self.mock_sizeType class TestMemory( unittest.TestCase ) : def setUp( self ) : self.memorySpace = MemoryConfiguration() self.memorySize = 10 self.memoryUnderTest = MockMemory( self.memorySpace, self.memorySize ) def testBaseAddressProperty( self ) : self.assertEqual( hex( self.memorySpace.baseAddress ), self.memoryUnderTest.baseAddress ) def testMemoryUnitSizeBitsProperty( self ) : self.assertEqual( self.memorySpace.memoryUnitBits, self.memoryUnderTest.memoryUnitBits ) def testSizeProperty( self ) : self.assertEqual( self.memorySize, self.memoryUnderTest.size ) if __name__ == '__main__' : unittest.main() PK&N%<<] ] 5registerMap/export/base/tests/testExportModuleBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap import RegisterMap from .mocks import \ MockField, \ MockModule, \ MockRegister class TestExportModuleBase( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module1 = self.registerMap.addModule( 'm1' ) self.exportUnderTest = MockModule( self.module1, MockRegister, MockField ) def testName( self ) : self.assertEqual( self.module1[ 'name' ], self.exportUnderTest.name ) def testEmptyModule( self ) : self.assertEqual( 0, len( self.exportUnderTest.registers ) ) def testHexAddress( self ) : self.assertEqual( self.exportUnderTest.expectedAddress, self.exportUnderTest.address ) def testOffset( self ) : self.assertEqual( self.exportUnderTest.expectedOffset, self.exportUnderTest.offset ) def testRegisters( self ) : self.register1 = self.module1.addRegister( 'r1' ) self.register1.addField( 'f1', (0, 2) ) self.register1.addField( 'f2', (3, 4) ) self.register1.addField( 'f3', (5, 7) ) self.register2 = self.module1.addRegister( 'r2' ) self.register2.addField( 'f1', (0, 2) ) self.register2.addField( 'f2', (3, 4) ) self.register2.addField( 'f3', (5, 7) ) for expectedRegisterName, thisRegister in zip( [ 'r1', 'r2' ], self.exportUnderTest.registers ) : self.assertEqual( expectedRegisterName, thisRegister.name ) for expectedFieldName, thisField in zip( [ 'f1', 'f2', 'f3' ], thisRegister.fields ) : self.assertEqual( expectedFieldName, thisField.name ) if __name__ == '__main__' : unittest.main() PK&NB  5registerMap/export/base/tests/testExportOutputBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap import RegisterMap from ..output import OutputBase class MockOptions : def __init__( self ) : self.output = None self.packAlignment = None class MockOutput( OutputBase ) : def __init__( self, outputOptions, licenseTextLines = list() ) : super().__init__( outputOptions, licenseTextLines = licenseTextLines ) def generate( self, registerMap, registerMapName ) : pass class TestOutputBase( unittest.TestCase ) : def setUp( self ) : self.filePath = 'some/path' self.registerMap = RegisterMap() self.registerMap.addModule( 'm1' ) self.registerMap.addModule( 'm2' ) def testOutputDirectoryProperty( self ) : mockOptions = MockOptions() mockOptions.output = self.filePath with unittest.mock.patch( 'registerMap.export.base.output.OutputBase._OutputBase__validateOutputDirectory' ) : outputUnderTest = MockOutput( mockOptions ) self.assertEqual( self.filePath, outputUnderTest.outputDirectory ) def testPackAlignmentOption( self ) : mockOptions = MockOptions() mockOptions.packAlignment = 10 with unittest.mock.patch( 'registerMap.export.base.output.OutputBase._OutputBase__validateOutputDirectory' ) : outputUnderTest = MockOutput( mockOptions ) self.assertEqual( mockOptions.packAlignment, outputUnderTest.outputOptions.packAlignment ) if __name__ == '__main__' : unittest.main() PK&Nq}tt7registerMap/export/base/tests/testExportRegisterBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap import RegisterMap from ..register import RegisterBase from .mocks import \ MockField, \ MockRegister class TestExportRegisterBase( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module1 = self.registerMap.addModule( 'm1' ) self.register1 = self.module1.addRegister( 'r1' ) self.exportUnderTest = MockRegister( self.register1, MockField ) def testName( self ) : self.assertEqual( self.register1[ 'name' ], self.exportUnderTest.name ) def testEmptyRegister( self ) : self.assertEqual( 0, len( self.exportUnderTest.fields ) ) def testAddressProperty( self ) : self.assertEqual( self.exportUnderTest.expectedAddress, self.exportUnderTest.address ) def testOffsetProperty( self ) : self.assertEqual( self.exportUnderTest.expectedOffset, self.exportUnderTest.offset ) def testFields( self ) : self.register1.addField( 'f1', (0, 2) ) self.register1.addField( 'f2', (3, 4) ) self.register1.addField( 'f3', (5, 7) ) for expectedName, expectedSize, thisField in zip( [ 'f1', 'f2', 'f3' ], [ 3, 2, 3 ], self.exportUnderTest.fields ) : self.assertEqual( expectedName, thisField.name ) self.assertEqual( expectedSize, thisField.size ) class TestRegisterBasePrecedingGapProperty( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module1 = self.registerMap.addModule( 'm1' ) self.register1 = self.module1.addRegister( 'r1' ) self.assertEqual( 0, self.register1.startAddress ) def testType( self ) : r2 = self.module1.addRegister( 'r2' ) self.assertEqual( 1, r2.startAddress ) exportUnderTest = RegisterBase( r2, MockField ) self.assertTrue( isinstance( exportUnderTest.precedingGapBytes, int ) ) def testZeroGap( self ) : r2 = self.module1.addRegister( 'r2' ) self.assertEqual( 1, r2.startAddress ) exportUnderTest = RegisterBase( r2, MockField ) self.assertEqual( 0, exportUnderTest.precedingGapBytes ) def testNonZeroGap( self ) : r2 = self.module1.addRegister( 'r2' ) r2[ 'constraints' ][ 'fixedAddress' ] = 0x10 self.assertEqual( 0x10, r2.startAddress ) exportUnderTest = RegisterBase( r2, MockField ) self.assertEqual( (0x10 - 1), exportUnderTest.precedingGapBytes ) def testNonZeroGap16BitMemoryUnit( self ) : self.module1.memory.memoryUnitBits = 16 r2 = self.module1.addRegister( 'r2' ) r2[ 'constraints' ][ 'fixedAddress' ] = 0x10 self.assertEqual( 0x10, r2.startAddress ) exportUnderTest = RegisterBase( r2, MockField ) self.assertEqual( ((0x10 - 1) * 2), exportUnderTest.precedingGapBytes ) if __name__ == '__main__' : unittest.main() PK&N9CregisterMap/export/base/tests/testExportRegisterContiguousFields.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap import RegisterMap from registerMap.structure.interval import sortIntervals from ..field import FieldBase from ..register import RegisterContiguousFieldIntervals as Register class MockField( FieldBase ) : def __init__( self, element ) : super().__init__( element ) @property def type( self ) : return 'unsigned' class TestCppRegisterFieldOrdering( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() m1 = self.registerMap.addModule( 'm1' ) self.r1 = m1.addRegister( 'r1' ) self.cppRegisterUnderTest = Register( self.r1, MockField ) def testContiguousLocalFields( self ) : expectedFields = [ self.r1.addField( 'f1', (0, 3) ), self.r1.addField( 'f2', (4, 6) ), self.r1.addField( 'f3', (7, 7) ), ] self.assertEqual( 8, self.r1.sizeBits ) registerIntervals = sortIntervals( self.r1.bitMap.sourceIntervals ) fieldsUnderTest = self.cppRegisterUnderTest.fields self.assertEqual( len( registerIntervals ), len( fieldsUnderTest ) ) self.assertEqual( len( expectedFields ), len( registerIntervals ) ) for index in range( 0, len( registerIntervals ) ) : expectedInterval = registerIntervals[ index ].value fieldIntervals = sortIntervals( fieldsUnderTest[ index ]._element.bitMap.destinationIntervals.values() ) self.assertEqual( 1, len( fieldIntervals ) ) self.assertEqual( expectedInterval, fieldIntervals[ 0 ].value ) def testNoncontiguousLocalFields8BitRegister( self ) : self.r1.addField( 'f1', (0, 1) ) # Unassigned interval (2, 3) self.r1.addField( 'f2', (4, 5) ) # Unassigned interval (6, 6) self.r1.addField( 'f3', (7, 7) ) self.assertEqual( 8, self.r1.sizeBits ) expectedNumberFields = 5 fieldsUnderTest = self.cppRegisterUnderTest.fields self.assertEqual( expectedNumberFields, len( fieldsUnderTest ) ) # Can only check names and sizes for inserted gaps expectedSizes = [ 2, 2, 2, 1, 1, ] actualSizes = [ x._element[ 'size' ] for x in fieldsUnderTest ] self.assertEqual( expectedSizes, actualSizes ) expectedNames = [ 'f1', '', 'f2', '', 'f3', ] actualNames = [ x._element[ 'name' ] for x in fieldsUnderTest ] self.assertEqual( expectedNames, actualNames ) def testNoncontiguousLocalFields8BitRegisterStartsWithUnassignedf( self ) : # Unassigned interval (0, 0) self.r1.addField( 'f1', (1, 1) ) # Unassigned interval (2, 3) self.r1.addField( 'f2', (4, 5) ) # Unassigned interval (6, 6) self.r1.addField( 'f3', (7, 7) ) self.assertEqual( 8, self.r1.sizeBits ) expectedNumberFields = 6 fieldsUnderTest = self.cppRegisterUnderTest.fields self.assertEqual( expectedNumberFields, len( fieldsUnderTest ) ) # Can only check names and sizes for inserted gaps expectedSizes = [ 1, 1, 2, 2, 1, 1, ] actualSizes = [ x._element[ 'size' ] for x in fieldsUnderTest ] self.assertEqual( expectedSizes, actualSizes ) expectedNames = [ '', 'f1', '', 'f2', '', 'f3', ] actualNames = [ x._element[ 'name' ] for x in fieldsUnderTest ] self.assertEqual( expectedNames, actualNames ) def testNoncontiguousLocalFields16BitRegister( self ) : self.r1.addField( 'f1', (0, 1) ) # Unassigned interval (2, 3) self.r1.addField( 'f2', (4, 5) ) # Unassigned interval (6, 6) self.r1.addField( 'f3', (7, 9) ) # Unassigned interval (10, 15) expectedNumberFields = 6 fieldsUnderTest = self.cppRegisterUnderTest.fields self.assertEqual( expectedNumberFields, len( fieldsUnderTest ) ) # Can only check names and sizes for inserted gaps expectedSizes = [ 2, 2, 2, 1, 3, 6, ] actualSizes = [ x._element[ 'size' ] for x in fieldsUnderTest ] self.assertEqual( expectedSizes, actualSizes ) expectedNames = [ 'f1', '', 'f2', '', 'f3', '', ] actualNames = [ x._element[ 'name' ] for x in fieldsUnderTest ] self.assertEqual( expectedNames, actualNames ) if __name__ == '__main__' : unittest.main() PK&N̘s:registerMap/export/base/tests/testExportRegisterMapBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap import RegisterMap from ..registerMap import RegisterMapBase from ..memory import MemoryBase from .mocks import \ MockField, \ MockMemory, \ MockModule, \ MockRegister MOCK_TYPE_CONFIGURATION = { 'field' : MockField, 'memory' : MockMemory, 'module' : MockModule, 'register' : MockRegister, } class TestRegisterMapBase( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() m1 = self.registerMap.addModule( 'm1' ) m1 = self.registerMap.addModule( 'm2' ) def testMemoryProperty( self ) : exporterUnderTest = RegisterMapBase( 'thisRegisterMap', self.registerMap, MOCK_TYPE_CONFIGURATION ) self.assertTrue( isinstance( exporterUnderTest.memory, MemoryBase ) ) self.assertEqual(self.registerMap.spanMemoryUnits, exporterUnderTest.memory.size) def testModuleIndirection( self ) : exporterUnderTest = RegisterMapBase( 'thisRegisterMap', self.registerMap, MOCK_TYPE_CONFIGURATION ) for expectedName, thisModule in zip( [ 'm1', 'm2' ], exporterUnderTest.modules ) : self.assertEqual( expectedName, thisModule.name ) def testSpanMemoryUnitsProperty( self ) : exporterUnderTest = RegisterMapBase( 'thisRegisterMap', self.registerMap, MOCK_TYPE_CONFIGURATION ) self.assertEqual( self.registerMap.spanMemoryUnits, exporterUnderTest.spanMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&Nf hh7registerMap/export/base/tests/testExportTemplateBase.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import os import unittest.mock from registerMap.export.base.template import TemplateBase class TestExportTemplateBase( unittest.TestCase ) : def setUp( self ) : self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' def testDefaults( self ) : here = os.path.abspath( os.path.dirname( __file__ ) ) expectedTemplateDir = 'templates' paths = TemplateBase.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory paths.templatePackagePath = 'registerMap.export.c.output' outputUnderTest = TemplateBase( paths ) self.assertEqual( expectedTemplateDir, outputUnderTest.templateDirectory ) self.assertEqual( self.includeDirectory, outputUnderTest.paths.includeDirectory ) self.assertEqual( self.sourceDirectory, outputUnderTest.paths.sourceDirectory ) self.assertEqual( list(), outputUnderTest.createdDirectories ) self.assertEqual( list(), outputUnderTest.createdFiles ) def testTemplateLicenseTextLines( self ) : lines = [ 'this line', 'another line', ] paths = TemplateBase.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory paths.templatePackagePath = 'registerMap.export.c.output' outputUnderTest = TemplateBase( paths, licenseTextLines = lines ) self.assertEqual( lines, outputUnderTest.licenseTextLines ) def testTemplateSubDir( self ) : subdir = 'thisSubdir' expectedValue = os.path.join( 'templates', subdir ) paths = TemplateBase.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory paths.templatePackagePath = 'registerMap.export.c.output' outputUnderTest = TemplateBase( paths, subdir = subdir ) actualValue = outputUnderTest.templateDirectory self.assertEqual( expectedValue, actualValue ) def testCreateDirectorry( self ) : paths = TemplateBase.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory paths.templatePackagePath = 'registerMap.export.c.output' outputUnderTest = TemplateBase( paths ) expectedValue = 'some/path' with unittest.mock.patch( 'registerMap.export.base.template.os.makedirs' ) as mock_makedirs : outputUnderTest.createDirectory( expectedValue ) mock_makedirs.assert_called_once_with( expectedValue, exist_ok = True ) self.assertEqual( 1, len( outputUnderTest.createdDirectories ) ) self.assertIn( expectedValue, outputUnderTest.createdDirectories ) if __name__ == '__main__' : unittest.main() PK&Ni   registerMap/export/c/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .arguments import CArgumentParser from .registerMap import Output PK&NQ!registerMap/export/c/arguments.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from ..base.interface import LanguageParser from .options import COptions from .registerMap import Output class CArgumentParser( LanguageParser ) : def __init__( self, parentParser ) : self.parser = parentParser.add_parser( 'c' ) self.parser.add_argument( 'output', help = 'Directory to place the generated files. Created if not present.' ) self.parser.add_argument( '--pack', default = None, help = 'Pragma pack alignment value. Default None.', nargs = 1, type = int ) self.parser.add_argument( '--include-prefix', default = [ '' ], help = 'Prefix path to register map include files. Default None.', nargs = 1, type = str ) def acquireOptions( self, parserProcessedArguments ) : options = COptions() options.generator = Output options.output = parserProcessedArguments.output if parserProcessedArguments.pack is not None : options.packAlignment = parserProcessedArguments.pack[ 0 ] else : options.packAlignment = None if parserProcessedArguments.include_prefix is not None : options.includePrefix = parserProcessedArguments.include_prefix[ 0 ] else : options.includePrefix = None return options PK&N$mmregisterMap/export/c/options.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # class COptions : def __init__( self ) : self.generator = None self.includePrefix = None self.output = None self.packAlignment = None PK&Nt;RNN#registerMap/export/c/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import os from ..base import \ OutputBase from .elements import \ Memory, \ RegisterMap from .output import \ MacroTemplates, \ MemoryTemplates, \ ModuleTemplates, \ RegisterMapTemplates log = logging.getLogger( __name__ ) class Output( OutputBase ) : """ Export a C source code representation of the register map. """ def __init__( self, outputOptions, licenseTextLines = list() ) : super().__init__( outputOptions, licenseTextLines = licenseTextLines ) self.includePath = None self.sourceDirectory = None self.suffixes = [ '.h', '.c' ] def __createDirectories( self, registerMapName ) : self.includePath = os.path.join( self.outputDirectory, 'include', self.outputOptions.includePrefix, registerMapName ) self.createDirectory( self.includePath ) self.sourceDirectory = os.path.join( self.outputDirectory, 'source', registerMapName ) self.createDirectory( self.sourceDirectory ) def generate( self, registerMap, registerMapName ) : """ Export the register map representation. :param registerMap: A RegisterMap instance for export. :param registerMapName: A public name for the register map used in source code file structure and object names. """ self.__createDirectories( registerMapName ) encapsulatedRegisterMap = RegisterMap( registerMapName, registerMap ) encapsulatedRegisterMap.memory.alignment = self.outputOptions.packAlignment paths = MacroTemplates.Paths() paths.includeDirectory = self.includePath paths.includePrefix = os.path.join( self.outputOptions.includePrefix, registerMapName ) paths.sourceDirectory = self.sourceDirectory buildOrder = [ MacroTemplates( paths, registerMapName, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), MemoryTemplates( paths, registerMapName, encapsulatedRegisterMap.memory, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), ModuleTemplates( paths, encapsulatedRegisterMap, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), RegisterMapTemplates( paths, encapsulatedRegisterMap, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), ] for build in buildOrder : build.apply() PK&NaVV)registerMap/export/c/elements/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .field import Field from .memory import Memory from .module import Module from .register import Register from .registerMap import RegisterMap PK&N1m&registerMap/export/c/elements/field.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import FieldBase class Field( FieldBase ) : __knownTypes = { 8 : 'uint8_t', 16 : 'uint16_t', 32 : 'uint32_t', 64 : 'uint64_t', } def __init__( self, fieldElement ) : super().__init__( fieldElement ) @property def type( self ) : assert self._element[ 'size' ] <= max( [ x for x in self.__knownTypes.keys() ] ) leastSize = min( [ x for x in self.__knownTypes.keys() if x >= self._element[ 'size' ] ] ) thisType = self.__knownTypes[ leastSize ] return thisType PK&N(EE'registerMap/export/c/elements/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import MemoryBase class Memory( MemoryBase ) : __knownTypes = { 8 : 'uint8_t', 16 : 'uint16_t', 32 : 'uint32_t', 64 : 'uint64_t', } def __init__( self, memoryElement, memorySize ) : super().__init__( memoryElement, memorySize ) self.alignment = '' @property def sizeType( self ) : assert self.memoryUnitBits <= max( [ x for x in self.__knownTypes.keys() ] ) leastSize = min( [ x for x in self.__knownTypes.keys() if x >= self.memoryUnitBits ] ) thisType = self.__knownTypes[ leastSize ] return thisType PK&NL cc'registerMap/export/c/elements/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import ModuleBase from .field import Field from .register import Register class Module( ModuleBase ) : def __init__( self, moduleElement, RegisterType, FieldType ) : super().__init__( moduleElement, RegisterType, FieldType ) @property def address( self ) : """ The absolute base address of the module formatted for C, in hexadecimal. """ return hex( self._element.baseAddress ) @property def offset( self ) : """ The offset of the module formated for C, relative to the base address of the register map. """ return hex( self._element.offset ) PK&Nl;)registerMap/export/c/elements/register.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import RegisterContiguousFieldIntervals as Register PK&Nrps,registerMap/export/c/elements/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import RegisterMapBase from .field import Field from .memory import Memory from .module import Module from .register import Register C_TYPE_CONFIGURATION = { 'field' : Field, 'memory' : Memory, 'module' : Module, 'register' : Register, } class RegisterMap( RegisterMapBase ) : def __init__( self, registerMapName, registerMap ) : super().__init__( registerMapName, registerMap, C_TYPE_CONFIGURATION ) PK&N5ֵ/registerMap/export/c/elements/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NՃR1registerMap/export/c/elements/tests/testCField.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..field import Field class TestCExportField( unittest.TestCase ) : def setUp( self ) : self.mockFieldElement = { 'size' : 0, } self.fieldUnderTest = Field( self.mockFieldElement ) def testValidTypes( self ) : expectedValues = [ { 'size' : 8, 'type' : 'uint8_t', }, { 'size' : 9, 'type' : 'uint16_t', }, { 'size' : 16, 'type' : 'uint16_t', }, { 'size' : 17, 'type' : 'uint32_t', }, { 'size' : 32, 'type' : 'uint32_t', }, { 'size' : 33, 'type' : 'uint64_t', }, { 'size' : 64, 'type' : 'uint64_t', }, ] for thisValue in expectedValues : self.mockFieldElement[ 'size' ] = thisValue[ 'size' ] self.assertEqual( thisValue[ 'type' ], self.fieldUnderTest.type ) def testTypeGreaterThan64Asserts( self ) : # Assume that 64 bit is the maximum field size type allowed. self.mockFieldElement[ 'size' ] = 65 with self.assertRaises( AssertionError ) : self.fieldUnderTest.type if __name__ == '__main__' : unittest.main() PK&Ngg2registerMap/export/c/elements/tests/testCMemory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.memory.configuration import MemoryConfiguration from ..memory import Memory as CppMemory class TestCMemory( unittest.TestCase ) : def setUp( self ) : self.memorySpace = MemoryConfiguration() self.memorySize = 10 self.memoryUnderTest = CppMemory( self.memorySpace, self.memorySize ) def testDefaultAlignmentProperty( self ) : self.assertEqual( '', self.memoryUnderTest.alignment ) def testMemorySizeType( self ) : self.memorySpace.memoryUnitBits = 32 self.assertEqual( 'uint32_t', self.memoryUnderTest.sizeType ) if __name__ == '__main__' : unittest.main() PK&NjK[['registerMap/export/c/output/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .macro import MacroTemplates from .memory import MemoryTemplates from .module import ModuleTemplates from .registerMap import RegisterMapTemplates PK&NdH#registerMap/export/c/output/base.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # C_TEMPLATE_PACKAGE = 'registerMap.export.c.output' PK&Ns$registerMap/export/c/output/macro.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import MacroTemplatesBase from .base import C_TEMPLATE_PACKAGE MACRO_TEMPLATE_CONFIGURATION = { 'files' : [ { 'file' : 'assert.h', 'template' : 'assert_template.h', }, { 'file' : 'extern.h', 'template' : 'extern_template.h', }, ], 'template-package' : C_TEMPLATE_PACKAGE, } class MacroTemplates( MacroTemplatesBase ) : def __init__( self, paths, registerMapName, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MACRO_TEMPLATE_CONFIGURATION, registerMapName, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&N-%registerMap/export/c/output/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import MemoryTemplatesBase from .base import C_TEMPLATE_PACKAGE MEMORY_TEMPLATE_CONFIGURATION = { 'header' : [ { 'file' : 'memory.h', 'template' : 'memory_template.h', }, ], 'source' : [ # There are no source files for the C memory implementation. ], 'template-package' : C_TEMPLATE_PACKAGE, } class MemoryTemplates( MemoryTemplatesBase ) : def __init__( self, paths, registerMapName, encapsulatedMemory, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MEMORY_TEMPLATE_CONFIGURATION, registerMapName, encapsulatedMemory, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&N6V%registerMap/export/c/output/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import ModuleTemplatesBase from ..elements import \ Field, \ Module, \ Register from .base import C_TEMPLATE_PACKAGE MODULE_TEMPLATE_CONFIGURATION = { 'module-template' : 'module_template.h', 'header-suffix' : 'h', 'template-package' : C_TEMPLATE_PACKAGE, 'field-type' : Field, 'module-type' : Module, 'register-type' : Register, } class ModuleTemplates( ModuleTemplatesBase ) : def __init__( self, paths, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MODULE_TEMPLATE_CONFIGURATION, encapsulatedRegisterMap, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&Nd2kk*registerMap/export/c/output/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import RegisterMapTemplatesBase from ..elements import RegisterMap from .base import C_TEMPLATE_PACKAGE REGISTERMAP_TEMPLATE_CONFIGURATION = { 'registermap' : 'registerMap.h', 'header-template' : 'registerMap_template.h', 'source-template' : 'registerMap_template.c', 'source-suffix' : 'c', 'registermap-type' : RegisterMap, 'template-package' : C_TEMPLATE_PACKAGE, } class RegisterMapTemplates( RegisterMapTemplatesBase ) : def __init__( self, paths, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : paths.templatePackagePath = REGISTERMAP_TEMPLATE_CONFIGURATION[ 'template-package' ] super().__init__( paths, REGISTERMAP_TEMPLATE_CONFIGURATION, encapsulatedRegisterMap, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&N:#AregisterMap/export/c/output/templates/idiomatic/memory_template.h/* * * {{ registerMapName }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_MEMORY_H #define {{ registerMapName|upper }}_MEMORY_H #include #include "{{ prefixPath }}/macro/extern.h" {{ registerMapName|upper }}_OPEN_EXTERN_C {% set memoryPointerType = memory.sizeType~' volatile* const' -%} struct {{ registerMapName }}_MemorySpace_t { #ifdef OFF_TARGET_MEMORY uint_least32_t const allocated_memory_span; {{ memory.sizeType }} volatile base[ {{ memory.size }} ]; #else {{ memoryPointerType }} base; #endif }; {{ registerMapName|upper }}_CLOSE_EXTERN_C #endif PK&NGAregisterMap/export/c/output/templates/idiomatic/module_template.h/* * * Module: {{ module.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_{{ module.name|upper }}_H #define {{ registerMapName|upper }}_{{ module.name|upper }}_H #include #include "{{ prefixPath }}/macro/extern.h" #include "{{ prefixPath }}/memory/memory.h" #include "{{ prefixPath }}/registerMap.h" {% if module.registers|count != 0 %} {{ registerMapName|upper }}_OPEN_EXTERN_C {%- for thisRegister in module.registers %} {%- set canonicalRegisterName = module.name~'_'~thisRegister.name %} {%- set typeName = canonicalRegisterName~'_t' %} struct {{ registerMapName }}_{{ typeName }} { {%- for bitField in thisRegister.fields %} {{ bitField.type }} volatile {{ bitField.name }}:{{ bitField.size }}; {%- endfor %} }; {% endfor %} #pragma pack( {{ registerMapMemoryAlignment }} ) struct {{ registerMapName }}_{{ module.name }}_t { {%- for thisRegister in module.registers %} {%- if thisRegister.precedingGapBytes != 0 %} uint8_t gap_{{ thisRegister.name }}[{{ thisRegister.precedingGapBytes }}]; {%- endif %} {%- set canonicalRegisterName = module.name~'_'~thisRegister.name %} {%- set typeName = canonicalRegisterName~'_t volatile' %} struct {{ registerMapName }}_{{ typeName }} {{ thisRegister.name }}; {% endfor -%} }; #pragma pack() {{ registerMapName|upper }}_CLOSE_EXTERN_C {%- else %} // {{ registerMapName }}_{{ module.name }} is an empty module {%- endif %} #endif PK&Nc0LLFregisterMap/export/c/output/templates/idiomatic/registerMap_template.c/* * * {{ registerMap.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #include "{{ prefixPath }}/macro/extern.h" #include "{{ prefixPath }}/memory/memory.h" #include "{{ prefixPath }}/registerMap.h" {{ registerMap.name|upper }}_OPEN_EXTERN_C #ifdef OFF_TARGET_MEMORY struct {{ registerMap.name }}_MemorySpace_t myRegisterMap_memory = { .allocated_memory_span = {{ memory.size }}, }; #else {% set memoryPointerType = memory.sizeType~' volatile* const' -%} struct {{ registerMap.name }}_MemorySpace_t myRegisterMap_memory = { .allocated_memory_span = {{ memory.size }}, .base = ( {{ memoryPointerType }} ) {{ memory.baseAddress }}, }; #endif struct {{ registerMap.name }}_t {{ registerMap.name }} = { {%- for thisModule in registerMap.modules %} {%- set pointerType = registerMap.name~'_'~thisModule.name~'_t volatile* const' %} .{{ thisModule.name }} = ( {{ pointerType }} )( {{ registerMap.name }}_memory.base + {{ thisModule.offset }} ), {% endfor -%} }; {{ registerMap.name|upper }}_CLOSE_EXTERN_C PK&No]llFregisterMap/export/c/output/templates/idiomatic/registerMap_template.h/* * * {{ registerMap.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMap.name|upper }}_H #define {{ registerMap.name|upper }}_H #include "{{ prefixPath }}/macro/extern.h" #include "{{ prefixPath }}/memory/memory.h" {% for thisModule in registerMap.modules -%} #include "{{ prefixPath }}/modules/{{ thisModule.name }}.h" {% endfor %} {{ registerMap.name|upper }}_OPEN_EXTERN_C {%- set registerMapType = registerMap.name~'_t' %} {%- if registerMap.modules|count != 0 %} #pragma pack( {{ registerMap.memory.alignment }} ) struct {{ registerMapType }} { {%- for thisModule in registerMap.modules %} {%- set pointerType = thisModule.name~'_t volatile* const' %} struct {{ registerMap.name }}_{{ pointerType }} {{ thisModule.name }}; {%- endfor %} }; #pragma pack() // Declare the register map instance for users. extern struct {{ registerMap.name }}_MemorySpace_t {{ registerMap.name }}_memory; extern struct {{ registerMap.name }}_t {{ registerMap.name }}; {%- endif %} {{ registerMap.name|upper }}_CLOSE_EXTERN_C #endif PK&NpS|CC=registerMap/export/c/output/templates/macro/assert_template.h/* * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_ASSERT_H #define {{ registerMapName|upper }}_ASSERT_H #ifndef DISABLE_RUNTIME_ASSERT #include #define RUNTIME_ASSERT(expression) \ assert(expression) #else #define RUNTIME_ASSERT() #endif #ifndef DISABLE_COMPILETIME_ASSERT #define COMPILETIME_ASSERT(expression) \ #if !(expression) \ #error "ASSERTION FAILED: " #expression \ #endif #else #define COMPILETIME_ASSERT(expression) #endif #endif PK&N@=registerMap/export/c/output/templates/macro/extern_template.h/* * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_EXTERN_H #define {{ registerMapName|upper }}_EXTERN_H #ifdef __cplusplus #define {{ registerMapName|upper }}_OPEN_EXTERN_C extern "C" { #define {{ registerMapName|upper }}_CLOSE_EXTERN_C } #else /* Empty macro to disable extern C */ #define {{ registerMapName|upper }}_OPEN_EXTERN_C #define {{ registerMapName|upper }}_CLOSE_EXTERN_C #endif #endif PK&N5ֵ-registerMap/export/c/output/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Ni7registerMap/export/c/output/tests/testCMacroTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import copy import jinja2 import os import unittest.mock from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..macro import \ MACRO_TEMPLATE_CONFIGURATION, \ MacroTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.c.output.macro.MacroTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.macro.open' class TestMacroTemplate( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' def testDefaults( self ) : expectedMacroDirectory = os.path.join( self.includeDirectory, 'macro' ) expectedTemplateDirectory = os.path.join( 'templates', 'macro' ) paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) self.assertEqual( self.expectedName, outputUnderTest.registerMapName ) self.assertEqual( expectedTemplateDirectory, outputUnderTest.templateDirectory ) self.assertEqual( expectedMacroDirectory, outputUnderTest.macroDirectory ) def testInitialCreatedFiles( self ) : paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/macro/assert.h', 'include/path/macro/extern.h', ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) mock_template.render.assert_has_calls( [ unittest.mock.call( registerMapName = self.expectedName, licenseText = None ), unittest.mock.call( registerMapName = self.expectedName, licenseText = None ), ] ) mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.macroDirectory ), ] ) class TestAssertMacroTemplate( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.templateConfig = copy.deepcopy( MACRO_TEMPLATE_CONFIGURATION ) self.templateConfig[ 'files' ] = [ self.templateConfig[ 'files' ][ 0 ] ] def testAssertMacroOutput( self ) : paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) outputUnderTest.configuration = self.templateConfig actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_ASSERT_H\n', '#define SOMENAME_ASSERT_H\n', '\n', '\n', '#ifndef DISABLE_RUNTIME_ASSERT\n', '\n', '#include \n', '#define RUNTIME_ASSERT(expression) \\\n', ' assert(expression)\n', '\n', '#else\n', '\n', '#define RUNTIME_ASSERT()\n', '\n', '#endif\n', '\n', '\n', '#ifndef DISABLE_COMPILETIME_ASSERT\n', '\n', '#define COMPILETIME_ASSERT(expression) \\\n', '#if !(expression) \\\n', '#error "ASSERTION FAILED: " #expression \\\n', '#endif\n', '\n', '#else\n', '\n', '#define COMPILETIME_ASSERT(expression)\n', '\n', '#endif\n', '\n', '\n', '#endif\n', ] self.assertEqual( expectedLines, actualLines ) class TestExternMacroTemplate( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.templateConfig = copy.deepcopy( MACRO_TEMPLATE_CONFIGURATION ) self.templateConfig[ 'files' ] = [ self.templateConfig[ 'files' ][ 1 ] ] def testExternMacroOutput( self ) : paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) outputUnderTest.configuration = self.templateConfig actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_EXTERN_H\n', '#define SOMENAME_EXTERN_H\n', '\n', '#ifdef __cplusplus\n', '\n', '#define SOMENAME_OPEN_EXTERN_C extern "C" {\n', '#define SOMENAME_CLOSE_EXTERN_C }\n', '\n', '#else\n', '\n', '/* Empty macro to disable extern C */\n', '#define SOMENAME_OPEN_EXTERN_C\n', '#define SOMENAME_CLOSE_EXTERN_C\n', '\n', '#endif\n', '\n', '#endif\n', ] self.assertEqual( expectedLines, actualLines ) if __name__ == '__main__' : unittest.main() PK&NOA8registerMap/export/c/output/tests/testCMemoryTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import os import unittest.mock from registerMap.export.c.elements import Memory from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..memory import MemoryTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.c.output.memory.MemoryTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.memory.open' class TestCMemoryTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/this/path' self.sourceDirectory = 'source/path' self.mock_Memory = unittest.mock.create_autospec( Memory ) self.mock_Memory.size = 345 self.mock_Memory.sizeType = 'uint_least8_t' def testDefaults( self ) : expectedMemoryDirectory = os.path.join( self.includeDirectory, 'memory' ) expectedTemplateDirectory = os.path.join( 'templates', 'idiomatic' ) paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/path' paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) self.assertEqual( self.expectedName, outputUnderTest.registerMapName ) self.assertEqual( expectedTemplateDirectory, outputUnderTest.templateDirectory ) self.assertEqual( expectedMemoryDirectory, outputUnderTest.memoryDirectory ) self.assertEqual( self.mock_Memory, outputUnderTest.encapsulatedMemory ) def testInitialCreatedFiles( self ) : paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/path' paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/this/path/memory/memory.h' ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) mock_template.render.assert_called_once() mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.memoryDirectory ), ] ) def testMemoryOutput( self ) : paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' * someName\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_MEMORY_H\n', '#define SOMENAME_MEMORY_H\n', '\n', '#include \n', '\n', '#include "this/prefix/macro/extern.h"\n', '\n', '\n', 'SOMENAME_OPEN_EXTERN_C\n', '\n', 'struct someName_MemorySpace_t\n', '{\n', '#ifdef OFF_TARGET_MEMORY\n', '\n', ' uint_least32_t const allocated_memory_span;\n', '\n', " uint_least8_t volatile base[ 345 ];\n", '\n', '#else\n', '\n', " uint_least8_t volatile* const base;\n", '\n', '#endif\n', '};\n', '\n', 'SOMENAME_CLOSE_EXTERN_C\n', '\n', '#endif\n', ] self.assertEqual( expectedLines, actualLines ) if __name__ == '__main__' : unittest.main() PK&N{q,,8registerMap/export/c/output/tests/testCModuleTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import unittest.mock from registerMap import RegisterMap as ImportedRegisterMap from registerMap.export.c.elements.memory import Memory from registerMap.export.c.elements.registerMap import RegisterMap from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..module import ModuleTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.c.output.module.ModuleTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.module.open' class TestCModuleTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.__setupRegisterMap() def __setupRegisterMap( self ) : registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 2) ) r1.addField( 'f2', (3, 4) ) r1.addField( 'f3', (5, 15) ) self.registerMap = RegisterMap( self.expectedName, registerMap ) def testInitialCreatedFiles( self ) : paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/modules/m1.h' ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) mock_template.render.assert_called_once() mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.moduleDirectory ), ] ) def testContiguousFieldsRegisterData( self ) : expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" SOMENAME_OPEN_EXTERN_C struct someName_m1_r1_t { uint8_t volatile f1:3; uint8_t volatile f2:2; uint16_t volatile f3:11; }; #pragma pack( ) struct someName_m1_t { struct someName_m1_r1_t volatile r1; }; #pragma pack() SOMENAME_CLOSE_EXTERN_C #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = '{}'.format( ''.join( actualLines ) ) self.assertEqual( expectedText, actualText ) class TestNoncontiguousRegisterOutput( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) self.registerMap = RegisterMap( self.expectedName, registerMap ) def testNoncontiguousFieldsSingleByteRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 1) ) r1.addField( 'f2', (4, 5) ) r1.addField( 'f3', (7, 7) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" SOMENAME_OPEN_EXTERN_C struct someName_m1_r1_t { uint8_t volatile f1:2; uint8_t volatile :2; uint8_t volatile f2:2; uint8_t volatile :1; uint8_t volatile f3:1; }; #pragma pack( ) struct someName_m1_t { struct someName_m1_r1_t volatile r1; }; #pragma pack() SOMENAME_CLOSE_EXTERN_C #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) def testNoncontiguousFieldsStartsRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (2, 4) ) r1.addField( 'f2', (5, 5) ) r1.addField( 'f3', (7, 7) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" SOMENAME_OPEN_EXTERN_C struct someName_m1_r1_t { uint8_t volatile :2; uint8_t volatile f1:3; uint8_t volatile f2:1; uint8_t volatile :1; uint8_t volatile f3:1; }; #pragma pack( ) struct someName_m1_t { struct someName_m1_r1_t volatile r1; }; #pragma pack() SOMENAME_CLOSE_EXTERN_C #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) def testNoncontiguousFieldsMultiByteRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 1) ) r1.addField( 'f2', (4, 5) ) r1.addField( 'f3', (7, 9) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" SOMENAME_OPEN_EXTERN_C struct someName_m1_r1_t { uint8_t volatile f1:2; uint8_t volatile :2; uint8_t volatile f2:2; uint8_t volatile :1; uint8_t volatile f3:3; uint8_t volatile :6; }; #pragma pack( ) struct someName_m1_t { struct someName_m1_r1_t volatile r1; }; #pragma pack() SOMENAME_CLOSE_EXTERN_C #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) class TestEmptyModuleOutput( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 m1 = registerMap.addModule( 'm1' ) self.moduleUnderTest = m1 self.registerMap = RegisterMap( self.expectedName, registerMap ) def testNoRegistersEmptyFile( self ) : expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" // someName_m1 is an empty module #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) def testLicenseLines( self ) : expectedText = \ """/* * * Module: m1 * * This is a license text. * There could be some copyright applied. * Or any other distribution limitations. * */ #ifndef SOMENAME_M1_H #define SOMENAME_M1_H #include #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" // someName_m1 is an empty module #endif """ inputLicense = [ 'This is a license text.', 'There could be some copyright applied.', 'Or any other distribution limitations.', ] paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap, licenseTextLines = inputLicense ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) if __name__ == '__main__' : unittest.main() PK&Nn=registerMap/export/c/output/tests/testCRegisterMapTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import unittest.mock from registerMap import RegisterMap as ImportedRegisterMap from registerMap.export.c.elements.memory import Memory from registerMap.export.c.elements.registerMap import RegisterMap from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..registerMap import RegisterMapTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.c.output.registerMap.RegisterMapTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.registerMap.open' HEADER_MODULE_PATH = 'registerMap.export.c.output.registerMap.RegisterMapTemplatesBase' \ '._RegisterMapTemplatesBase__createRegisterMapHeader' SOURCE_MODULE_PATH = 'registerMap.export.c.output.registerMap.RegisterMapTemplatesBase' \ '._RegisterMapTemplatesBase__createRegisterMapSource' class TestCRegisterMapTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.__setupRegisterMap() def __setupRegisterMap( self ) : registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 2) ) r1.addField( 'f2', (3, 4) ) r1.addField( 'f3', (5, 15) ) self.registerMap = RegisterMap(self.expectedName, registerMap) def testInitialCreatedFiles( self ) : paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ), \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/registerMap.h', 'source/path/someName.c', ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) def testHeader( self ) : expectedText = """/* * * someName * * */ #ifndef SOMENAME_H #define SOMENAME_H #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/modules/m1.h" SOMENAME_OPEN_EXTERN_C #pragma pack( 10 ) struct someName_t { struct someName_m1_t volatile* const m1; }; #pragma pack() // Declare the register map instance for users. extern struct someName_MemorySpace_t someName_memory; extern struct someName_t someName; SOMENAME_CLOSE_EXTERN_C #endif """ paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory self.registerMap.memory.alignment = 10 outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH, suppressModulePath = SOURCE_MODULE_PATH ) actualText = ''.join(actualLines) self.assertEqual( expectedText, actualText ) def testSource( self ) : expectedText = """/* * * someName * * */ #include "this/prefix/macro/extern.h" #include "this/prefix/memory/memory.h" #include "this/prefix/registerMap.h" SOMENAME_OPEN_EXTERN_C #ifdef OFF_TARGET_MEMORY struct someName_MemorySpace_t myRegisterMap_memory = { .allocated_memory_span = 2, }; #else struct someName_MemorySpace_t myRegisterMap_memory = { .allocated_memory_span = 2, .base = ( uint8_t volatile* const ) 0x20f0, }; #endif struct someName_t someName = { .m1 = ( someName_m1_t volatile* const )( someName_memory.base + 0x0 ), }; SOMENAME_CLOSE_EXTERN_C """ paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH, suppressModulePath = HEADER_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) if __name__ == '__main__' : unittest.main() PK&N5ֵ&registerMap/export/c/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NdW>ж 1registerMap/export/c/tests/testCArgumentParser.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import argparse import unittest from ..arguments import CArgumentParser class TestCppArgumentParser( unittest.TestCase ) : def setUp( self ) : self.argumentParser = argparse.ArgumentParser() self.languageParsers = self.argumentParser.add_subparsers( dest = 'language', title = 'language' ) self.parserUnderTest = CArgumentParser( self.languageParsers ) def testOutputSpecified( self ) : inputValue = [ 'c', 'some/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( inputValue[ 1 ], actualValue.output ) def testMissingOutputRaises( self ) : inputValue = [ 'c', ] with self.assertRaises( SystemExit ) : self.argumentParser.parse_args( inputValue ) def testPack( self ) : inputValue = [ 'c', 'some/path', '--pack', '2' ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( int( inputValue[ 3 ] ), actualValue.packAlignment ) def testDefaultIncludePath( self ) : inputValue = [ 'c', 'some/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( '', actualValue.includePrefix ) def testIncludePath( self ) : inputValue = [ 'c', 'some/path', '--include-prefix', 'some/include/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( inputValue[ 3 ], actualValue.includePrefix ) if __name__ == '__main__' : unittest.main() PK&NsYi i 4registerMap/export/c/tests/testCRegisterMapOutput.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap import RegisterMap from ..options import COptions from ..registerMap import Output as COutput class TestCRegisterMapHeaderSource( unittest.TestCase ) : def setUp( self ) : self.outputDir = 'some/path' self.__setupRegisterMap() self.mock_options = COptions() self.mock_options.includePrefix = 'this/prefix' self.mock_options.output = self.outputDir self.mock_options.packAlignment = 10 def __setupRegisterMap( self ) : self.registerMap = RegisterMap() self.registerMap.memory.baseAddress = 0x20f0 m1 = self.registerMap.addModule( 'm1' ) r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) m2 = self.registerMap.addModule( 'm2' ) r2 = m2.addRegister( 'r2' ) r2.addField( 'f2', (0, 4) ) m3 = self.registerMap.addModule( 'm3' ) r3 = m3.addRegister( 'r3' ) r3.addField( 'f3', (4, 6) ) def testExecution( self ) : with unittest.mock.patch( 'registerMap.export.c.registerMap.OutputBase._OutputBase__validateOutputDirectory' ), \ unittest.mock.patch( 'registerMap.export.c.registerMap.MacroTemplates' ) as mock_MacroTemplate, \ unittest.mock.patch( 'registerMap.export.c.registerMap.MemoryTemplates' ) as mock_MemoryTemplate, \ unittest.mock.patch( 'registerMap.export.c.registerMap.ModuleTemplates' ) as mock_ModuleTemplate, \ unittest.mock.patch( 'registerMap.export.c.registerMap.RegisterMapTemplates' ) as \ mock_RegisterMapTemplate, \ unittest.mock.patch( 'registerMap.export.c.registerMap.Output._Output__createDirectories' ) : outputUnderTest = COutput( self.mock_options ) # Mock created directory paths outputUnderTest.includePath = 'some/include' outputUnderTest.sourceDirectory = 'some/source' outputUnderTest.generate( self.registerMap, 'myRegisterMap' ) mock_macroTemplateInstance = mock_MacroTemplate.return_value mock_macroTemplateInstance.apply.assert_called_once() mock_memoryTemplateInstance = mock_MemoryTemplate.return_value mock_memoryTemplateInstance.apply.assert_called_once() mock_moduleTemplateInstance = mock_ModuleTemplate.return_value mock_moduleTemplateInstance.apply.assert_called_once() mock_registerMapTemplateInstance = mock_RegisterMapTemplate.return_value mock_registerMapTemplateInstance.apply.assert_called_once() if __name__ == '__main__' : unittest.main() PK&N5ֵ)registerMap/export/commonCppC/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NEjj0registerMap/export/commonCppC/output/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .macro import MacroTemplatesBase from .memory import MemoryTemplatesBase from .module import ModuleTemplatesBase from .registerMap import RegisterMapTemplatesBasePK&N߿__-registerMap/export/commonCppC/output/macro.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import os from registerMap.export.base import \ TemplateBase, \ TemplateInterface class MacroTemplatesBase( TemplateInterface, TemplateBase ) : def __init__( self, paths, configuration, registerMapName, licenseTextLines = None, suffixes = list() ) : paths.templatePackagePath = configuration[ 'template-package' ] super().__init__( paths, licenseTextLines = licenseTextLines, subdir = 'macro', suffixes = suffixes ) self.configuration = configuration self.macroDirectory = os.path.join( self.paths.includeDirectory, 'macro' ) self.registerMapName = registerMapName def apply( self ) : self.createDirectory( self.macroDirectory ) for thisTemplate in self.configuration[ 'files' ] : self.__createHeader( thisTemplate[ 'file' ], thisTemplate[ 'template' ] ) def __createHeader( self, file, template ) : assertHeader = os.path.join( self.macroDirectory, file ) template = self.environment.get_template( template ) with open( assertHeader, 'w' ) as headerFile : text = template.render( registerMapName = self.registerMapName, licenseText = self.licenseTextLines ) headerFile.write( text ) self.createdFiles.append( assertHeader ) PK&No5\ .registerMap/export/commonCppC/output/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import os from registerMap.export.base import \ TemplateBase, \ TemplateInterface class MemoryTemplatesBase( TemplateInterface, TemplateBase ) : def __init__( self, paths, configuration, registerMapName, encapsulatedMemory, licenseTextLines = None, suffixes = list() ) : paths.templatePackagePath = configuration[ 'template-package' ] super().__init__( paths, licenseTextLines = licenseTextLines, subdir = 'idiomatic', suffixes = suffixes ) self.configuration = configuration self.encapsulatedMemory = encapsulatedMemory self.memoryDirectory = os.path.join( self.paths.includeDirectory, 'memory' ) self.registerMapName = registerMapName self.__TEMPLATE_GENERATORS = { 'header' : self.__createHeader, 'source' : self.__createSource, } def apply( self ) : assert self.memoryDirectory is not None self.createDirectory( self.memoryDirectory ) for id, createFileMethod in self.__TEMPLATE_GENERATORS.items() : for thisTemplate in self.configuration[ id ] : createFileMethod( thisTemplate[ 'file' ], thisTemplate[ 'template' ] ) def __createHeader( self, file, template ) : targetSource = os.path.join( self.memoryDirectory, file ) template = self.environment.get_template( template ) with open( targetSource, 'w' ) as sourceFile : text = template.render( licenseText = self.licenseTextLines, memory = self.encapsulatedMemory, prefixPath = self.paths.includePrefix, registerMapName = self.registerMapName ) sourceFile.write( text ) self.createdFiles.append( targetSource ) def __createSource( self, file, template ) : targetSource = os.path.join( self.paths.sourceDirectory, file ) template = self.environment.get_template( template ) with open( targetSource, 'w' ) as sourceFile : text = template.render( licenseText = self.licenseTextLines, memory = self.encapsulatedMemory, prefixPath = self.paths.includePrefix, registerMapName = self.registerMapName ) sourceFile.write( text ) self.createdFiles.append( targetSource ) PK&N6 ^ .registerMap/export/commonCppC/output/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import os from registerMap.export.base import \ TemplateBase, \ TemplateInterface class ModuleTemplatesBase( TemplateInterface, TemplateBase ) : def __init__( self, paths, configuration, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : paths.templatePackagePath = configuration[ 'template-package' ] self.configuration = configuration super().__init__( paths, licenseTextLines = licenseTextLines, subdir = 'idiomatic', suffixes = suffixes ) self.moduleDirectory = None self.encapsulatedRegisterMap = encapsulatedRegisterMap def apply( self ) : self.moduleDirectory = os.path.join( self.paths.includeDirectory, 'modules' ) self.createDirectory( self.moduleDirectory ) moduleElements = self.encapsulatedRegisterMap.modules self.__createModuleFiles( self.encapsulatedRegisterMap.name, self.encapsulatedRegisterMap.memory, moduleElements ) def __createModuleFiles( self, registerMapName, memory, moduleElements ) : template = self.environment.get_template( self.configuration[ 'module-template' ] ) for thisModule in moduleElements : thisModuleFile = os.path.join( self.moduleDirectory, '{0}.{1}'.format( thisModule.name, self.configuration[ 'header-suffix' ] ) ) with open( thisModuleFile, 'w' ) as sourceFile : text = template.render( licenseText = self.licenseTextLines, memory = memory, module = thisModule, prefixPath = self.paths.includePrefix, registerMapMemoryAlignment = self.encapsulatedRegisterMap.memory.alignment, registerMapName = registerMapName ) sourceFile.write( text ) self.createdFiles.append( thisModuleFile ) PK&Ns滦 3registerMap/export/commonCppC/output/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import os from registerMap.export.base import \ TemplateBase, \ TemplateInterface class RegisterMapTemplatesBase( TemplateInterface, TemplateBase ) : def __init__( self, paths, configuration, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, licenseTextLines = licenseTextLines, subdir = 'idiomatic', suffixes = suffixes ) self.configuration = configuration self.encapsulatedRegisterMap = encapsulatedRegisterMap def apply( self ) : self.__createRegisterMapHeader( self.encapsulatedRegisterMap ) self.__createRegisterMapSource( self.encapsulatedRegisterMap, self.encapsulatedRegisterMap.memory ) def __createRegisterMapHeader( self, registerMap ) : registerMapHeader = os.path.join( self.paths.includeDirectory, self.configuration[ 'registermap' ] ) template = self.environment.get_template( self.configuration[ 'header-template' ] ) with open( registerMapHeader, 'w' ) as headerFile : text = template.render( licenseText = self.licenseTextLines, prefixPath = self.paths.includePrefix, registerMap = registerMap ) headerFile.write( text ) self.createdFiles.append( registerMapHeader ) def __createRegisterMapSource( self, registerMap, memory ) : registerMapSource = os.path.join( self.paths.sourceDirectory, '{0}.{1}'.format( registerMap.name, self.configuration[ 'source-suffix' ] ) ) template = self.environment.get_template( self.configuration[ 'source-template' ] ) with open( registerMapSource, 'w' ) as sourceFile : text = template.render( licenseText = self.licenseTextLines, memory = memory, prefixPath = self.paths.includePrefix, registerMap = registerMap ) sourceFile.write( text ) self.createdFiles.append( registerMapSource ) PK&N5ֵ6registerMap/export/commonCppC/output/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N(a`""4registerMap/export/commonCppC/output/tests/common.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import io import unittest.mock class KeepString( io.StringIO ) : """ Retain the lines written to io.StringIO before it is closed (at which point they are discarded). """ def __init__( self, *args, **kwargs ) : super().__init__( *args, **kwargs ) self.outputLines = None def close( self ) : self.seek( 0 ) self.outputLines = self.readlines() super().close() def doTemplateTest( outputUnderTest, openModulePath, createDirectoryModulePath, suppressModulePath = None ) : """ Acquire the output :param outputUnderTest: :param openModulePath: :param createDirectoryModulePath: :param suppressModulePath: """ mock_fileObject = KeepString() with unittest.mock.patch( createDirectoryModulePath, return_value = True ), \ unittest.mock.patch( openModulePath, unittest.mock.mock_open() ) as mock_memoryOpen : mock_memoryOpen.return_value = mock_fileObject if suppressModulePath is None : # apply the output for testing outputUnderTest.apply() else : # mock the module path to be suppresed. with unittest.mock.patch( suppressModulePath ) : outputUnderTest.apply() return mock_fileObject.outputLines PK&N3"  "registerMap/export/cpp/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .arguments import CppArgumentParser from .registerMap import Output PK&NnK#registerMap/export/cpp/arguments.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from ..base.interface import LanguageParser from .options import CppOptions from .registerMap import Output class CppArgumentParser( LanguageParser ) : def __init__( self, parentParser ) : self.parser = parentParser.add_parser( 'c++' ) self.parser.add_argument( 'output', help = 'Directory to place the generated files. Created if not present.' ) self.parser.add_argument( '--pack', default = None, help = 'Pragma pack alignment value. Default None.', nargs = 1, type = int ) self.parser.add_argument( '--include-prefix', default = [ '' ], help = 'Prefix path to register map include files. Default None.', nargs = 1, type = str ) def acquireOptions( self, parserProcessedArguments ) : options = CppOptions() options.generator = Output options.output = parserProcessedArguments.output if parserProcessedArguments.pack is not None : options.packAlignment = parserProcessedArguments.pack[ 0 ] else : options.packAlignment = None if parserProcessedArguments.include_prefix is not None : options.includePrefix = parserProcessedArguments.include_prefix[ 0 ] else : options.includePrefix = None return options PK&Nt=oo!registerMap/export/cpp/options.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # class CppOptions : def __init__( self ) : self.generator = None self.includePrefix = None self.output = None self.packAlignment = None PK&N‚RR%registerMap/export/cpp/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import os from ..base import \ OutputBase from .elements import \ Memory, \ RegisterMap from .output import \ MacroTemplates, \ MemoryTemplates, \ ModuleTemplates, \ RegisterMapTemplates log = logging.getLogger( __name__ ) class Output( OutputBase ) : """ Export a C source code representation of the register map. """ def __init__( self, outputOptions, licenseTextLines = list() ) : super().__init__( outputOptions, licenseTextLines = licenseTextLines ) self.includePath = None self.sourceDirectory = None self.suffixes = [ '.hpp', '.cpp' ] def __createDirectories( self, registerMapName ) : self.includePath = os.path.join( self.outputDirectory, 'include', self.outputOptions.includePrefix, registerMapName ) self.createDirectory( self.includePath ) self.sourceDirectory = os.path.join( self.outputDirectory, 'source', registerMapName ) self.createDirectory( self.sourceDirectory ) def generate( self, registerMap, registerMapName ) : """ Export the register map representation. :param registerMap: A RegisterMap instance for export. :param registerMapName: A public name for the register map used in source code file structure and object names. """ self.__createDirectories( registerMapName ) encapsulatedRegisterMap = RegisterMap( registerMapName, registerMap ) encapsulatedRegisterMap.memory.alignment = self.outputOptions.packAlignment paths = MacroTemplates.Paths() paths.includeDirectory = self.includePath paths.includePrefix = os.path.join( self.outputOptions.includePrefix, registerMapName ) paths.sourceDirectory = self.sourceDirectory buildOrder = [ MacroTemplates( paths, registerMapName, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), MemoryTemplates( paths, registerMapName, encapsulatedRegisterMap.memory, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), ModuleTemplates( paths, encapsulatedRegisterMap, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), RegisterMapTemplates( paths, encapsulatedRegisterMap, licenseTextLines = self.licenseTextLines, suffixes = self.suffixes ), ] for build in buildOrder : build.apply() PK&NaVV+registerMap/export/cpp/elements/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .field import Field from .memory import Memory from .module import Module from .register import Register from .registerMap import RegisterMap PK&N5##(registerMap/export/cpp/elements/field.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import FieldBase class Field( FieldBase ) : __knownTypes = { 8 : 'std::uint8_t', 16 : 'std::uint16_t', 32 : 'std::uint32_t', 64 : 'std::uint64_t', } def __init__( self, fieldElement ) : super().__init__( fieldElement ) @property def type( self ) : assert self._element[ 'size' ] <= max( [ x for x in self.__knownTypes.keys() ] ) leastSize = min( [ x for x in self.__knownTypes.keys() if x >= self._element[ 'size' ] ] ) thisType = self.__knownTypes[ leastSize ] return thisType PK&N=Iqq)registerMap/export/cpp/elements/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import MemoryBase class Memory( MemoryBase ) : __knownTypes = { 8 : 'std::uint_least8_t', 16 : 'std::uint_least16_t', 32 : 'std::uint_least32_t', 64 : 'std::uint_least64_t', } def __init__( self, memoryElement, memorySize ) : super().__init__( memoryElement, memorySize ) self.alignment = '' @property def sizeType( self ) : assert self.memoryUnitBits <= max( [ x for x in self.__knownTypes.keys() ] ) leastSize = min( [ x for x in self.__knownTypes.keys() if x >= self.memoryUnitBits ] ) thisType = self.__knownTypes[ leastSize ] return thisType PK&Nigg)registerMap/export/cpp/elements/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import ModuleBase from .field import Field from .register import Register class Module( ModuleBase ) : def __init__( self, moduleElement, RegisterType, FieldType ) : super().__init__( moduleElement, RegisterType, FieldType ) @property def address( self ) : """ The absolute base address of the module formatted for C++, in hexadecimal. """ return hex( self._element.baseAddress ) @property def offset( self ) : """ The offset of the module formated for C++, relative to the base address of the register map. """ return hex( self._element.offset ) PK&N{+registerMap/export/cpp/elements/register.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import RegisterContiguousFieldIntervals as Register PK&Nc.registerMap/export/cpp/elements/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.base import \ RegisterMapBase from .field import Field from .memory import Memory from .module import Module from .register import Register CPP_TYPE_CONFIGURATION = { 'field' : Field, 'memory' : Memory, 'module' : Module, 'register' : Register, } class RegisterMap( RegisterMapBase ) : def __init__( self, registerMapName, registerMap ) : super().__init__( registerMapName, registerMap, CPP_TYPE_CONFIGURATION ) PK&N5ֵ1registerMap/export/cpp/elements/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nk5registerMap/export/cpp/elements/tests/testCppField.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..field import Field class TestCppExportField( unittest.TestCase ) : def setUp( self ) : self.mockFieldElement = { 'size' : 0, } self.fieldUnderTest = Field( self.mockFieldElement ) def testValidTypes( self ) : expectedValues = [ { 'size' : 8, 'type' : 'std::uint8_t', }, { 'size' : 9, 'type' : 'std::uint16_t', }, { 'size' : 16, 'type' : 'std::uint16_t', }, { 'size' : 17, 'type' : 'std::uint32_t', }, { 'size' : 32, 'type' : 'std::uint32_t', }, { 'size' : 33, 'type' : 'std::uint64_t', }, { 'size' : 64, 'type' : 'std::uint64_t', }, ] for thisValue in expectedValues : self.mockFieldElement[ 'size' ] = thisValue[ 'size' ] self.assertEqual( thisValue[ 'type' ], self.fieldUnderTest.type ) def testTypeGreaterThan64Asserts( self ) : # Assume that 64 bit is the maximum field size type allowed. self.mockFieldElement[ 'size' ] = 65 with self.assertRaises( AssertionError ) : self.fieldUnderTest.type if __name__ == '__main__' : unittest.main() PK&Nvv6registerMap/export/cpp/elements/tests/testCppMemory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.memory.configuration import MemoryConfiguration from ..memory import Memory as CppMemory class TestCppMemory( unittest.TestCase ) : def setUp( self ) : self.memorySpace = MemoryConfiguration() self.memorySize = 10 self.memoryUnderTest = CppMemory( self.memorySpace, self.memorySize ) def testDefaultAlignmentProperty( self ) : self.assertEqual( '', self.memoryUnderTest.alignment ) def testSizeTypeProperty( self ) : self.memorySpace.memoryUnitBits = 32 self.assertEqual( 'std::uint_least32_t', self.memoryUnderTest.sizeType ) if __name__ == '__main__' : unittest.main() PK&NjK[[)registerMap/export/cpp/output/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .macro import MacroTemplates from .memory import MemoryTemplates from .module import ModuleTemplates from .registerMap import RegisterMapTemplates PK&N[u*%registerMap/export/cpp/output/base.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # CPP_TEMPLATE_PACKAGE = 'registerMap.export.cpp.output' PK&N3$tt&registerMap/export/cpp/output/macro.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import MacroTemplatesBase from .base import CPP_TEMPLATE_PACKAGE MACRO_TEMPLATE_CONFIGURATION = { 'files' : [ { 'file' : 'assert.hpp', 'template' : 'assert_template.hpp', }, ], 'template-package' : CPP_TEMPLATE_PACKAGE, } class MacroTemplates( MacroTemplatesBase ) : def __init__( self, paths, registerMapName, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MACRO_TEMPLATE_CONFIGURATION, registerMapName, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&N""'registerMap/export/cpp/output/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import MemoryTemplatesBase from .base import CPP_TEMPLATE_PACKAGE MEMORY_TEMPLATE_CONFIGURATION = { 'header' : [ { 'file' : 'memory.hpp', 'template' : 'memory_template.hpp', }, ], 'source' : [ { 'file' : 'memory.cpp', 'template' : 'memory_template.cpp', }, ], 'template-package' : CPP_TEMPLATE_PACKAGE, } class MemoryTemplates( MemoryTemplatesBase ) : def __init__( self, paths, registerMapName, encapsulatedMemory, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MEMORY_TEMPLATE_CONFIGURATION, registerMapName, encapsulatedMemory, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&N$/'registerMap/export/cpp/output/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import ModuleTemplatesBase from ..elements import \ Field, \ Module, \ Register from .base import CPP_TEMPLATE_PACKAGE MODULE_TEMPLATE_CONFIGURATION = { 'module-template' : 'module_template.hpp', 'header-suffix' : 'hpp', 'template-package' : CPP_TEMPLATE_PACKAGE, 'field-type' : Field, 'module-type' : Module, 'register-type' : Register, } class ModuleTemplates( ModuleTemplatesBase ) : def __init__( self, paths, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : super().__init__( paths, MODULE_TEMPLATE_CONFIGURATION, encapsulatedRegisterMap, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&NQ;ww,registerMap/export/cpp/output/registerMap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.export.commonCppC.output import RegisterMapTemplatesBase from ..elements import RegisterMap from .base import CPP_TEMPLATE_PACKAGE REGISTERMAP_TEMPLATE_CONFIGURATION = { 'registermap' : 'registerMap.hpp', 'header-template' : 'registerMap_template.hpp', 'source-template' : 'registerMap_template.cpp', 'source-suffix' : 'cpp', 'registermap-type' : RegisterMap, 'template-package' : CPP_TEMPLATE_PACKAGE, } class RegisterMapTemplates( RegisterMapTemplatesBase ) : def __init__( self, paths, encapsulatedRegisterMap, licenseTextLines = None, suffixes = list() ) : paths.templatePackagePath = REGISTERMAP_TEMPLATE_CONFIGURATION[ 'template-package' ] super().__init__( paths, REGISTERMAP_TEMPLATE_CONFIGURATION, encapsulatedRegisterMap, licenseTextLines = licenseTextLines, suffixes = suffixes ) PK&NtEregisterMap/export/cpp/output/templates/idiomatic/memory_template.cpp/* * * {{ registerMapName }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #include #include "{{ prefixPath }}/memory/memory.hpp" {% set memoryPointerType = memory.sizeType~' volatile* const' -%} namespace {{ registerMapName }} { #ifndef OFF_TARGET_MEMORY {{ memoryPointerType }} MemorySpace::base = reinterpret_cast<{{ memoryPointerType }}>( {{ memory.baseAddress }} ); #else constexpr std::uint_least32_t MemorySpace::allocated_memory_span; {{ memory.sizeType }} volatile MemorySpace::off_target_memory[]; {{ memoryPointerType }} MemorySpace::base = MemorySpace::off_target_memory; #endif } PK&N EregisterMap/export/cpp/output/templates/idiomatic/memory_template.hpp/* * * {{ registerMapName }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_MEMORY_HPP #define {{ registerMapName|upper }}_MEMORY_HPP #include namespace {{ registerMapName }} { {% set memoryPointerType = memory.sizeType~' volatile* const' -%} class MemorySpace { public: static {{ memoryPointerType }} base; #ifdef OFF_TARGET_MEMORY static constexpr std::uint_least32_t allocated_memory_span = {{ memory.size }}; static {{ memory.sizeType }} volatile off_target_memory[ allocated_memory_span ]; #endif }; } #endif PK&NEregisterMap/export/cpp/output/templates/idiomatic/module_template.hpp/* * * Module: {{ module.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_{{ module.name|upper }}_HPP #define {{ registerMapName|upper }}_{{ module.name|upper }}_HPP #include #include "{{ prefixPath }}/memory/memory.hpp" {% if module.registers|count != 0 %} namespace {{ registerMapName }} { namespace {{ module.name }} { {%- for thisRegister in module.registers %} class {{ thisRegister.name }}_t { public: {%- for bitField in thisRegister.fields %} {{ bitField.type }} volatile {{ bitField.name }}:{{ bitField.size }}; {%- endfor %} }; {%- endfor %} } #pragma pack( {{ registerMapMemoryAlignment }} ) class {{ module.name }}_t { public: {% for thisRegister in module.registers %} {%- if thisRegister.precedingGapBytes != 0 %} uint8_t gap_{{ thisRegister.name }}[{{ thisRegister.precedingGapBytes }}]; {%- endif %} {{ module.name }}::{{ thisRegister.name }}_t volatile {{ thisRegister.name }}; {%- endfor %} }; #pragma pack() } {% else %} // {{ registerMapName }}::{{ module.name }} is an empty module {%- endif %} #endif PK&N>!!JregisterMap/export/cpp/output/templates/idiomatic/registerMap_template.cpp/* * * {{ registerMap.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #include "{{ prefixPath }}/registerMap.hpp" namespace {{ registerMap.name }} { {{ registerMap.name }}_t {{ registerMap.name }}; } PK&N{M+JregisterMap/export/cpp/output/templates/idiomatic/registerMap_template.hpp/* * * {{ registerMap.name }} * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMap.name|upper }}_HPP #define {{ registerMap.name|upper }}_HPP {% for thisModule in registerMap.modules -%} #include "{{ prefixPath }}/modules/{{ thisModule.name }}.hpp" {% endfor %} {% set registerMapType = registerMap.name~'_t' -%} namespace {{ registerMap.name }} { {%- if registerMap.modules|count != 0 %} #pragma pack( {{ registerMap.memory.alignment }} ) class {{ registerMapType }} { public: MemorySpace memory; {{ registerMapType }}() : {%- for thisModule in registerMap.modules %} {%- set pointerType = thisModule.name~'_t volatile* const' %} {{ thisModule.name }}( reinterpret_cast<{{ pointerType }}>( memory.base + {{ thisModule.offset }} ) ){{ "," if not loop.last }} {%- endfor %} {}; {% for thisModule in registerMap.modules %} {%- set pointerType = thisModule.name~'_t volatile* const' %} {{ pointerType }} {{ thisModule.name }}; {%- endfor %} }; #pragma pack() // Declare the register map instance for users. extern {{ registerMap.name }}_t {{ registerMap.name }}; {%- endif %} } #endif PK&N4bFFAregisterMap/export/cpp/output/templates/macro/assert_template.hpp/* * {%- if licenseText is not none %} {%- for line in licenseText %} * {{ line }} {%- endfor %} {%- endif %} * */ #ifndef {{ registerMapName|upper }}_ASSERT_HPP #define {{ registerMapName|upper }}_ASSERT_HPP #ifndef DISABLE_RUNTIME_ASSERT #include #define RUNTIME_ASSERT(expression) \ assert(expression) #else #define RUNTIME_ASSERT() #endif #ifndef DISABLE_COMPILETIME_ASSERT #define COMPILETIME_ASSERT(expression) \ #if !(expression) \ #error "ASSERTION FAILED: " #expression \ #endif #else #define COMPILETIME_ASSERT(expression) #endif #endif PK&N5ֵ/registerMap/export/cpp/output/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N\_ OKK;registerMap/export/cpp/output/tests/testCppMacroTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import copy import jinja2 import os import unittest.mock from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..macro import \ MACRO_TEMPLATE_CONFIGURATION, \ MacroTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.cpp.output.macro.MacroTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.macro.open' class TestMacroTemplate( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' def testDefaults( self ) : expectedMacroDirectory = os.path.join( self.includeDirectory, 'macro' ) expectedTemplateDirectory = os.path.join( 'templates', 'macro' ) paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) self.assertEqual( self.expectedName, outputUnderTest.registerMapName ) self.assertEqual( expectedTemplateDirectory, outputUnderTest.templateDirectory ) self.assertEqual( expectedMacroDirectory, outputUnderTest.macroDirectory ) def testInitialCreatedFiles( self ) : paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/macro/assert.hpp', ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) mock_template.render.assert_has_calls( [ unittest.mock.call( registerMapName = self.expectedName, licenseText = None ), ] ) mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.macroDirectory ), ] ) class TestAssertMacroTemplate( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.templateConfig = copy.deepcopy( MACRO_TEMPLATE_CONFIGURATION ) self.templateConfig[ 'files' ] = [ self.templateConfig[ 'files' ][ 0 ] ] def testAssertMacroOutput( self ) : paths = MacroTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MacroTemplates( paths, self.expectedName ) outputUnderTest.configuration = self.templateConfig actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_ASSERT_HPP\n', '#define SOMENAME_ASSERT_HPP\n', '\n', '\n', '#ifndef DISABLE_RUNTIME_ASSERT\n', '\n', '#include \n', '#define RUNTIME_ASSERT(expression) \\\n', ' assert(expression)\n', '\n', '#else\n', '\n', '#define RUNTIME_ASSERT()\n', '\n', '#endif\n', '\n', '\n', '#ifndef DISABLE_COMPILETIME_ASSERT\n', '\n', '#define COMPILETIME_ASSERT(expression) \\\n', '#if !(expression) \\\n', '#error "ASSERTION FAILED: " #expression \\\n', '#endif\n', '\n', '#else\n', '\n', '#define COMPILETIME_ASSERT(expression)\n', '\n', '#endif\n', '\n', '\n', '#endif\n' ] self.assertEqual( expectedLines, actualLines ) if __name__ == '__main__' : unittest.main() PK&N(5O<registerMap/export/cpp/output/tests/testCppMemoryTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import copy import jinja2 import os import unittest.mock from registerMap.export.cpp.elements import Memory from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..memory import \ MEMORY_TEMPLATE_CONFIGURATION, \ MemoryTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.cpp.output.memory.MemoryTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.memory.open' class TestMemoryTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.mock_Memory = unittest.mock.create_autospec( Memory ) self.mock_Memory.baseAddress = 1234 self.mock_Memory.size = 345 self.mock_Memory.sizeType = 'uint_least8_t' self.templateConfig = copy.deepcopy( MEMORY_TEMPLATE_CONFIGURATION ) def testDefaults( self ) : expectedMemoryDirectory = os.path.join( self.includeDirectory, 'memory' ) expectedTemplateDirectory = os.path.join( 'templates', 'idiomatic' ) paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) self.assertEqual( self.expectedName, outputUnderTest.registerMapName ) self.assertEqual( expectedTemplateDirectory, outputUnderTest.templateDirectory ) self.assertEqual( expectedMemoryDirectory, outputUnderTest.memoryDirectory ) self.assertEqual( self.mock_Memory, outputUnderTest.encapsulatedMemory ) def testInitialCreatedFiles( self ) : paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/memory/memory.hpp', 'source/path/memory.cpp', ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) self.assertEqual( 2, len( mock_template.render.mock_calls ) ) mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.memoryDirectory ), ] ) def testMemoryHeader( self ) : paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) # Select the header to test self.templateConfig[ 'header' ] = [ self.templateConfig[ 'header' ][ 0 ] ] self.templateConfig[ 'source' ] = list() outputUnderTest.configuration = self.templateConfig actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' * someName\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_MEMORY_HPP\n', '#define SOMENAME_MEMORY_HPP\n', '\n', '#include \n', '\n', '\n', 'namespace someName\n', '{\n', '\n', 'class MemorySpace\n', ' {\n', ' public:\n', '\n', ' static uint_least8_t volatile* const\n', ' base;\n', '\n', '#ifdef OFF_TARGET_MEMORY\n', '\n', ' static constexpr std::uint_least32_t\n', ' allocated_memory_span = 345;\n', '\n', ' static uint_least8_t volatile\n', ' off_target_memory[ allocated_memory_span ];\n', '\n', '#endif\n', '\n', ' };\n', '\n', '}\n', '\n', '#endif\n' ] self.assertEqual( expectedLines, actualLines ) def testMemorySource( self ) : paths = MemoryTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory outputUnderTest = MemoryTemplates( paths, self.expectedName, self.mock_Memory ) # Select the source to test self.templateConfig[ 'header' ] = list() self.templateConfig[ 'source' ] = [ self.templateConfig[ 'source' ][ 0 ] ] outputUnderTest.configuration = self.templateConfig actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) expectedLines = [ '/*\n', ' *\n', ' * someName\n', ' *\n', ' *\n', ' */\n', '\n', '#include \n', '\n', '#include "this/prefix/memory/memory.hpp"\n', '\n', '\n', 'namespace someName\n', '{\n', '\n', '#ifndef OFF_TARGET_MEMORY\n', '\n', ' uint_least8_t volatile* const\n', " MemorySpace::base = reinterpret_cast( 1234 );\n", '\n', '#else\n', '\n', ' constexpr std::uint_least32_t\n', ' MemorySpace::allocated_memory_span;\n', '\n', ' uint_least8_t volatile\n', ' MemorySpace::off_target_memory[];\n', '\n', ' uint_least8_t volatile* const\n', ' MemorySpace::base = MemorySpace::off_target_memory;\n', '\n', '#endif\n', '\n', '}\n' ] expectedText = ''.join( expectedLines ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) if __name__ == '__main__' : unittest.main() PK&N,,<registerMap/export/cpp/output/tests/testCppModuleTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import unittest.mock from registerMap import RegisterMap as ImportedRegisterMap from registerMap.export.cpp.elements.memory import Memory from registerMap.export.cpp.elements.registerMap import RegisterMap from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..module import ModuleTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.cpp.output.module.ModuleTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.module.open' class TestModuleTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.__setupRegisterMap() self.memory = Memory( self.registerMap.memory, self.registerMap.spanMemoryUnits ) def __setupRegisterMap( self ) : registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 2) ) r1.addField( 'f2', (3, 4) ) r1.addField( 'f3', (5, 15) ) self.registerMap = RegisterMap( self.expectedName, registerMap ) def testInitialCreatedFiles( self ) : paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ) as mock_createDirectory, \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/modules/m1.hpp' ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) mock_template.render.assert_called_once() mock_createDirectory.assert_has_calls( [ unittest.mock.call( outputUnderTest.moduleDirectory ), ] ) def testContiguousFieldsRegisterData( self ) : expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" namespace someName { namespace m1 { class r1_t { public: std::uint8_t volatile f1:3; std::uint8_t volatile f2:2; std::uint16_t volatile f3:11; }; } #pragma pack( ) class m1_t { public: m1::r1_t volatile r1; }; #pragma pack() } #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = '{}'.format( ''.join( actualLines ) ) self.assertEqual( expectedText, actualText ) class TestNoncontiguousRegisterOutput( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) self.registerMap = RegisterMap( self.expectedName, registerMap ) self.memory = Memory( self.registerMap.memory, self.registerMap.spanMemoryUnits ) def testNoncontiguousFieldsSingleByteRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 1) ) r1.addField( 'f2', (4, 5) ) r1.addField( 'f3', (7, 7) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" namespace someName { namespace m1 { class r1_t { public: std::uint8_t volatile f1:2; std::uint8_t volatile :2; std::uint8_t volatile f2:2; std::uint8_t volatile :1; std::uint8_t volatile f3:1; }; } #pragma pack( ) class m1_t { public: m1::r1_t volatile r1; }; #pragma pack() } #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) def testNoncontiguousFieldsStartsRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (2, 4) ) r1.addField( 'f2', (5, 5) ) r1.addField( 'f3', (7, 7) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" namespace someName { namespace m1 { class r1_t { public: std::uint8_t volatile :2; std::uint8_t volatile f1:3; std::uint8_t volatile f2:1; std::uint8_t volatile :1; std::uint8_t volatile f3:1; }; } #pragma pack( ) class m1_t { public: m1::r1_t volatile r1; }; #pragma pack() } #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) self.assertEqual( expectedText.splitlines( keepends = True ), actualLines ) def testNoncontiguousFieldsMultiByteRegisterData( self ) : r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 1) ) r1.addField( 'f2', (4, 5) ) r1.addField( 'f3', (7, 9) ) expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" namespace someName { namespace m1 { class r1_t { public: std::uint8_t volatile f1:2; std::uint8_t volatile :2; std::uint8_t volatile f2:2; std::uint8_t volatile :1; std::uint8_t volatile f3:3; std::uint8_t volatile :6; }; } #pragma pack( ) class m1_t { public: m1::r1_t volatile r1; }; #pragma pack() } #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) class TestEmptyModuleOutput( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 m1 = registerMap.addModule( 'm1' ) self.moduleUnderTest = m1 self.registerMap = RegisterMap( self.expectedName, registerMap ) def testNoRegistersEmptyFile( self ) : expectedText = \ """/* * * Module: m1 * * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" // someName::m1 is an empty module #endif """ paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) def testLicenseLines( self ) : expectedText = \ """/* * * Module: m1 * * This is a license text. * There could be some copyright applied. * Or any other distribution limitations. * */ #ifndef SOMENAME_M1_HPP #define SOMENAME_M1_HPP #include #include "this/prefix/memory/memory.hpp" // someName::m1 is an empty module #endif """ inputLicense = [ 'This is a license text.', 'There could be some copyright applied.', 'Or any other distribution limitations.', ] paths = ModuleTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.includeDirectory outputUnderTest = ModuleTemplates( paths, self.registerMap, licenseTextLines = inputLicense ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) if __name__ == '__main__' : unittest.main() PK&NN7R00AregisterMap/export/cpp/output/tests/testCppRegisterMapTemplate.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import jinja2 import unittest.mock from registerMap import RegisterMap as ImportedRegisterMap from registerMap.export.c.elements.memory import Memory from registerMap.export.c.elements.registerMap import RegisterMap from registerMap.export.commonCppC.output.tests.common import doTemplateTest from ..registerMap import RegisterMapTemplates import registerMap.export.base.template CREATE_DIRECTORY_MODULE_PATH = 'registerMap.export.cpp.output.registerMap.RegisterMapTemplates.createDirectory' OPEN_MODULE_PATH = 'registerMap.export.commonCppC.output.registerMap.open' HEADER_MODULE_PATH = 'registerMap.export.cpp.output.registerMap.RegisterMapTemplatesBase' \ '._RegisterMapTemplatesBase__createRegisterMapHeader' SOURCE_MODULE_PATH = 'registerMap.export.cpp.output.registerMap.RegisterMapTemplatesBase' \ '._RegisterMapTemplatesBase__createRegisterMapSource' class TestRegisterMapTemplates( unittest.TestCase ) : def setUp( self ) : self.expectedName = 'someName' self.includeDirectory = 'include/path' self.sourceDirectory = 'source/path' self.__setupRegisterMap() def __setupRegisterMap( self ) : registerMap = ImportedRegisterMap() registerMap.memory.baseAddress = 0x20f0 self.m1 = registerMap.addModule( 'm1' ) r1 = self.m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 2) ) r1.addField( 'f2', (3, 4) ) r1.addField( 'f3', (5, 15) ) self.registerMap = RegisterMap( self.expectedName, registerMap ) def testInitialCreatedFiles( self ) : paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.sourceDirectory = self.sourceDirectory outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) mock_template = unittest.mock.create_autospec( jinja2.Template ) with unittest.mock.patch( CREATE_DIRECTORY_MODULE_PATH, return_value = True ), \ unittest.mock.patch( OPEN_MODULE_PATH ), \ unittest.mock.patch.object( registerMap.export.base.template.jinja2.Environment, 'get_template', return_value = mock_template ) : outputUnderTest.apply() expectedFiles = [ 'include/path/registerMap.hpp', 'source/path/someName.cpp', ] self.assertEqual( expectedFiles, outputUnderTest.createdFiles ) def testHeader( self ) : expectedLines = [ '/*\n', ' *\n', ' * someName\n', ' *\n', ' *\n', ' */\n', '\n', '#ifndef SOMENAME_HPP\n', '#define SOMENAME_HPP\n', '\n', '#include "this/prefix/modules/m1.hpp"\n', '\n', '\n', 'namespace someName\n', '{\n', '\n', '#pragma pack( 10 )\n', '\n', ' class someName_t\n', ' {\n', ' public:\n', ' MemorySpace memory;\n', '\n', ' someName_t() :\n', ' m1( reinterpret_cast( memory.base + 0x0 ) )\n', ' {};\n', '\n', ' m1_t volatile* const m1;\n', ' };\n', '\n', '#pragma pack()\n', '\n', '\n', ' // Declare the register map instance for users.\n', ' extern someName_t someName;\n', '\n', '}\n', '\n', '#endif' '\n', ] paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory self.registerMap.memory.alignment = 10 outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH, suppressModulePath = SOURCE_MODULE_PATH ) expectedText = ''.join( expectedLines ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) def testSource( self ) : expectedText = """/* * * someName * * */ #include "this/prefix/registerMap.hpp" namespace someName { someName_t someName; } """ paths = RegisterMapTemplates.Paths() paths.includeDirectory = self.includeDirectory paths.includePrefix = 'this/prefix' paths.sourceDirectory = self.sourceDirectory outputUnderTest = RegisterMapTemplates( paths, self.registerMap ) actualLines = doTemplateTest( outputUnderTest, OPEN_MODULE_PATH, CREATE_DIRECTORY_MODULE_PATH, suppressModulePath = HEADER_MODULE_PATH ) actualText = ''.join( actualLines ) self.assertEqual( expectedText, actualText ) if __name__ == '__main__' : unittest.main() PK&N5ֵ(registerMap/export/cpp/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nc5 5registerMap/export/cpp/tests/testCppArgumentParser.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import argparse import unittest from ..arguments import CppArgumentParser class TestCppArgumentParser( unittest.TestCase ) : def setUp( self ) : self.argumentParser = argparse.ArgumentParser() self.languageParsers = self.argumentParser.add_subparsers( dest = 'language', title = 'language' ) self.parserUnderTest = CppArgumentParser( self.languageParsers ) def testOutputSpecified( self ) : inputValue = [ 'c++', 'some/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( inputValue[ 1 ], actualValue.output ) def testMissingOutputRaises( self ) : inputValue = [ 'c++', ] with self.assertRaises( SystemExit ) : self.argumentParser.parse_args( inputValue ) def testPack( self ) : inputValue = [ 'c++', 'some/path', '--pack', '2' ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( int( inputValue[ 3 ] ), actualValue.packAlignment ) def testDefaultIncludePath( self ) : inputValue = [ 'c++', 'some/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( '', actualValue.includePrefix ) def testIncludePath( self ) : inputValue = [ 'c++', 'some/path', '--include-prefix', 'some/include/path', ] args = self.argumentParser.parse_args( inputValue ) actualValue = self.parserUnderTest.acquireOptions( args ) self.assertEqual( inputValue[ 3 ], actualValue.includePrefix ) if __name__ == '__main__' : unittest.main() PK&N; 8registerMap/export/cpp/tests/testCppRegisterMapOutput.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap import RegisterMap from ..options import CppOptions from ..registerMap import Output as CppOutput BASE_MODULE_PATH = 'registerMap.export.cpp.registerMap' class TestCRegisterMapHeaderSource( unittest.TestCase ) : def setUp( self ) : self.outputDir = 'some/path' self.__setupRegisterMap() self.mock_options = CppOptions() self.mock_options.includePrefix = 'this/prefix' self.mock_options.output = self.outputDir self.mock_options.packAlignment = 10 def __setupRegisterMap( self ) : self.registerMap = RegisterMap() self.registerMap.memory.baseAddress = 0x20f0 m1 = self.registerMap.addModule( 'm1' ) r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) m2 = self.registerMap.addModule( 'm2' ) r2 = m2.addRegister( 'r2' ) r2.addField( 'f2', (0, 4) ) m3 = self.registerMap.addModule( 'm3' ) r3 = m3.addRegister( 'r3' ) r3.addField( 'f3', (4, 6) ) def testExecution( self ) : with unittest.mock.patch( '{0}.OutputBase._OutputBase__validateOutputDirectory'.format( BASE_MODULE_PATH ) ), \ unittest.mock.patch( 'registerMap.export.cpp.registerMap.MacroTemplates'.format( BASE_MODULE_PATH ) ) as \ mock_MacroTemplate, \ unittest.mock.patch( '{0}.MemoryTemplates'.format( BASE_MODULE_PATH ) ) as mock_MemoryTemplate, \ unittest.mock.patch( '{0}.ModuleTemplates'.format( BASE_MODULE_PATH ) ) as mock_ModuleTemplate, \ unittest.mock.patch( '{0}.RegisterMapTemplates'.format( BASE_MODULE_PATH ) ) as \ mock_RegisterMapTemplate, \ unittest.mock.patch( '{0}.Output._Output__createDirectories'.format( BASE_MODULE_PATH ) ) : outputUnderTest = CppOutput( self.mock_options ) # Mock created directory paths outputUnderTest.includePath = 'some/include' outputUnderTest.sourceDirectory = 'some/source' outputUnderTest.generate( self.registerMap, 'myRegisterMap' ) mock_macroTemplateInstance = mock_MacroTemplate.return_value mock_macroTemplateInstance.apply.assert_called_once() mock_memoryTemplateInstance = mock_MemoryTemplate.return_value mock_memoryTemplateInstance.apply.assert_called_once() mock_moduleTemplateInstance = mock_ModuleTemplate.return_value mock_moduleTemplateInstance.apply.assert_called_once() mock_registerMapTemplateInstance = mock_RegisterMapTemplate.return_value mock_registerMapTemplateInstance.apply.assert_called_once() if __name__ == '__main__' : unittest.main() PK&N!registerMap/export/io/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nu&registerMap/export/io/yaml/__init__.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from .abstract import Export, ImportPK&Nqi&registerMap/export/io/yaml/abstract.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class Import( metaclass = abc.ABCMeta ) : @classmethod @abc.abstractmethod def from_yamlData( cls, yamlData ) : ''' Use yamlData to initialize the object. :param yamlData: YAML data loaded using yaml.load :return: Created instance of class. ''' return class Export( metaclass = abc.ABCMeta ) : @abc.abstractmethod def to_yamlData( self ) : ''' Create the YAML data structure to be used by yaml.dump for YAML export. :return: YAML data structure ''' return PK&NN=$registerMap/export/io/yaml/stream.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import yaml def load( filename ) : data = None with open( filename, 'r' ) as yamlFile : data = yaml.load( yamlFile ) assert (data is not None) return data def save( filename, data ) : with open( filename, 'w' ) as yamlFile : yaml.dump( data, yamlFile ) PK&N1registerMap/export/io/yaml/parameters/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N</registerMap/export/io/yaml/parameters/encode.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import yaml def parameter( parameterName, value ) : """ Encode a simple parameter for yaml data. :param parameterName: Name of yaml parameter. :param value: Parameter value in a format suitable for output to yaml. :return: Yaml data structure. """ return { parameterName : value } # From http://stackoverflow.com/questions/18666816/using-python-to-dump-hexidecimals-into-yaml class HexInt( int ) : pass def hexIntRepresenter( dumper, data ) : return yaml.ScalarNode( 'tag:yaml.org,2002:int', hex( data ) ) yaml.add_representer( HexInt, hexIntRepresenter ) PK&N.registerMap/export/io/yaml/parameters/parse.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging from registerMap.exceptions import ParseError log = logging.getLogger( __name__ ) def booleanParameter( yamlData, keyName, recordValue, optional = False ) : value = None goodResult = True if keyName in yamlData : value = bool( yamlData[ keyName ] ) recordValue( value ) elif optional : log.debug( 'Yaml data does not specify an optional ' + keyName ) goodResult = False else : raise ParseError( 'Yaml data does not specify a ' + keyName + '. ' + repr( yamlData ) ) return goodResult def stringParameter( yamlData, keyName, recordValue, optional = False ) : value = None goodResult = True if keyName in yamlData : value = str( yamlData[ keyName ] ) recordValue( value ) elif optional : log.debug( 'Yaml data does not specify an optional ' + keyName ) goodResult = False else : raise ParseError( 'Yaml data does not specify a ' + keyName + '. ' + repr( yamlData ) ) return goodResult def integerParameter( yamlData, keyName, recordValue, optional = False, noneValid = False, useName = False ) : """ Parse yaml data for an integer value. :param yamlData: Source yaml data. :param keyName: Parameter name. :param recordValue: Function to record the parameter value. :param optional: The parameter is optional, so no error state if parameter is not present. :param noneValid: The parameter value can be None. :return: Error state of parameter parsing. """ value = None goodResult = True if keyName in yamlData : try : value = int( yamlData[ keyName ] ) if useName : recordValue( keyName, value ) else : recordValue( value ) except ValueError : log.error( 'Yaml parameter ' + keyName + ' must be an integer. ' + repr( yamlData ) ) goodResult = False except TypeError as e : if 'NoneType' not in str( e ) : log.error( 'Yaml parameer ' + keyName + ' must be an integer. ' + repr( yamlData ) ) goodResult = False elif not noneValid : # Report an error for None value. log.error( 'Yaml parameer ' + keyName + ' must be an integer. ' + repr( yamlData ) ) goodResult = False elif optional : log.debug( ' Yaml data does not specify an optional ' + keyName ) else : log.error( 'Yaml data does not specify a ' + keyName + '. ' + repr( yamlData ) ) goodResult = False return goodResult def complexParameter( yamlData, keyName, doParsingAction, optional = False ) : goodResult = True if keyName in yamlData : goodResult = doParsingAction( yamlData[ keyName ] ) if not goodResult : raise ParseError( 'Incorrectly specified ' + keyName + '. ' + repr( yamlData ) ) elif optional : log.debug( 'Yaml data does not specify an optional ' + keyName ) goodResult = False else : raise ParseError( 'Yaml data does not specify ' + keyName + '.' + repr( yamlData ) ) return goodResult PK&N7registerMap/export/io/yaml/parameters/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N dd9registerMap/export/io/yaml/parameters/tests/testEncode.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os import unittest import registerMap.export.io.yaml.parameters.encode as rmyce import registerMap.export.io.yaml.stream as rmycs class TestEncodeParameter( unittest.TestCase ) : @classmethod def setUpClass( cls ) : thisDir = os.path.dirname( os.path.realpath( __file__ ) ) cls.__dataDir = os.path.join( thisDir, 'data' ) def testSaveLoad( self ) : filePathName = os.path.join( self.__dataDir, (self.testSaveLoad.__name__ + '.yml') ) yamlData = rmyce.parameter( 'someParameter', 10 ) _testSaveLoad( self, filePathName, yamlData ) def _testSaveLoad( instance, filePathName, yamlData ) : try : rmycs.save( filePathName, yamlData ) recoveredData = rmycs.load( filePathName ) instance.assertEqual( yamlData, recoveredData ) finally : if os.path.exists( filePathName ) : os.remove( filePathName ) if __name__ == '__main__' : unittest.main( ) PK&N"  8registerMap/export/io/yaml/parameters/tests/testParse.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import unittest import registerMap.export.io.yaml.parameters.parse as rmpp from registerMap.tests.expectedActual import simpleComparison class TestBooleanParameter( unittest.TestCase ) : def testGoodData( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'name' expectedValue = True yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.booleanParameter( yamlData, keyName, recordResult ) self.assertTrue( goodResult ) self.assertEqual( actualValue, expectedValue ) class TestStringParameter( unittest.TestCase ) : def testGoodData( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'name' expectedValue = 'value' yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.stringParameter( yamlData, keyName, recordResult ) simpleComparison( self, goodResult, True, 'good result' ) simpleComparison( self, actualValue, expectedValue, 'parameter value' ) def testBadKey( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'name' expectedValue = 'value' yamlData = { keyName : expectedValue } actualValue = None with self.assertRaises( rmpp.ParseError ) : goodResult = rmpp.stringParameter( yamlData, 'parameter', recordResult ) class TestIntegerParameter( unittest.TestCase ) : def testGoodData( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'offset' expectedValue = 10 yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.integerParameter( yamlData, keyName, recordResult ) simpleComparison( self, goodResult, True, 'good result' ) simpleComparison( self, actualValue, expectedValue, 'parameter value' ) def testBadValue( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'offset' expectedValue = 'value' yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.integerParameter( yamlData, keyName, recordResult ) simpleComparison( self, goodResult, False, 'good result' ) simpleComparison( self, actualValue, None, 'parameter value' ) def testNoneValueValid( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'offset' expectedValue = None yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.integerParameter( yamlData, keyName, recordResult, noneValid = True ) simpleComparison( self, goodResult, True, 'good result' ) simpleComparison( self, actualValue, None, 'parameter value' ) def testNoneValueInvalid( self ) : def recordResult( value ) : nonlocal actualValue actualValue = value keyName = 'offset' expectedValue = None yamlData = { keyName : expectedValue } actualValue = None goodResult = rmpp.integerParameter( yamlData, keyName, recordResult ) simpleComparison( self, goodResult, False, 'good result' ) simpleComparison( self, actualValue, None, 'parameter value' ) def testUseNameActive( self ) : def recordResult( name, value ) : nonlocal actualName, actualValue actualName = name actualValue = value keyName = 'offset' expectedValue = 3 yamlData = { keyName : expectedValue } actualName = None actualValue = None goodResult = rmpp.integerParameter( yamlData, keyName, recordResult, useName = True ) simpleComparison( self, goodResult, True, 'good result' ) simpleComparison( self, actualName, keyName, 'parameter name' ) simpleComparison( self, actualValue, expectedValue, 'parameter value' ) class TestComplexParameter( unittest.TestCase ) : def testGoodData( self ) : def doParseAction( thisData ) : nonlocal actualData thisGoodResult = True actualData = [ ] for element in thisData : try : value = element[ 'name' ] actualData.append( value ) except KeyError : thisGoodResult = False return thisGoodResult keyName = 'fields' yamlData = { keyName : [ { 'name' : 'one' }, { 'name' : 'two' }, { 'name' : 'three' } ] } actualData = None goodResult = rmpp.complexParameter( yamlData, keyName, doParseAction ) simpleComparison( self, goodResult, True, 'good result' ) simpleComparison( self, actualData, [ 'one', 'two', 'three' ], 'parameter value' ) def testBadValue( self ) : def doParseAction( thisData ) : nonlocal actualData thisGoodResult = False return thisGoodResult keyName = 'fields' yamlData = { 'badName' : [ { 'name' : 'one' }, { 'name' : 'two' }, { 'name' : 'three' } ] } actualData = None with self.assertRaises( rmpp.ParseError ) : goodResult = rmpp.complexParameter( yamlData, keyName, doParseAction ) if __name__ == '__main__' : unittest.main( ) PK&N7registerMap/export/io/yaml/parameters/tests/data/.emptyPK&N۟,registerMap/export/io/yaml/tests/__init__.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # PK&NӠ,registerMap/export/io/yaml/tests/data/.emptyDo not delete this file unless there are other files occupying the directory. It is here to ensure that git recreates the empty directory in clones of the repo.PK&N5ֵ$registerMap/export/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NF  )registerMap/export/tests/testArguments.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..arguments import parseArguments class TestExporterArgumentParser( unittest.TestCase ) : def testRegisterMapFilePath( self ) : inputValue = [ 'path/registerMapFile', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( inputValue[ 0 ], optionsUnderTest.registerMapFile ) def testDefaultRegisterMapName( self ) : inputValue = [ 'path/registerMapFile', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( 'registerMap', optionsUnderTest.registerMapName ) def testMissingLanguageRaises( self ) : inputValue = [ 'path/registerMapFile', ] with self.assertRaisesRegex( RuntimeError, '^Language must be specified' ) : parseArguments( inputValue ) def testLongLicenseFileOption( self ) : inputValue = [ 'path/registerMapFile', '--license-file', 'license/path', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( inputValue[ 2 ], optionsUnderTest.licenseFile ) def testShortLicenseFileOption( self ) : inputValue = [ 'path/registerMapFile', '-l', 'license/path', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( inputValue[ 2 ], optionsUnderTest.licenseFile ) def testLongRegisterMapNameOption( self ) : inputValue = [ 'path/registerMapFile', '--registermap-name', 'someName', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( inputValue[ 2 ], optionsUnderTest.registerMapName ) def testShortRegisterMapNameOption( self ) : inputValue = [ 'path/registerMapFile', '-n', 'someName', 'c++', 'output/path', ] optionsUnderTest = parseArguments( inputValue ) self.assertEqual( inputValue[ 2 ], optionsUnderTest.registerMapName ) if __name__ == '__main__' : unittest.main() PK&N!registerMap/structure/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N(registerMap/structure/bitmap/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .bitmap import BitMap PK&Nd/8*1*1&registerMap/structure/bitmap/bitmap.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections import registerMap.export.io.yaml.parameters.encode as rye from registerMap.exceptions import \ ConfigurationError from registerMap.structure.bitrange import BitRange from registerMap.structure.interval.overlap import isOverlap from registerMap.export.io import yaml class SourceIntervalError( ConfigurationError ) : pass class DestinationIntervalError( ConfigurationError ) : pass class BitMap( yaml.Export ) : """ Map bits from a source to a destination. Assumes a single destination with multiple sources. eg. A register (source) maps its bits to multiple bit fields (destinations). A bit field (source) maps its bits to multiple registers (destinations). """ __yamlName = 'bitmap' def __init__( self, source ) : """ :param source: The source element. """ self.__source = source self.__destinations = set() # Indexed by source bit ranges. # Each source bit range entry contains the destination object and destination bit range it is mapped to. self.__map = collections.OrderedDict() @property def destinations( self ) : return self.__destinations @property def destinationIntervals( self ) : """ Map source intervals to destination intervals, one-to-one. :return: dict mapping """ intervals = dict() for sourceRange, destinationData in self.__map.items() : intervals[ sourceRange ] = destinationData[ 'interval' ] return intervals @property def intervalMap( self ) : return self.__map @property def source( self ) : return self.__source @property def sourceIntervals( self ) : """ :return: set of source intervals. """ intervals = set() for sourceRange, destinationData in self.__map.items() : intervals.add( sourceRange ) return intervals def addReciprocalMap( self, sourceBitRange, destinationBitRange, destination ) : """ When creating a reciprocal mapping between elements (eg register <-> field) this method is used to apply the map to the destination element. The parameter names are defined with respect to the other side of the mapping. So if the register is where the reciprocal map is being applied from, then the parameters of this method are as seen by the field (the destination object is the register). :param sourceBitRange: :param destinationBitRange: :param destination: :return: """ # Notation has reversed here, but keep in mind that we are talking about the other (remote/destination) end of # the reciprocal map. self.__validateBitRange( sourceBitRange, self.__source, 'destination' ) self.__validateBitRange( destinationBitRange, destination, 'source' ) try : self.__validateSourceOverlaps( sourceBitRange ) except SourceIntervalError as e : raise DestinationIntervalError( 'Specifed destination interval overlaps existing destination intervals, {0}: {1}'.format( self.__source.canonicalId, sourceBitRange.value ) ) from e # Assume that length checking of source & destination ranges has been done by mapBits. # Passed all the validation so preserve the mapping self.__addElements( sourceBitRange, destinationBitRange, destination ) def mapBits( self, sourceBitRange, destinationBitRange, destination ) : self.__validateBitRange( sourceBitRange, self.__source, 'source' ) self.__validateBitRange( destinationBitRange, destination, 'destination' ) self.__validateSourceOverlaps( sourceBitRange ) if sourceBitRange.numberBits != destinationBitRange.numberBits : raise ConfigurationError( 'Mismatched bit range sizes, {0} (source), {1} (destination)'.format( sourceBitRange.numberBits, destinationBitRange.numberBits ) ) # The destination is assumed to do it's own validation of the destination interval. destination.bitMap.addReciprocalMap( destinationBitRange, sourceBitRange, self.__source ) # Passed all the validation so preserve the mapping self.__addElements( sourceBitRange, destinationBitRange, destination ) def __addElements( self, sourceBitRange, destinationBitRange, destination ) : self.__map[ sourceBitRange ] = { 'interval' : destinationBitRange, 'destination' : destination } self.__destinations.add( destination ) @staticmethod def __validateBitRange( bitRange, element, rangeText ) : """ Check if the specified range has the appropriate properties against the specified element. :param bitRange: :param element: :param rangeText: 'source' | 'destination' :return: """ assert rangeText in [ 'source', 'destination' ] if not isinstance( bitRange, BitRange ) : raise RuntimeError( 'Incorrect bits type for {1}, {0}'.format( type( bitRange ), rangeText ) ) expectedSize = element.sizeBits if bitRange.numberBits > expectedSize : raise RuntimeError( 'Range {2} cannot exceed size, {0} (range), {1} (size)'.format( bitRange.numberBits, expectedSize, rangeText ) ) def __validateSourceOverlaps( self, sourceBitRange ) : """ Check if a specified range overlaps any existing ranges in the mapping. :param sourceBitRange: :return: """ anyOverlaps = False overlapsIntervals = list() for thisSourceRange, destinationData in self.__map.items() : # Do not fail on identical intevals because this implies an over-write, not an error. if sourceBitRange != thisSourceRange : thisOverlap = isOverlap( sourceBitRange, thisSourceRange ) anyOverlaps |= thisOverlap if thisOverlap : overlapsIntervals.append( '{0}'.format( thisSourceRange.value ) ) if anyOverlaps : raise SourceIntervalError( 'Specifed source interval overlaps existing source intervals, {0}: {1}, {2}'.format( self.__source.canonicalId, sourceBitRange.value, overlapsIntervals ) ) def removeDestination( self, destination = None, interval = None ) : """ Remove a mapping related to a destination. :param destination: (optional) Destination object to be removed. All interval mappings to the destination object will be removed. :param interval: (optional) Interval to be removed. :return: """ assert not ((destination is None) and (interval is None)) if interval is None : self.__removeDestinationObject( destination ) # The source is a destination on the other side of the mapping so make sure the other end is cleaned up. destination.bitMap._removeReciprocalMap( self.__source ) else : assert (destination is not None) \ and (interval is not None) sourceInterval = self.__removeDestinationInterval( destination, interval ) # The source is a destination on the other side of the mapping so make sure the other end is cleaned up. destination.bitMap._removeReciprocalMap( self.__source, sourceInterval ) def __removeDestinationObject( self, destination ) : # destination is not None assert destination is not None try : self.__destinations.remove( destination ) # find every source interval mapped to destination and remove it from the mapping. mappedSourceIntervals = [ k for k, v in self.__map.items() if v[ 'destination' ] == destination ] for sourceBitRange in mappedSourceIntervals : del self.__map[ sourceBitRange ] except KeyError as e : raise ConfigurationError( 'Specified destination does not exist in bit map and cannot be removed, {0}'.format( destination.id ) ) from e def __removeDestinationInterval( self, destination, interval ) : if destination not in self.__destinations : raise ConfigurationError( 'Specified destination does not exist in bit map so cannot remove interval, {0}'.format( destination.id ) ) mappedSourceIntervals = [ k for k, v in self.__map.items() if (v[ 'destination' ] == destination) and (v[ 'interval' ] == interval) ] if len( mappedSourceIntervals ) != 0 : assert len( mappedSourceIntervals ) == 1 for sourceBitRange in mappedSourceIntervals : del self.__map[ sourceBitRange ] else : raise ConfigurationError( 'Specified destination interval does not exist in bit map and cannot be removed, {0}, {1}'.format( destination.id, interval ) ) return mappedSourceIntervals[ 0 ] def _removeReciprocalMap( self, destination = None, interval = None ) : """ Remove the specified object or range from the reciprocal mapping. Should only be used BitMap to BitMap, not publicly by users. :param destination: :param interval: :return: """ assert not ((destination is None) and (interval is None)) if interval is None : self.__removeDestinationObject( destination ) else : assert (destination is not None) \ and (interval is not None) self.__removeDestinationInterval( destination, interval ) def removeSource( self, interval ) : assert interval is not None if interval == self.__source : raise ConfigurationError( 'Cannot remove source from bit map, {0}'.format( self.__source.canonicalId ) ) destination = self.__removeSourceInterval( interval ) # The source is a destination on the other side of the mapping so make sure the other end is cleaned up. destination.bitMap._removeReciprocalMap( self.__source, interval ) def __removeSourceInterval( self, interval ) : range = BitRange( interval ) destinationObject = self.__map[ range ][ 'destination' ] del self.__map[ range ] return destinationObject def to_yamlData( self ) : def constructDestinationIntervalsMapping() : nonlocal self, yamlData mappingData = list() for sourceRange, destinationData in self.__map.items() : sourceRangeData = sourceRange.to_yamlData() destinationRangeData = destinationData[ 'interval' ].to_yamlData() intervalData = { 'source' : sourceRangeData[ 'range' ], 'destination' : destinationRangeData[ 'range' ], 'destinationId' : destinationData[ 'destination' ].canonicalId, } mappingData.append( intervalData ) yamlData[ self.__yamlName ] = mappingData yamlData = rye.parameter( 'bitmap', dict() ) constructDestinationIntervalsMapping() return yamlData PK&N.registerMap/structure/bitmap/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NZ+registerMap/structure/bitmap/tests/mocks.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.structure.elements.base import IdentityElement class MockBitStore( IdentityElement ) : def __init__( self, id, sizeBits, bitMap = None ) : self.__bitMap = bitMap self.__id = id self.__sizeBits = sizeBits @property def bitMap( self ) : return self.__bitMap @bitMap.setter def bitMap( self, value ) : self.__bitMap = value @property def canonicalId( self ) : return self.__id @property def sizeBits( self ) : return self.__sizeBits PK&N 0registerMap/structure/bitmap/tests/testBitMap.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest import unittest.mock import registerMap.structure.bitmap as rmbm from .mocks import MockBitStore class TestBitMapRegisterSize( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) def testRegisterSize( self ) : bm = rmbm.BitMap( self.mock_source ) self.assertEqual( bm.source, self.mock_source ) if __name__ == '__main__' : unittest.main() PK&NcyBregisterMap/structure/bitmap/tests/testBitMapMapDestinationBits.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from ..bitmap import \ BitMap, \ BitRange, \ DestinationIntervalError from .mocks import MockBitStore class TestDestinationRangePersists( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) self.sourceBitMap = BitMap( self.mock_source ) self.mock_source.bitMap = self.sourceBitMap self.destinationSize = 4 self.destinationId = 'testDestination' self.mock_destination = MockBitStore( self.destinationId, self.destinationSize ) self.destinationBitMap = BitMap( self.mock_destination ) self.mock_destination.bitMap = self.destinationBitMap self.destinationRanges = [ BitRange( (0, 2) ), ] self.sourceBitOffset = 4 self.sourceRanges = [ BitRange( (self.sourceBitOffset, (self.sourceBitOffset + 2)) ), ] self.assertNotIn( self.mock_source, self.destinationBitMap.destinations ) self.assertEqual( self.sourceBitMap.source, self.mock_source ) self.assertEqual( self.sourceBitMap.destinations, set() ) self.assertNotIn( self.mock_destination, self.sourceBitMap.destinations ) self.assertEqual( self.destinationBitMap.source, self.mock_destination ) self.assertEqual( self.destinationBitMap.destinations, set() ) self.sourceBitMap.mapBits( self.sourceRanges[ 0 ], self.destinationRanges[ 0 ], self.mock_destination ) def testDestinationAddedToSource( self ) : """ Creating a mapping stores the destination in the source BitMap. """ self.assertIn( self.mock_destination, self.sourceBitMap.destinations ) actualIntervalMap = self.sourceBitMap.intervalMap self.assertEqual( len( actualIntervalMap ), 1 ) (actualSourceInterval, actualDestination) = actualIntervalMap.popitem() self.assertEqual( actualSourceInterval, self.sourceRanges[ 0 ] ) self.assertEqual( actualDestination[ 'destination' ], self.mock_destination ) self.assertEqual( actualDestination[ 'interval' ], self.destinationRanges[ 0 ] ) def testSourceAddedToDestinationAsDestination( self ) : """ Creating a mapping stores the source in the destination BitMap as a destination. """ self.assertIn( self.mock_source, self.destinationBitMap.destinations ) actualIntervalMap = self.destinationBitMap.intervalMap self.assertEqual( len( actualIntervalMap ), 1 ) (actualSourceInterval, actualDestination) = actualIntervalMap.popitem() self.assertEqual( actualSourceInterval, self.destinationRanges[ 0 ] ) self.assertEqual( actualDestination[ 'destination' ], self.mock_source ) self.assertEqual( actualDestination[ 'interval' ], self.sourceRanges[ 0 ] ) def testDestinationAddedToDestinationAsSource( self ) : """ Creating a mapping stores the destination in the destination BitMap as the source of that BitMap. """ self.assertEqual( self.destinationBitMap.source, self.mock_destination ) class TestAssignOverlappingDestinationIntervals( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) self.sourceBitMap = BitMap( self.mock_source ) self.mock_source.bitMap = self.sourceBitMap self.destinationSize = 4 self.destinationId = 'testDestination' self.mock_destination = MockBitStore( self.destinationId, self.destinationSize ) self.destinationBitMap = BitMap( self.mock_destination ) self.mock_destination.bitMap = self.destinationBitMap def testOverlappedDestinationIntervalRaises( self ) : destinationRanges = [ BitRange( (0, 2) ), BitRange( (2, 3) ), ] sourceBitOffset = 4 sourceRanges = [ BitRange( (sourceBitOffset, (sourceBitOffset + 2)) ), BitRange( ((sourceBitOffset + 3), (sourceBitOffset + 4)) ), ] self.sourceBitMap.mapBits( sourceRanges[ 0 ], destinationRanges[ 0 ], self.mock_destination ) self.assertEqual( len( self.sourceBitMap.intervalMap ), 1 ) with self.assertRaisesRegex( DestinationIntervalError, '^Specifed destination interval overlaps existing destination intervals' ) : self.sourceBitMap.mapBits( sourceRanges[ 1 ], destinationRanges[ 1 ], self.mock_destination ) if __name__ == '__main__' : unittest.main() PK&N4[=registerMap/structure/bitmap/tests/testBitMapMapSourceBits.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from ..bitmap import \ BitMap, \ BitRange, \ ConfigurationError from .mocks import MockBitStore class TestAssignOverlappingSourceIntervals( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) self.sourceBitMap = BitMap( self.mock_source ) self.mock_source.bitMap = self.sourceBitMap self.destinationSize = 4 self.destinationId = 'testDestination' self.mock_destination = MockBitStore( self.destinationId, self.destinationSize ) self.destinationBitMap = BitMap( self.mock_destination ) self.mock_destination.bitMap = self.destinationBitMap def testOverlappedSourceIntervalRaises( self ) : fieldRanges = [ BitRange( (0, 1) ), BitRange( (2, 3) ), ] registerBitOffset = 4 registerRanges = [ BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1 - 2)) ), BitRange( ((registerBitOffset + self.destinationSize - 1 - 2), (registerBitOffset + self.destinationSize - 1)) ), ] self.sourceBitMap.mapBits( registerRanges[ 0 ], fieldRanges[ 0 ], self.mock_destination ) self.assertEqual( len( self.sourceBitMap.intervalMap ), 1 ) with self.assertRaisesRegex( ConfigurationError, '^Specifed source interval overlaps existing source intervals' ) : self.sourceBitMap.mapBits( registerRanges[ 1 ], fieldRanges[ 1 ], self.mock_destination ) def testIdenticalSourceIntervalWritesNewMapping( self ) : # Equal source interval writes the new mapping. fieldRanges = [ BitRange( (0, 1) ), BitRange( (2, 3) ), ] registerBitOffset = 4 registerRange = BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1 - 2)) ) self.sourceBitMap.mapBits( registerRange, fieldRanges[ 0 ], self.mock_destination ) self.assertEqual( len( self.sourceBitMap.intervalMap ), 1 ) self.sourceBitMap.mapBits( registerRange, fieldRanges[ 1 ], self.mock_destination ) self.assertEqual( len( self.sourceBitMap.intervalMap ), 1 ) actualIntervals = self.sourceBitMap.intervalMap self.assertTrue( len( actualIntervals ), 1 ) actualSourceRange, destinationData = actualIntervals.popitem() self.assertEqual( actualSourceRange, registerRange ) self.checkDestinationData( destinationData, self.mock_destination, fieldRanges[ 1 ] ) def checkDestinationData( self, actualData, expectedObject, expectedInterval ) : self.assertEqual( actualData[ 'destination' ], expectedObject ) self.assertEqual( actualData[ 'interval' ], expectedInterval ) def testAddingDifferentIntervalsIncreasesSize( self ) : fieldRanges = [ BitRange( (0, 1) ), BitRange( (2, 3) ), ] registerBitOffset = 4 registerRanges = [ BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1 - 2)) ), BitRange( ((registerBitOffset + self.destinationSize - 1 - 1), (registerBitOffset + self.destinationSize - 1)) ), ] self.sourceBitMap.mapBits( registerRanges[ 0 ], fieldRanges[ 0 ], self.mock_destination ) self.assertEqual( len( self.sourceBitMap.intervalMap ), 1 ) self.sourceBitMap.mapBits( registerRanges[ 1 ], fieldRanges[ 1 ], self.mock_destination ) actualIntervals = self.sourceBitMap.intervalMap self.assertTrue( len( actualIntervals ), 2 ) destinationData = actualIntervals[ registerRanges[ 0 ] ] self.checkDestinationData( destinationData, self.mock_destination, fieldRanges[ 0 ] ) destinationData = actualIntervals[ registerRanges[ 1 ] ] self.checkDestinationData( destinationData, self.mock_destination, fieldRanges[ 1 ] ) if __name__ == '__main__' : unittest.main() PK&NP5registerMap/structure/bitmap/tests/testBitMapQuery.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from ..bitmap import \ BitMap, \ BitRange from .mocks import MockBitStore class TestQueryRanges( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) self.sourceBitMap = BitMap( self.mock_source ) self.mock_source.bitMap = self.sourceBitMap self.destinationSize = 4 self.destinationId = 'testDestination' self.mock_destination = MockBitStore( self.destinationId, self.destinationSize ) self.destinationBitMap = BitMap( self.mock_destination ) self.mock_destination.bitMap = self.destinationBitMap def testAssignedSourceRangePersists( self ) : # The assigned source range can be queried. fieldRange = BitRange( (0, (self.destinationSize - 1)) ) registerBitOffset = 4 registerRange = BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1)) ) self.sourceBitMap.mapBits( registerRange, fieldRange, self.mock_destination ) actualIntervals = self.sourceBitMap.sourceIntervals self.assertTrue( len( actualIntervals ), 1 ) actualValue = actualIntervals.pop() self.assertEqual( actualValue, registerRange ) def testAssignedDestinationRangePersists( self ) : # The assigned destination range can be queried. fieldRange = BitRange( (0, (self.destinationSize - 1)) ) registerBitOffset = 4 registerRange = BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1)) ) self.sourceBitMap.mapBits( registerRange, fieldRange, self.mock_destination ) actualIntervals = self.sourceBitMap.destinationIntervals self.assertTrue( len( actualIntervals ), 1 ) (sourceInterval, actualValue) = actualIntervals.popitem() self.assertEqual( actualValue, fieldRange ) self.assertEqual( sourceInterval, registerRange ) def testAssignedRangesPersists( self ) : # The assigned destination range can be queried. fieldRange = BitRange( (0, (self.destinationSize - 1)) ) registerBitOffset = 4 registerRange = BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1)) ) self.sourceBitMap.mapBits( registerRange, fieldRange, self.mock_destination ) actualIntervals = self.sourceBitMap.intervalMap self.assertTrue( len( actualIntervals ), 1 ) (sourceRange, destinationValue) = actualIntervals.popitem() self.assertEqual( destinationValue[ 'destination' ], self.mock_destination ) self.assertEqual( sourceRange, registerRange ) self.assertEqual( destinationValue[ 'interval' ], fieldRange ) if __name__ == '__main__' : unittest.main() PK&Nܺ''6registerMap/structure/bitmap/tests/testBitMapRanges.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from ..bitmap import \ BitMap, \ BitRange, \ ConfigurationError from .mocks import MockBitStore class TestBitMapAssignRanges( unittest.TestCase ) : def setUp( self ) : self.sourceSize = 16 self.sourceId = 'testSource' self.mock_source = MockBitStore( self.sourceId, self.sourceSize ) self.sourceBitMap = BitMap( self.mock_source ) self.mock_source.bitMap = self.sourceBitMap self.destinationSize = 4 self.destinationId = 'testDestination' self.mock_destination = MockBitStore( self.destinationId, self.destinationSize ) self.destinationBitMap = BitMap( self.mock_destination ) self.mock_destination.bitMap = self.destinationBitMap def testMapBitRange( self ) : # Mapping two intervals of equal size generates no errors fieldRange = BitRange( (0, (self.destinationSize - 1)) ) registerBitOffset = 4 registerRange = BitRange( (registerBitOffset, (registerBitOffset + self.destinationSize - 1)) ) self.sourceBitMap.mapBits( registerRange, fieldRange, self.mock_destination ) def testAssignBadSourceBitsTypeRaises( self ) : # Specifying "not BitRange" for the source range raises. with self.assertRaisesRegex( RuntimeError, '^Incorrect bits type for source' ) : self.sourceBitMap.mapBits( 5, BitRange( (4, 6) ), self.mock_destination ) def testSourceBitsExceedsSourceSizeRaises( self ) : # Specifying register/source range that exceed the source size raises. fieldRange = BitRange( (0, 5) ) registerRange = BitRange( (0, (self.sourceSize + 1)) ) with self.assertRaisesRegex( RuntimeError, '^Range source cannot exceed size' ) : self.sourceBitMap.mapBits( registerRange, fieldRange, self.mock_destination ) def testDestinationBitsExceedsDestinationSizeRaises( self ) : # Specifying field/destination range that exceeds the destination size raises. destinationRange = BitRange( (0, (self.destinationSize + 1)) ) sourceRange = BitRange( (0, 5) ) with self.assertRaisesRegex( RuntimeError, '^Range destination cannot exceed size' ) : self.sourceBitMap.mapBits( sourceRange, destinationRange, self.mock_destination ) def testAssignBadDestinationBitsTypeRaises( self ) : # Specifying "not BitRange" type for destination range raises. with self.assertRaisesRegex( RuntimeError, '^Incorrect bits type for destination' ) : self.sourceBitMap.mapBits( BitRange( (4, 6) ), 8, self.mock_destination ) def testAssignMismatchedSizes( self ) : # Specifying source and destination ranges that don't have the same size raises. destinationRange = BitRange( (0, (self.destinationSize - 1)) ) sourceRange = BitRange( (4, 10) ) with self.assertRaisesRegex( ConfigurationError, '^Mismatched bit range sizes' ) : self.sourceBitMap.mapBits( sourceRange, destinationRange, self.mock_destination ) if __name__ == '__main__' : unittest.main() PK&NUܫu u :registerMap/structure/bitmap/tests/testBitMapYamlEncode.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest.mock from registerMap.structure.elements.field import Field from registerMap.structure.bitrange import BitRange from .mocks import MockBitStore from .. import BitMap log = logging.getLogger( __name__ ) class TestEncodeYamlBitMap( unittest.TestCase ) : def setUp( self ) : self.mockSource = MockBitStore( 'module.register', 10 ) self.bitMapUnderTest = BitMap( self.mockSource ) self.mockSource.bitMap = self.bitMapUnderTest def testEncodeEmptyBitMap( self ) : # An empty bitmap encodes only the source info encodedYamlData = self.bitMapUnderTest.to_yamlData() self.assertEqual( encodedYamlData[ 'bitmap' ], list() ) class TestEncodeYamlBitMapIntervals( unittest.TestCase ) : """ Demonstrate YAML encoding BitMap intervals. """ def setUp( self ) : def constructMockDestination() : nonlocal self self.destinationMockBitmap = unittest.mock.create_autospec( BitMap ) self.mockDestination = unittest.mock.create_autospec( Field ) idp = unittest.mock.PropertyMock( return_value = 'module.register.field' ) type( self.mockDestination ).canonicalId = idp idbm = unittest.mock.PropertyMock( return_value = self.destinationMockBitmap ) type( self.mockDestination ).bitMap = idbm self.mockSource = MockBitStore( 'module.register', 10 ) self.bitMapUnderTest = BitMap( self.mockSource ) self.mockSource.bitMap = self.bitMapUnderTest constructMockDestination() def testEncodeMapping( self ) : with unittest.mock.patch.object( self.bitMapUnderTest, '_BitMap__validateBitRange' ) : with unittest.mock.patch.object( self.bitMapUnderTest, '_BitMap__validateSourceOverlaps' ) : self.bitMapUnderTest.mapBits( BitRange( [ 4, 7 ] ), BitRange( (0, 3) ), self.mockDestination ) encodedYamlData = self.bitMapUnderTest.to_yamlData() self.assertEqual( len( encodedYamlData[ 'bitmap' ] ), 1 ) self.assertEqual( encodedYamlData[ 'bitmap' ][ 0 ][ 'source' ], '[4:7]' ) self.assertEqual( encodedYamlData[ 'bitmap' ][ 0 ][ 'destination' ], '[0:3]' ) self.assertEqual( encodedYamlData[ 'bitmap' ][ 0 ][ 'destinationId' ], self.mockDestination.canonicalId ) if __name__ == '__main__' : unittest.main() PK&NXX3registerMap/structure/bitmap/tests/testRemoveMap.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap.structure.elements.field import Field from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.bitrange import BitRange from ..bitmap import \ BitMap, \ ConfigurationError class TestBitMapRemoveMap( unittest.TestCase ) : def setUp( self ) : self.mockRegister = unittest.mock.create_autospec( RegisterInstance ) self.mockField = unittest.mock.create_autospec( Field ) self.mapUnderTest = BitMap( self.mockRegister ) def testNeitherDestinationNorIntervalAsserts( self ) : with self.assertRaises( AssertionError ) : self.mapUnderTest.removeDestination() def testRemoveDestination( self ) : def checkRemovedFromSourceMapping() : nonlocal self destinationMappings = self.mapUnderTest.intervalMap.values() for k in destinationMappings : self.assertNotEqual( k[ 'destination' ], self.mockField ) # Removing an entire destination object also removes the corresponding source intervals. with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateBitRange' ) as br : with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateSourceOverlaps' ) as so : self.mapUnderTest.mapBits( BitRange( [ 0, 4 ] ), BitRange( [ 0, 4 ] ), self.mockField ) self.assertIn( self.mockField, self.mapUnderTest.destinations ) self.mapUnderTest.removeDestination( self.mockField ) self.assertNotIn( self.mockField, self.mapUnderTest.destinations ) checkRemovedFromSourceMapping() # Check that the Field (destination) has been reciprocally called for source removal. self.assertEqual( self.mockField.method_calls[ -1 ][ 0 ], 'bitMap._removeReciprocalMap' ) def testRemoveNonexistentDestinationIntervalRaises( self ) : # Removing a nonexistent destination interval raises an exception with self.assertRaisesRegex( ConfigurationError, '^Specified destination does not exist in bit map and cannot be removed' ) : self.mapUnderTest.removeDestination( self.mockField ) def testRemoveDestinationInterval( self ) : # Removing a valid destination interval also removes the corresponding source interval. with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateBitRange' ) as br : with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateSourceOverlaps' ) as so : self.mapUnderTest.mapBits( BitRange( [ 0, 4 ] ), BitRange( [ 0, 4 ] ), self.mockField ) self.mapUnderTest.mapBits( BitRange( [ 5, 6 ] ), BitRange( [ 5, 6 ] ), self.mockField ) self.assertIn( self.mockField, self.mapUnderTest.destinations ) self.mapUnderTest.removeDestination( destination = self.mockField, interval = [ 0, 4 ] ) # The actual objects must not have been removed. self.assertIn( self.mockField, self.mapUnderTest.destinations ) self.assertEqual( self.mockRegister, self.mapUnderTest.source ) # But the interval must have been removed. self.checkRemovedSourceInterval( BitRange( [ 0, 4 ] ) ) self.checkRemovedDestinationInterval( BitRange( [ 0, 4 ] ) ) # Check that the Field (destination) has been reciprocally called for interval removal. self.assertEqual( self.mockField.method_calls[ -1 ][ 0 ], 'bitMap._removeReciprocalMap' ) def checkRemovedSourceInterval( self, range ) : sourceMappings = self.mapUnderTest.intervalMap.keys() self.assertNotIn( range, sourceMappings ) def checkRemovedDestinationInterval( self, range ) : destinationMappings = self.mapUnderTest.intervalMap.values() for k in destinationMappings : self.assertNotEqual( k[ 'interval' ], range ) def testRemoveSourceInterval( self ) : # Removing a valid source interval also removes the corresponding destination interval. with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateBitRange' ) as br : with unittest.mock.patch.object( self.mapUnderTest, '_BitMap__validateSourceOverlaps' ) as so : self.mapUnderTest.mapBits( BitRange( [ 0, 4 ] ), BitRange( [ 0, 4 ] ), self.mockField ) self.mapUnderTest.mapBits( BitRange( [ 5, 6 ] ), BitRange( [ 5, 6 ] ), self.mockField ) self.assertIn( self.mockField, self.mapUnderTest.destinations ) self.mapUnderTest.removeSource( interval = [ 0, 4 ] ) # The actual objects must not have been removed. self.assertIn( self.mockField, self.mapUnderTest.destinations ) self.assertEqual( self.mockRegister, self.mapUnderTest.source ) # But the interval must have been removed. self.checkRemovedSourceInterval( BitRange( [ 0, 4 ] ) ) self.checkRemovedDestinationInterval( BitRange( [ 0, 4 ] ) ) # Check that the Field (destination) has been reciprocally called for interval removal. self.assertEqual( self.mockField.method_calls[ -1 ][ 0 ], 'bitMap._removeReciprocalMap' ) def testRemoveSourceRaises( self ) : # Removing a source object raises an exception. with self.assertRaisesRegex( ConfigurationError, '^Cannot remove source from bit map' ) : self.mapUnderTest.removeSource( self.mockRegister ) if __name__ == '__main__' : unittest.main() PK&N ¤ *registerMap/structure/bitrange/__init__.py""" Definition of BitRange """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import re import registerMap.export.io.yaml.parameters.encode as rye import registerMap.export.io.yaml.parameters.parse as ryp import registerMap.utility.observer as rmo from registerMap.structure import interval as rmbi from registerMap.export.io import yaml from registerMap.exceptions import ParseError log = logging.getLogger( __name__ ) class BitRange( yaml.Export, yaml.Import, rmbi.ClosedIntegerInterval ) : """ A representation of a closed interval of bit indices. The interval can be imported to, and exported from, a YAML file. """ __yamlName = 'range' def __init__( self, value = None ) : super().__init__( value = value ) self.sizeChangeNotifier = rmo.Observable() @property def maxValue( self ) : maxValue = pow( 2, self.numberBits ) - 1 return maxValue @staticmethod def __calculateNumberBits( value ) : return max( value ) - min( value ) + 1 @property def numberBits( self ) : interval = super().value if interval is None : returnValue = 0 else : returnValue = max( interval ) - min( interval ) + 1 return returnValue @rmbi.ClosedIntegerInterval.value.setter def value( self, v ) : rmbi.ClosedIntegerInterval.value.fset( self, v ) log.debug( 'Notifying of a bit range value change' ) self.sizeChangeNotifier.notifyObservers() @classmethod def from_yamlData( cls, yamlData ) : bitRange = cls() goodResult = bitRange.__decodeBitRange( yamlData ) if not goodResult : raise ParseError( 'Processing bit range data failed. Check log for details. ' + repr( yamlData ) ) return bitRange def __decodeBitRange( self, yamlData ) : def recordValue( valueData ) : nonlocal self if valueData == 'None' : self.__value = None else : rangeData = valueData.strip( '[' ).strip( ']' ) tokens = re.split( r':', rangeData ) if len( tokens ) != 2 : log.error( 'Range must have only two values: ' + rangeData ) try : v = [ int( tokens[ 0 ] ), int( tokens[ 1 ] ) ] self.value = v except ValueError : log.error( 'Range must be integers: ' + rangeData ) return ryp.stringParameter( yamlData, self.__yamlName, recordValue, optional = False ) def to_yamlData( self ) : value = '[' + str( min( super().value ) ) + ':' + str( max( super().value ) ) + ']' return rye.parameter( self.__yamlName, value ) PK&N0registerMap/structure/bitrange/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NȊ ff4registerMap/structure/bitrange/tests/testBitRange.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest import registerMap.exceptions as rme import registerMap.structure.bitrange as rmbr from registerMap.structure.elements.tests.mockObserver import MockObserver log = logging.getLogger( __name__ ) class TestBitRange( unittest.TestCase ) : def setUp( self ) : self.testBitRange = rmbr.BitRange() self.observer = MockObserver() self.testBitRange.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertEqual( self.testBitRange, None ) def testConstructedValue( self ) : expectedValue = [ 3, 6 ] r = rmbr.BitRange( value = expectedValue ) self.assertEqual( r.value, set( expectedValue ) ) def testBadConstructedValueRaises( self ) : expectedValue = '[3, 6]' with self.assertRaisesRegex( rme.ConfigurationError, '^Interval must be a set of one or two positive integers' ) : rmbr.BitRange( value = expectedValue ) def testValueAssignment( self ) : expectedValue = [ 0, 8 ] self.testBitRange.value = expectedValue self.assertTrue( isinstance( self.testBitRange, rmbr.BitRange ) ) self.assertEqual( self.testBitRange, expectedValue ) self.assertTrue( self.observer.updated ) def testMaxValue( self ) : expectedValue = 7 self.testBitRange.value = [ 2, 4 ] self.assertEqual( self.testBitRange.maxValue, expectedValue ) def testNonListRaises( self ) : with self.assertRaisesRegex( rme.ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testBitRange.value = '5' def testListNonIntRaises( self ) : with self.assertRaisesRegex( rme.ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testBitRange.value = [ 5, '6' ] def testNegativeValuesRaises( self ) : with self.assertRaisesRegex( rme.ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testBitRange.value = [ 5, -7 ] def testWrongLengthRaises( self ) : with self.assertRaisesRegex( rme.ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testBitRange.value = [ 5, 8, 6 ] class TestNumberBits( unittest.TestCase ) : def setUp( self ) : self.testBitRange = rmbr.BitRange() def testCalculateNumberBits( self ) : expectedValue = 5 self.testBitRange.value = [ 2, 6 ] self.assertEqual( self.testBitRange.numberBits, expectedValue ) def testNumberBitsNoneValueIsZero( self ) : self.assertEqual( self.testBitRange.numberBits, 0 ) class TestEqualOperator( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.testBitRange = rmbr.BitRange( value = self.expectedValue ) def testList( self ) : self.assertTrue( self.testBitRange == self.expectedValue ) def testNone( self ) : # It is necessary to use == operator here because 'is' operator cannot be overridden in Python. self.assertFalse( self.testBitRange == None ) def testBitRange( self ) : self.assertTrue( self.testBitRange == rmbr.BitRange( value = self.expectedValue ) ) self.assertFalse( self.testBitRange == rmbr.BitRange( value = [ 0, 4 ] ) ) class TestNotEqualOperator( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.testBitRange = rmbr.BitRange( value = self.expectedValue ) def testList( self ) : self.assertTrue( self.testBitRange != [ 0, 4 ] ) def testNone( self ) : # It is necessary to use != operator here because 'is' operator cannot be overridden in Python. self.assertTrue( self.testBitRange != None ) def testBitRange( self ) : self.assertFalse( self.testBitRange != rmbr.BitRange( value = self.expectedValue ) ) self.assertTrue( self.testBitRange != rmbr.BitRange( value = [ 0, 4 ] ) ) if __name__ == '__main__' : unittest.main() PK&NED  :registerMap/structure/bitrange/tests/testBitRangeYamlIo.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest import registerMap.structure.bitrange as rmbr log = logging.getLogger( __name__ ) class TestBitRangeLoadSave( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.testBitRange = rmbr.BitRange( value = self.expectedValue ) def testLoadSave( self ) : encodedYamlData = self.testBitRange.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = rmbr.BitRange.from_yamlData( encodedYamlData ) self.assertEqual( decodedData.value, self.testBitRange.value ) def testNoneValueDecode( self ) : yamlData = { 'range' : None } decodedData = rmbr.BitRange.from_yamlData( yamlData ) self.assertIsNone( decodedData.value ) if __name__ == '__main__' : unittest.main() PK&N*registerMap/structure/elements/__init__.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from .field import Field from .module import Module from .register import \ Register, \ RegisterInstance PK&N!GV/registerMap/structure/elements/base/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .bitStore import BitStoreInterface from .element import ElementList from .identity import IdentityElement from .observable import \ AddressObservableInterface, \ SizeObservableInterface PK&NvE/registerMap/structure/elements/base/bitStore.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class BitStoreInterface( metaclass = abc.ABCMeta ) : @property @abc.abstractmethod def bitMap( self ) : pass @property @abc.abstractmethod def id( self ) : pass @property @abc.abstractmethod def sizeBits( self ) : pass PK&N).registerMap/structure/elements/base/element.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections class ElementList( collections.OrderedDict ) : """ Manage the instances of addressable memory elements such as module and register. The list maintains the notification relationships between element regarding address and size changes. """ def __init__( self, owner ) : """ :param owner: RegisterMap or Module object who "owns" the list of sub elements. """ super().__init__() self.__owner = owner def __setitem__( self, key, value ) : try : previousElementKey = next( reversed( self ) ) previousElement = self[ previousElementKey ] except StopIteration as e : # This is the first register added. previousElement = self.__owner.firstElement super().__setitem__( key, value ) # Link the value being added to it's previous element in the list. value.previousElement = previousElement # Size change of an element means the owner might also need to change size. value.sizeChangeNotifier.addObserver( self.__owner.sizeObserver ) # Address change of an element implies a potential size change to its owner. value[ 'constraints' ].addressChangeNotifier.addObserver( self.__owner.sizeObserver ) value.reviewAddressChange() PK&N}/registerMap/structure/elements/base/identity.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class IdentityElement( metaclass = abc.ABCMeta ) : """ Provide a unique, numerical identity for a register map element. """ __idCounter = 0 def __init__( self ) : self.__id = IdentityElement.assignId() @property @abc.abstractmethod def canonicalId( self ) : """ Text identity based on the register map structure. eg. 'm1' for a module 'm1.r1' for a register inside a module 'm1.r1.f1' for a field inside a register """ pass @property def id( self ) : """ Unique, numerical (integer) identity. """ return self.__id @staticmethod def assignId() : IdentityElement.__idCounter += 1 return IdentityElement.__idCounter PK&N1registerMap/structure/elements/base/observable.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class SizeObservableInterface( metaclass = abc.ABCMeta ) : @abc.abstractmethod def reviewSizeChange( self ) : pass class AddressObservableInterface( metaclass = abc.ABCMeta ) : @abc.abstractmethod def reviewAddressChange( self ) : passPK&N7- 0registerMap/structure/elements/base/parameter.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from registerMap.constraints import ConstraintTable from registerMap.utility.observer import Observable from registerMap.export.io.yaml.parameters.encode import parameter as YamlEncodedParameter from registerMap.exceptions import ParseError class Parameter( Observable ) : def __init__( self, name = None, value = None ) : super().__init__() self.validate( value ) self.name = name self.__value = value if value is not None : # notify an initial value self.notifyObservers() def validate( self, value ) : # By default, do nothing (implicitly pass validation) pass @property def value( self ) : return self.__value @value.setter def value( self, v ) : self.validate( v ) self.__value = v # Notify any observers. self.notifyObservers() @classmethod def from_yamlData( cls, yamlData, name, optional = False ) : parameter = cls() parameter.name = name if name in yamlData.keys() : # Don't modify the data type discovered by yaml parsing. parameter.__value = yamlData[ name ] elif optional : parameter.__value = None elif not optional : raise ParseError( 'Parameter is not in yaml data, ' + repr( name ) ) return parameter def to_yamlData( self ) : # Assume the data can be stored directly in yaml. yamlData = YamlEncodedParameter( self.name, self.value ) return yamlData class ConstraintsParameter( Parameter ) : __parameterName = 'constraints' def __init__( self, memorySpace, validConstraints = None ) : super().__init__( self.__parameterName, ConstraintTable( memorySpace, validConstraints = validConstraints ) ) @classmethod def from_yamlData( cls, yamlData, memorySpace, optional = False ) : parameter = cls( memorySpace ) parameter.value = ConstraintTable.from_yamlData( yamlData, memorySpace, optional = optional ) return parameter def to_yamlData( self ) : return self.value.to_yamlData() PK&N5registerMap/structure/elements/base/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N>(3registerMap/structure/elements/base/tests/testId.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..identity import IdentityElement class MockIdentityElement( IdentityElement ) : """ Implement abstract methods to enable testing. """ @property def canonicalId( self ) : return None class TestIdentityElement( unittest.TestCase ) : def setUp( self ) : self.firstId = MockIdentityElement() self.secondId = MockIdentityElement() def testInitialId( self ) : firstId = self.firstId.id secondId = self.secondId.id self.assertNotEqual( firstId, secondId ) def testIdConsistency( self ) : firstIdRead = self.firstId.id newId = MockIdentityElement() secondIdRead = self.firstId.id self.assertEqual( firstIdRead, secondIdRead ) if __name__ == '__main__' : unittest.main() PK&N:registerMap/structure/elements/base/tests/testParameter.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.utility.observer.interface import Observer from ..parameter import Parameter class MockObserver( Observer ) : def __init__( self ) : super().__init__() self.value = None def update( self, subject, arguments ) : self.value = subject.value class TestObserveParameter( unittest.TestCase ) : def setUp( self ) : self.parameterUnderTest = Parameter( value = 6.6626 ) self.observer = MockObserver() self.parameterUnderTest.addObserver( self.observer ) def testValueChangeNotifies( self ) : self.assertNotEqual( self.parameterUnderTest.value, self.observer.value ) self.parameterUnderTest.value = 3.14 self.assertEqual( self.parameterUnderTest.value, self.observer.value ) if __name__ == '__main__' : unittest.main() PK&N̫m0registerMap/structure/elements/field/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .field import Field PK&NS`//-registerMap/structure/elements/field/field.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections import logging from registerMap.structure.bitmap import BitMap from registerMap.export.io import yaml from registerMap.export.io.yaml.parameters.encode import \ HexInt, \ parameter from registerMap.export.io.yaml.parameters.parse import \ complexParameter, \ integerParameter, \ stringParameter from registerMap.utility.observer import \ Observable, \ SizeChangeObserver from registerMap.exceptions import \ ConfigurationError, \ ParseError from ..base import \ BitStoreInterface, \ IdentityElement from .parameters import \ GlobalParameter, \ NameParameter, \ Parameter, \ ResetValueParameter, \ SizeParameter, \ StringParameter log = logging.getLogger( __name__ ) class Field( IdentityElement, BitStoreInterface, yaml.Export, yaml.Import ) : """ Representation of a bit field in a register. The following parameters are available for every BitField: # description (str) - Expanded description of the BitField object. # global (bool) - Assert whether or not the BitField object is global. # name (str) - Alphanumeric name of the BitField object. # public (bool) - Assert whether or not the BitField object is public. # resetValue (int) - Reset (default) value of the BitField object. # size (int) - The number of bits in the BitField object. # summary (str) - Short description of the BitField object. """ __DEFAULT_NAME = 'unassigned' __KEY_NAME = 'field' def __init__( self, parent = None ) : super().__init__() self.sizeChangeNotifier = Observable() self.__bitMap = BitMap( self ) self.__parentRegister = parent self.__sizeChangeObserver = SizeChangeObserver( self ) self.__coreData = { 'description' : StringParameter( name = 'description', value = '' ), 'global' : GlobalParameter( self ), 'name' : NameParameter( value = self.__DEFAULT_NAME ), 'resetValue' : ResetValueParameter( value = 0, size = 0 ), 'summary' : StringParameter( name = 'summary', value = '' ), } self.__coreData[ 'size' ] = SizeParameter( self.__coreData[ 'resetValue' ] ) self.__userData = collections.OrderedDict() def __getitem__( self, item ) : if item in self.__coreData : value = self.__coreData[ item ].value elif item in self.__userData : value = self.__userData[ item ].value else : raise KeyError( 'Field parameter not in core or user data, {0} ({1})'.format( item, self.canonicalId ) ) return value def __setitem__( self, key, value ) : if key in self.__coreData : self.__coreData[ key ].value = value else : assert not key.startswith( '_' ) # Assume user data self.__userData[ key ] = Parameter( name = key, value = value ) if key == 'size' : log.debug( 'Notifying on field size change, {0}: {1}'.format( self.__coreData[ 'name' ].value, value ) ) self.sizeChangeNotifier.notifyObservers() @property def bitMap( self ) : return self.__bitMap @property def canonicalId( self ) : if self.__parentRegister is not None : canonicalName = '{0}.{1}'.format( self.__parentRegister.canonicalId, self.__coreData[ 'name' ].value ) else : canonicalName = '{0}'.format( self.__coreData[ 'name' ].value ) return canonicalName @property def coreParameters( self ) : """ The dictionary cannot be used to modify the parameters. :return: A dictionary of the core parameters. """ p = dict() for key, v in self.__coreData.items() : p[ key ] = v.value return p @property def userParameters( self ) : """ The dictionary cannot be used to modify the parameters. :return: A dictionary of the user defined parameters. """ p = dict() for key, v in self.__userData.items() : p[ key ] = v.value return p @property def parent( self ) : """ :return: Parent register of field. None if no parent (implies a global field). """ return self.__parentRegister @property def sizeBits( self ) : return self.__coreData[ 'size' ].value def reviewSizeChange( self ) : # Cascade the size change self.sizeChangeNotifier.notifyObservers() @classmethod def from_yamlData( cls, yamlData, parentRegister = None ) : field = cls() goodResult = field.__decodeField( yamlData, parentRegister ) if not goodResult : raise ParseError( 'Processing field data failed. Check log for details. ' + repr( yamlData ) ) return field def __decodeField( self, yamlData, parentRegister ) : def acquireDescription( thisData ) : nonlocal self self.__coreData[ 'description' ] = StringParameter.from_yamlData( thisData, 'description', optional = True ) def recordParent( value ) : nonlocal parentRegister assert value is not None if parentRegister is None : # Must specify a parent register for local fields. raise ParseError( 'Parent register not specified for YAML acquisition of a local field' ) elif parentRegister.canonicalId != value : raise ParseError( 'Parent register does not match YAML specification, spec({0}), yaml({1})'.format( parentRegister.canonicalId, value ) ) self.__parentRegister = parentRegister def acquireName( thisData ) : nonlocal self self.__coreData[ 'name' ] = NameParameter.from_yamlData( thisData, 'name' ) def acquireResetValue( thisData ) : nonlocal self self.__coreData[ 'resetValue' ] = ResetValueParameter.from_yamlData( thisData, 'resetValue' ) def recordSize( value ) : nonlocal self self.__coreData[ 'size' ] = SizeParameter( self.__coreData[ 'resetValue' ] ) self.__coreData[ 'size' ].value = value # Make sure that we subscribe to notification of bit range size changes. self.__coreData[ 'size' ].sizeChangeNotifier.addObserver( self.__sizeChangeObserver ) def acquireSummary( thisData ) : nonlocal self self.__coreData[ 'summary' ] = StringParameter.from_yamlData( thisData, 'summary', optional = True ) def acquireUserParameters( thisData ) : nonlocal self for name, value in thisData.items() : if (name not in self.__coreData) \ and (not name.startswith( '_' )) : # Assume a user defined parameter. self.__userData[ name ] = Parameter( name = name, value = value ) def getParameters( thisData ) : nonlocal self acquireName( thisData ) acquireResetValue( thisData ) # The size record is tightly coupled to the reset value, but it needs a separate parsing implementation. goodResult = integerParameter( thisData, 'size', recordSize ) acquireDescription( thisData ) acquireSummary( thisData ) stringParameter( thisData, 'parent', recordParent, optional = True ) acquireUserParameters( thisData ) return goodResult return complexParameter( yamlData, Field.__KEY_NAME, getParameters ) def convertToLocal( self, parentRegister, removeOthers = False ) : """ Convert field to non-global, that is, dedicated bit maps to a single register. """ def removeOtherRegisters() : nonlocal parentRegister otherRegisters = [ x for x in self.__bitMap.destinations if x != parentRegister.bitMap.source ] assert len( otherRegisters ) == (len( self.__bitMap.destinations ) - 1) for thisRegister in otherRegisters : self.__bitMap.removeDestination( thisRegister ) if parentRegister.bitMap.source not in self.__bitMap.destinations : raise ConfigurationError( 'Field does not map to the register selected for parent' ) if not removeOthers : if (parentRegister.bitMap.source in self.__bitMap.destinations) \ and (len( self.__bitMap.destinations ) > 1) : raise ConfigurationError( 'Field maps to multiple registers' ) else : removeOtherRegisters() self.__parentRegister = parentRegister def convertToGlobal( self ) : """ Convert field to global, that is, allowing bit maps to multiple registers. """ self.__parentRegister = None def __encodeCoreParameters( self ) : """ Prepare core parameters for output to YAML. :return: List of encoded parameters. """ encodedParameters = [ parameter( 'size', self.__coreData[ 'size' ].value ), parameter( 'name', self.__coreData[ 'name' ].value ), parameter( 'resetValue', HexInt( self.__coreData[ 'resetValue' ].value ) ) ] if self.__coreData[ 'description' ] != '' : encodedParameters.append( parameter( 'description', self.__coreData[ 'description' ].value ) ) if self.__coreData[ 'summary' ] != '' : encodedParameters.append( parameter( 'summary', self.__coreData[ 'summary' ].value ) ) if not self.__coreData[ 'global' ].value : assert self.__parentRegister.canonicalId is not None encodedParameters.append( parameter( 'parent', self.__parentRegister.canonicalId ) ) return encodedParameters def __encodeUserParameters( self ) : """ Prepare user parameters for output to YAML. :return: List of encoded parameters. """ encodedParameters = list() for name, element in self.__userData.items() : encodedParameters.append( parameter( name, element.value ) ) return encodedParameters def to_yamlData( self ) : """ Generate YAML data structure representation of Field ready for use with yaml.dump. :return: YAML data structure. """ coreParameters = self.__encodeCoreParameters() userParameters = self.__encodeUserParameters() parameters = coreParameters + userParameters yamlData = { Field.__KEY_NAME : { } } for thisParameter in parameters : yamlData[ Field.__KEY_NAME ].update( thisParameter ) return yamlData PK&Nɀp##2registerMap/structure/elements/field/parameters.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.exceptions import ConfigurationError from registerMap.utility.observer import \ Observable, \ SizeChangeObserver from ..base.parameter import Parameter class BooleanParameter( Parameter ) : def __init__( self, name = None, value = True ) : super().__init__( name = name, value = value ) def validate( self, value ) : if not isinstance( value, bool ) : raise ConfigurationError( 'Must be specified as boolean' ) class GlobalParameter( Parameter ) : __parameterName = 'global' def __init__( self, element ) : self.__element = element super().__init__( name = self.__parameterName, value = self.__evaluateGlobal() ) def __evaluateGlobal( self ) : isGlobal = False if self.__element.parent is None : isGlobal = True return isGlobal @property def value( self ) : return self.__evaluateGlobal() class IntParameter( Parameter ) : def __init__( self, name = None, value = 0 ) : super().__init__( name = name, value = value ) def validate( self, value ) : if not isinstance( value, int ) : raise ConfigurationError( 'Must be an int, not {0}'.format( value ) ) class PositiveIntParameter( IntParameter ) : def __init__( self, name = None, value = 0 ) : super().__init__( name = name, value = value ) def validate( self, value ) : super().validate( value ) if value < 0 : raise ConfigurationError( 'Must be a positive int, not {0}'.format( value ) ) class StringParameter( Parameter ) : def __init__( self, name = None, value = '' ) : super().__init__( name = name, value = value ) def validate( self, value ) : if not isinstance( value, str ) : raise ConfigurationError( 'Must be a string, not {0}'.format( type( value ) ) ) class NameParameter( StringParameter ) : __parameterName = 'name' def __init__( self, value = 'unassigned' ) : super().__init__( name = self.__parameterName, value = value ) class ResetValueParameter( PositiveIntParameter ) : __parameterName = 'resetValue' def __init__( self, value = 0, size = 0 ) : """ :type value: int :type size: int """ self.__validateSize( size ) self.__numberBits = size super().__init__( name = self.__parameterName, value = value ) @property def maxValue( self ) : thisMax = pow( 2, self.__numberBits ) - 1 return thisMax @property def size( self ) : return self.__numberBits def __validateSize( self, value ) : if (not isinstance( value, int )) \ or (value < 0) : raise ConfigurationError( 'Size must be positive int, {0}'.format( value ) ) @size.setter def size( self, value ) : self.__validateSize( value ) self.__numberBits = value def validate( self, value ) : super().validate( value ) maxValue = self.maxValue if value > maxValue : raise ConfigurationError( 'Reset value cannot exceed number of bits of field, {0} maximum, {1} specified'.format( maxValue, value ) ) class SizeParameter( Parameter ) : __parameterName = 'size' def __init__( self, sizeResetParameter ) : super().__init__( name = self.__parameterName ) assert isinstance( sizeResetParameter, ResetValueParameter ) self.__sizeChangeObserver = SizeChangeObserver( self ) self.__sizeResetParameter = sizeResetParameter self.sizeChangeNotifier = Observable() @property def value( self ) : return self.__sizeResetParameter.size @value.setter def value( self, v ) : self.__sizeResetParameter.size = v def reviewSizeChange( self ) : # Cascade the size change self.sizeChangeNotifier.notifyObservers() PK&N6registerMap/structure/elements/field/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nz =registerMap/structure/elements/field/tests/testCanonicalId.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.module import Module from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.set.fieldSet import FieldSet from registerMap.structure.memory.configuration import MemoryConfiguration from .. import Field class TestFieldCanonicalId( unittest.TestCase ) : def setUp( self ) : self.fieldSet = FieldSet() self.memorySpace = MemoryConfiguration() def testGlobalCanonicalId( self ) : fieldName = 'thisField' testField = Field() testField[ 'name' ] = fieldName expectedCanonicalId = '{0}'.format( fieldName ) self.assertEqual( testField.canonicalId, expectedCanonicalId ) self.assertTrue( testField[ 'global' ] ) def testLocalCanonicalId( self ) : fieldName = 'thisField' moduleName = 'thisModule' registerName = 'thisRegister' parentModule = Module( self.memorySpace, self.fieldSet ) parentModule[ 'name' ] = moduleName parentRegister = RegisterInstance( self.memorySpace, parent = parentModule, setCollection = self.fieldSet ) parentRegister[ 'name' ] = registerName testField = Field( parent = parentRegister ) testField[ 'name' ] = fieldName expectedCanonicalId = '{0}.{1}.{2}'.format( moduleName, registerName, fieldName ) self.assertEqual( testField.canonicalId, expectedCanonicalId ) self.assertFalse( testField[ 'global' ] ) if __name__ == '__main__' : unittest.main() PK&NqZMEFF7registerMap/structure/elements/field/tests/testField.py""" Test BitField. """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConfigurationError from ..field import Field log = logging.getLogger( __name__ ) class TestFieldDescription( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = '' self.assertEqual( self.testField[ 'description' ], expectedValue ) def testDataAssignment( self ) : expectedValue = 'some description' self.assertNotEqual( expectedValue, self.testField[ 'description' ] ) self.testField[ 'description' ] = expectedValue self.assertEqual( self.testField[ 'description' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) class TestFieldGlobal( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertTrue( self.testField[ 'global' ] ) def testDataAssignment( self ) : class MockRegister : def __init__( self ) : self.canonicalId = 'someName' register = MockRegister() testField = Field( parent = register ) self.assertFalse( testField[ 'global' ] ) class TestFieldName( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = 'unassigned' self.assertEqual( self.testField[ 'name' ], expectedValue ) def testDataAssignment( self ) : expectedValue = 'new name' self.assertNotEqual( expectedValue, self.testField[ 'name' ] ) self.testField[ 'name' ] = expectedValue self.assertEqual( self.testField[ 'name' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) class TestFieldResetValue( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertEqual( self.testField[ 'resetValue' ], 0 ) def testDataAssignment( self ) : expectedValue = 0xd self.testField[ 'size' ] = 9 self.assertEqual( self.observer.updateCount, 1 ) self.assertNotEqual( expectedValue, self.testField[ 'resetValue' ] ) self.testField[ 'resetValue' ] = expectedValue actualValue = self.testField[ 'resetValue' ] self.assertEqual( actualValue, expectedValue ) self.assertEqual( self.observer.updateCount, 1 ) def testNonIntRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Must be an int' ) : self.testField[ 'resetValue' ] = '5' def testNegativeIntRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Must be a positive int' ) : self.testField[ 'resetValue' ] = -5 def testResetValueGreaterThanBitRangeRaises( self ) : self.testField[ 'size' ] = 2 with self.assertRaisesRegex( ConfigurationError, '^Reset value cannot exceed number of bits of field' ) : self.testField[ 'resetValue' ] = 8 def testResetValueAssignBitRangeUndefinedRaises( self ) : self.assertEqual( self.testField[ 'size' ], 0 ) with self.assertRaisesRegex( ConfigurationError, '^Reset value cannot exceed number of bits of field' ) : self.testField[ 'resetValue' ] = 8 class TestFieldSize( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = 0 self.assertEqual( self.testField[ 'size' ], expectedValue ) self.assertEqual( self.testField[ 'size' ], self.testField.sizeBits ) def testDataAssignment( self ) : expectedValue = 10 self.assertNotEqual( expectedValue, self.testField[ 'size' ] ) self.testField[ 'size' ] = expectedValue actualValue = self.testField[ 'size' ] self.assertEqual( actualValue, expectedValue ) self.assertEqual( self.observer.updateCount, 1 ) def testChangedValueNotifies( self ) : expectedValue = 15 self.assertNotEqual( self.testField[ 'size' ], expectedValue ) self.testField[ 'size' ] = expectedValue self.assertEqual( self.observer.updateCount, 1 ) class TestFieldSummary( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = '' self.assertEqual( self.testField[ 'summary' ], expectedValue ) def testDataAssignment( self ) : expectedValue = 'does something' self.assertNotEqual( expectedValue, self.testField[ 'summary' ] ) self.testField[ 'summary' ] = expectedValue self.assertEqual( self.testField[ 'summary' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) class TestFieldParametersProperty( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testDefaultCoreParametersProperty( self ) : expectedValue = { 'name' : 'unassigned', 'description' : '', 'global' : True, 'resetValue' : 0, 'size': 0, 'summary' : '', } actualValue = self.testField.coreParameters self.assertEqual( expectedValue, actualValue ) def testDefaultUserParametersProperty( self ) : expectedValue = dict() actualValue = self.testField.userParameters self.assertEqual( expectedValue, actualValue ) def testUserParametersProperty( self ) : expectedValue = { 'someValue': 123, } self.testField['someValue'] = 123 actualValue = self.testField.userParameters self.assertEqual( expectedValue, actualValue ) if __name__ == '__main__' : unittest.main() PK&NccLregisterMap/structure/elements/field/tests/testFieldLocalGlobalConversion.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from ..field import ConfigurationError class TestConvertToGlobal( unittest.TestCase ) : def setUp( self ) : self.setCollection = SetCollection() self.memory = MemoryConfiguration() self.register = RegisterInstance( self.memory, setCollection = self.setCollection ) self.testField = self.register.addField( 'fieldName', [ 0, 4 ], (0, 4) ) self.assertFalse( self.testField[ 'global' ] ) def testConvertLocalToGlobal( self ) : self.testField.convertToGlobal() self.assertTrue( self.testField[ 'global' ] ) class TestConvertToLocal( unittest.TestCase ) : def setUp( self ) : self.setCollection = SetCollection() self.memory = MemoryConfiguration() self.register = RegisterInstance( self.memory, setCollection = self.setCollection ) self.testField = self.register.addField( 'fieldName', [ 0, 4 ], (0, 4), isGlobal = True ) self.assertTrue( self.testField[ 'global' ] ) def testConvertGlobalToLocalSingleRegister( self ) : self.testField.convertToLocal( self.register ) self.assertFalse( self.testField[ 'global' ] ) def testMultipleRegistersRaises( self ) : register2 = RegisterInstance( self.memory, setCollection = self.setCollection ) register2.addField( 'fieldName', [ 0, 2 ], (5, 7), isGlobal = True ) with self.assertRaisesRegex( ConfigurationError, '^Field maps to multiple registers' ) : self.testField.convertToLocal( self.register ) def testAbsentRegister( self ) : register2 = RegisterInstance( self.memory, setCollection = self.setCollection ) newField = register2.addField( 'otherField', [ 0, 2 ], (5, 7), isGlobal = True ) with self.assertRaisesRegex( ConfigurationError, '^Field does not map to the register selected for parent' ) : newField.convertToLocal( self.register ) def testForceSingleParent( self ) : register2 = RegisterInstance( self.memory, setCollection = self.setCollection ) register2.addField( 'fieldName', [ 0, 2 ], (5, 7), isGlobal = True ) self.testField.convertToLocal( self.register, removeOthers = True ) self.assertFalse( self.testField[ 'global' ] ) self.assertNotIn( register2, self.testField.bitMap.destinations ) if __name__ == '__main__' : unittest.main() PK&N-@ @ ;registerMap/structure/elements/field/tests/testFieldSize.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from ..field import Field class TestFieldSizeParameter( unittest.TestCase ) : def setUp( self ) : self.fieldUnderTest = Field() def testDefaultSize( self ) : expectedSize = 0 actualSize = self.fieldUnderTest[ 'size' ] self.assertEqual( actualSize, expectedSize ) def testAssignSize( self ) : expectedSize = 15 self.assertNotEqual( self.fieldUnderTest, expectedSize ) self.fieldUnderTest[ 'size' ] = expectedSize actualSize = self.fieldUnderTest[ 'size' ] self.assertEqual( actualSize, expectedSize ) class TestFieldSizeParameterNotification( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.fieldUnderTest = Field() self.fieldUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testSizeChangeNotification( self ) : expectedSize = 15 self.assertNotEqual( self.fieldUnderTest, expectedSize ) self.fieldUnderTest[ 'size' ] = expectedSize actualSize = self.fieldUnderTest[ 'size' ] self.assertEqual( actualSize, expectedSize ) self.assertEqual( self.observer.updateCount, 1 ) class TestFieldSizeBitsMethod( unittest.TestCase ) : def setUp( self ) : self.fieldUnderTest = Field() def testDefaultSizeBits( self ) : expectedSize = 0 actualSize = self.fieldUnderTest.sizeBits self.assertEqual( actualSize, expectedSize ) def testAssignSize( self ) : expectedSize = 15 self.assertNotEqual( self.fieldUnderTest, expectedSize ) self.fieldUnderTest[ 'size' ] = expectedSize actualSizeBits = self.fieldUnderTest.sizeBits self.assertEqual( actualSizeBits, expectedSize ) if __name__ == '__main__' : unittest.main() PK&N5SKregisterMap/structure/elements/field/tests/testFieldUserDefinedParameter.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..field import Field class TestFieldUserDefinedParameter( unittest.TestCase ) : def setUp( self ) : self.fieldUnderTest = Field() def testAssignParameterOk( self ) : expectedValue = 'some value' self.fieldUnderTest[ 'my-parameter' ] = expectedValue self.assertEqual( expectedValue, self.fieldUnderTest[ 'my-parameter' ] ) def testBadParameterRaises( self ) : with self.assertRaisesRegex( KeyError, 'Field parameter not in core or user data' ) : self.fieldUnderTest[ 'bad-parameter' ] def testUnderscorePrefixAsserts( self ) : with self.assertRaises( AssertionError ) : self.fieldUnderTest[ '_my-parameter' ] = 2 if __name__ == '__main__' : unittest.main() PK&N2""8registerMap/structure/elements/field/tests/testYamlIo.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest.mock from registerMap.structure.elements.register import RegisterInstance from ..field import \ Field, \ ParseError from registerMap.structure.elements.tests.mockObserver import MockObserver log = logging.getLogger( __name__ ) class TestLoadSaveGlobalField( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testField = Field() self.testField.sizeChangeNotifier.addObserver( self.observer ) def testEncodeDecodeGlobalField( self ) : self.testField[ 'description' ] = 'some description' self.testField[ 'name' ] = 'f1' self.testField[ 'size' ] = 8 self.testField[ 'resetValue' ] = 0x5a self.testField[ 'summary' ] = 'a summary' self.assertTrue( self.testField[ 'global' ] ) encodedYamlData = self.testField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData ) self.assertEqual( decodedData[ 'description' ], self.testField[ 'description' ] ) self.assertEqual( decodedData[ 'name' ], self.testField[ 'name' ] ) self.assertEqual( decodedData[ 'resetValue' ], self.testField[ 'resetValue' ] ) self.assertEqual( decodedData[ 'summary' ], self.testField[ 'summary' ] ) self.assertTrue( decodedData[ 'global' ] ) def testEncodeDecodeLocalField( self ) : self.testField[ 'description' ] = 'some description' self.testField[ 'name' ] = 'f1' self.testField[ 'size' ] = 8 self.testField[ 'resetValue' ] = 0x5a self.testField[ 'summary' ] = 'a summary' self.assertTrue( self.testField[ 'global' ] ) encodedYamlData = self.testField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData ) self.assertEqual( decodedData[ 'description' ], self.testField[ 'description' ] ) self.assertEqual( decodedData[ 'name' ], self.testField[ 'name' ] ) self.assertEqual( decodedData[ 'resetValue' ], self.testField[ 'resetValue' ] ) self.assertEqual( decodedData[ 'summary' ], self.testField[ 'summary' ] ) self.assertTrue( decodedData[ 'global' ] ) def testOptionalDescription( self ) : self.testField[ 'name' ] = 'f1' self.testField[ 'size' ] = 8 self.testField[ 'resetValue' ] = 0x5a self.testField[ 'summary' ] = 'a summary' encodedYamlData = self.testField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData ) self.assertEqual( decodedData[ 'description' ], '' ) def testOptionalSummary( self ) : self.testField[ 'description' ] = 'some description' self.testField[ 'name' ] = 'f1' self.testField[ 'size' ] = 8 self.testField[ 'resetValue' ] = 0x5a encodedYamlData = self.testField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData ) self.assertEqual( decodedData[ 'description' ], self.testField[ 'description' ] ) self.assertEqual( decodedData[ 'name' ], self.testField[ 'name' ] ) self.assertEqual( decodedData[ 'resetValue' ], self.testField[ 'resetValue' ] ) self.assertEqual( decodedData[ 'summary' ], '' ) def testFieldLargerThanOneByte( self ) : self.testField[ 'name' ] = 'f1' self.testField[ 'size' ] = 11 encodedYamlData = self.testField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData ) self.assertEqual( decodedData[ 'name' ], self.testField[ 'name' ] ) self.assertEqual( decodedData[ 'size' ], self.testField[ 'size' ] ) class TestLoadSaveLocalField( unittest.TestCase ) : def setUp( self ) : self.parentRegister = self.generateRegister( 'registerName' ) self.sourceField = Field( parent = self.parentRegister ) @staticmethod def generateRegister( name ) : """ Generate mock parent register for the test. :param name: :return: """ thisRegister = unittest.mock.create_autospec( RegisterInstance ) pn = unittest.mock.PropertyMock( return_value = name ) type( thisRegister ).name = pn pci = unittest.mock.PropertyMock( return_value = name ) type( thisRegister ).canonicalId = pci return thisRegister def testEncodeDecodeLocalField( self ) : self.sourceField[ 'name' ] = 'f1' self.sourceField[ 'size' ] = 8 self.sourceField[ 'resetValue' ] = 0x5a self.assertFalse( self.sourceField[ 'global' ] ) self.assertEqual( self.sourceField.canonicalId, 'registerName.f1' ) encodedYamlData = self.sourceField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData, parentRegister = self.parentRegister ) self.assertFalse( decodedData[ 'global' ] ) self.assertEqual( decodedData.canonicalId, 'registerName.f1' ) def testDecodeMissingParentRaises( self ) : self.sourceField[ 'name' ] = 'f1' self.sourceField[ 'size' ] = 8 self.sourceField[ 'resetValue' ] = 0x5a self.assertFalse( self.sourceField[ 'global' ] ) self.assertEqual( self.sourceField.canonicalId, 'registerName.f1' ) encodedYamlData = self.sourceField.to_yamlData() with self.assertRaisesRegex( ParseError, '^Parent register not specified for YAML acquisition of a local field' ) : Field.from_yamlData( encodedYamlData ) def testDecodeWrongParentRaises( self ) : self.sourceField[ 'name' ] = 'f1' self.sourceField[ 'size' ] = 8 self.sourceField[ 'resetValue' ] = 0x5a self.assertFalse( self.sourceField[ 'global' ] ) self.assertEqual( self.sourceField.canonicalId, 'registerName.f1' ) otherRegister = self.generateRegister( 'otherRegister' ) encodedYamlData = self.sourceField.to_yamlData() with self.assertRaisesRegex( ParseError, '^Parent register does not match YAML specification' ) : Field.from_yamlData( encodedYamlData, parentRegister = otherRegister ) class TestLoadSaveUserDefinedParameters( unittest.TestCase ) : def setUp( self ) : self.parentRegister = self.generateRegister( 'registerName' ) self.sourceField = Field( parent = self.parentRegister ) @staticmethod def generateRegister( name ) : """ Generate mock parent register for the test. :param name: :return: """ thisRegister = unittest.mock.create_autospec( RegisterInstance ) pn = unittest.mock.PropertyMock( return_value = name ) type( thisRegister ).name = pn pci = unittest.mock.PropertyMock( return_value = name ) type( thisRegister ).canonicalId = pci return thisRegister def testEncodeDecodeUserDefinedParameters( self ) : expectedValue = 'some value' self.sourceField[ 'name' ] = 'f1' self.sourceField[ 'size' ] = 8 self.sourceField[ 'resetValue' ] = 0x5a self.assertFalse( self.sourceField[ 'global' ] ) self.assertEqual( self.sourceField.canonicalId, 'registerName.f1' ) self.sourceField[ 'my-parameter' ] = expectedValue encodedYamlData = self.sourceField.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedData = Field.from_yamlData( encodedYamlData, parentRegister = self.parentRegister ) self.assertEqual( expectedValue, decodedData[ 'my-parameter' ] ) if __name__ == '__main__' : unittest.main() PK&NAregisterMap/structure/elements/field/tests/parameters/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nv. # import unittest import registerMap.structure.elements.field.parameters as rmbp class TestBooleanParameter( unittest.TestCase ) : def setUp( self ) : self.p = rmbp.BooleanParameter( 'booleanParameter' ) self.assertTrue( self.p.value ) def testDataAssignment( self ) : self.p.value = False self.assertFalse( self.p.value ) def testNonBoolRaises( self ) : with self.assertRaisesRegex( rmbp.ConfigurationError, '^Must be specified as boolean' ) : self.p.value = 'true' if __name__ == '__main__' : unittest.main() PK&Nw1__LregisterMap/structure/elements/field/tests/parameters/testGlobalParameter.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field.parameters import GlobalParameter class MockElement : def __init__( self, parent ) : self.__parent = parent @property def parent( self ) : return self.__parent class TestGlobalParameter( unittest.TestCase ) : def testIsGlobal( self ) : mockElement = MockElement( None ) testParameter = GlobalParameter( mockElement ) self.assertTrue( testParameter.value ) def testIsNotGlobal( self ) : mockElement = MockElement( 'someName' ) testParameter = GlobalParameter( mockElement ) self.assertFalse( testParameter.value ) PK&Ny  IregisterMap/structure/elements/field/tests/parameters/testIntParameter.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field.parameters import \ ConfigurationError, \ IntParameter, \ PositiveIntParameter class TestIntParameter( unittest.TestCase ) : def typeUnderTest( self, value = 0 ) : """ Children must implement this method to define the parameter type to apply testing to. :return: Type of parameter for testing. """ return IntParameter( 'intParameter', value = value ) def testDefaultConstructorOk( self ) : self.typeUnderTest() def testConstructorNoneRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Must be an int' ) : self.typeUnderTest( value = None ) def testConstructorNonIntRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Must be an int' ) : self.typeUnderTest( value = '30' ) def testValueNonIntRaises( self ) : p = self.typeUnderTest() with self.assertRaisesRegex( ConfigurationError, '^Must be an int' ) : p.value = list() class TestPositiveIntParameter( TestIntParameter ) : def typeUnderTest( self, value = 0 ) : return PositiveIntParameter( 'positiveIntParameter', value = value ) def testNegativeValueRaises( self ) : p = self.typeUnderTest() with self.assertRaisesRegex( ConfigurationError, '^Must be a positive int' ) : p.value = -1 if __name__ == '__main__' : unittest.main() PK&NQ7= = PregisterMap/structure/elements/field/tests/parameters/testResetValueParameter.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field.parameters import \ ConfigurationError, \ ResetValueParameter from registerMap.structure.elements.field.tests.parameters.testIntParameter import TestPositiveIntParameter class TestResetValueParameter( TestPositiveIntParameter ) : def typeUnderTest( self, value = 0 ) : return ResetValueParameter( value = value ) def setUp( self ) : self.parameter = self.typeUnderTest() def testDefaultMaxValue( self ) : expectedValue = 0 actualValue = self.parameter.maxValue self.assertEqual( actualValue, expectedValue ) class TestResetValueParameterSize( unittest.TestCase ) : def testDefaultSize( self ) : p = ResetValueParameter() expectedValue = 0 actualValue = p.size self.assertEqual( actualValue, expectedValue ) def testConstructSize( self ) : expectedSize = 2 p = ResetValueParameter( size = expectedSize ) actualSize = p.size self.assertEqual( actualSize, expectedSize ) def testSetSize( self ) : expectedSize = 2 p = ResetValueParameter() self.assertNotEqual( p.size, expectedSize ) p.size = expectedSize self.assertEqual( p.size, expectedSize ) def testNegativeSetSizeRaises( self ) : p = ResetValueParameter() with self.assertRaisesRegex( ConfigurationError, '^Size must be positive int' ) : p.size = -1 def testNegativeConstructSizeRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Size must be positive int' ) : ResetValueParameter( size = -1 ) class TestResetValueParameterMaxValue( unittest.TestCase ) : def testMaxValue( self ) : p = ResetValueParameter( size = 2 ) self.assertEqual( p.maxValue, 3 ) if __name__ == '__main__' : unittest.main() PK&NU1registerMap/structure/elements/module/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .module import Module PK&N# 1registerMap/structure/elements/module/instance.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from ..base.parameter import \ ConstraintsParameter from ..base import \ IdentityElement from .interface import ModuleInterface class ModuleInstance( IdentityElement, ModuleInterface ) : """ Maintainer of RegisterInstances within a module. In a series module - a Module with multiple instances - there is a one to one correspondence between instances and ModuleInstance. """ __INSTANCE_PARAMETERS = { 'constraints', } __VALID_CONSTRAINTS = { 'fixedAddress', 'alignmentMemoryUnits', } def __init__( self, parent ) : super().__init__() self.__memory = parent.memory self.__parent = parent self.__previousElement = None self.__coreData = { 'constraints' : ConstraintsParameter( self.__memory, validConstraints = self.__VALID_CONSTRAINTS ), } @property def assignedMemoryUnits( self ) : return self.__parent.assignedMemoryUnits @property def baseAddress( self ) : if self.__previousElement.endAddress is not None : proposedValue = self.__previousElement.endAddress + 1 else : proposedValue = None value = self.__coreData[ 'constraints' ].value.applyAddressConstraints( proposedValue ) return value @property def canonicalId( self ) : # Append the instance base address to the parent module canonical id. value = '{0}[{1}]'.format( self.__parent.canonicalId, hex( self.baseAddress ) ) return value @property def endAddress( self ) : pass @property def memory( self ) : return self.__memory @property def offset( self ) : value = self.baseAddress - self.memory.baseAddress return value @property def previousElement( self ) : return self.__previousElement @previousElement.setter def previousElement( self, value ) : self.__previousElement = value @property def spanMemoryUnits( self ) : pass def __getitem__( self, item ) : if item in self.__INSTANCE_PARAMETERS : value = self.__coreData[ item ].value else : value = self.__parent[ item ] return value def __setitem__( self, key, value ) : if key in self.__INSTANCE_PARAMETERS : self.__coreData[ key ].value = value else : self.__parent[ key ] = value PK&NE 2registerMap/structure/elements/module/interface.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class ModuleInterface( metaclass = abc.ABCMeta ) : @property @abc.abstractmethod def assignedMemoryUnits( self ) : """ The number of memory units in the module or module instance. """ pass @property @abc.abstractmethod def baseAddress( self ) : """ The base (smallest numerical value) address of the module, or module instance. """ pass @property @abc.abstractmethod def canonicalId( self ) : pass @property @abc.abstractmethod def endAddress( self ) : """ The address of the last assigned memory unit in the module or module instance. In the case of a multibyte register, this would be the address of the last memory unit in the register (the address with the highest numerical value). """ pass @property @abc.abstractmethod def memory( self ) : """ Register map memory space. """ return self.__memory @property @abc.abstractmethod def offset( self ) : """ The offset of the module or module instance relative to the base address of the register map. """ pass @property @abc.abstractmethod def previousElement( self ) : """ The element preceding this element in the register map. """ pass @previousElement.setter @abc.abstractmethod def previousElement( self, value ) : """ Set the element preceding this element in the register map. :param value: :return: """ pass @property @abc.abstractmethod def spanMemoryUnits( self ) : """ The total number of memory units spanned by the module or module instance; including any gaps of unassigned memory units. In essence the span is the difference between the base address and end address of the module or module instance. eg. In a module with 4 registers totalling 4 bytes with gaps totalling 2 bytes, the span will be 6 bytes. """ pass @abc.abstractmethod def __getitem__( self, item ) : pass @abc.abstractmethod def __setitem__( self, key, value ) : pass PK&NXWHWH/registerMap/structure/elements/module/module.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging from registerMap.exceptions import \ ConfigurationError, \ ParseError from registerMap.structure.memory.element import \ AddressableMemoryElement, \ BitsMemoryElement from registerMap.export.io.yaml.parameters.encode import parameter from registerMap.export.io.yaml.parameters.parse import complexParameter from registerMap.utility.observer import \ AddressChangeObserver, \ Observable, \ SizeChangeObserver from ..base import \ IdentityElement, \ AddressObservableInterface, \ SizeObservableInterface from ..base.parameter import \ ConstraintsParameter, \ Parameter from ..register import RegisterInstance from .interface import ModuleInterface from .parameters import RegistersParameter log = logging.getLogger( __name__ ) class Module( ModuleInterface, IdentityElement, AddressObservableInterface, SizeObservableInterface ) : __DEFAULT_NUMBER_INSTANCES = 1 __DEFAULT_MODULE_SIZE_MEMORY_UNITS = 0 __YAML_NAME = 'module' def __init__( self, memorySpace, setCollection ) : super().__init__() self.addressChangeNotifier = Observable() self.sizeChangeNotifier = Observable() self.__addressObserver = AddressChangeObserver( self ) self.__sizeObserver = SizeChangeObserver( self ) self.__setCollection = setCollection self.__memory = memorySpace self.__previousModule = None # __element initialisation must be done before __coreData initialisation because it is needed by # RegistersParameter. self.__initialiseElements() self.__coreData = { 'constraints' : ConstraintsParameter( self.__memory ), 'description' : Parameter( 'description', '' ), 'instances' : Parameter( 'instances', self.__DEFAULT_NUMBER_INSTANCES ), 'name' : Parameter( 'name', None ), 'registers' : RegistersParameter( self ), 'summary' : Parameter( 'summary', '' ), } self.__coreData[ 'registers' ].addObserver( self.__sizeObserver ) self.__coreData[ 'instances' ].addObserver( self.__sizeObserver ) self.__userData = dict() self.__registerConstraintNotifiers() def __initialiseElements( self ) : self.__moduleInstance = BitsMemoryElement() self.__moduleInstance.sizeBits = self.__DEFAULT_MODULE_SIZE_MEMORY_UNITS * self.__memory.memoryUnitBits self.__element = { x : AddressableMemoryElement( self.__memory, sizeObject = self.__moduleInstance ) for x in range( self.__DEFAULT_NUMBER_INSTANCES ) } def __registerConstraintNotifiers( self ) : self.__memory.addressChangeNotifier.addObserver( self.__addressObserver ) self.__coreData[ 'constraints' ].value.addressChangeNotifier.addObserver( self.__addressObserver ) self.__coreData[ 'constraints' ].value.sizeChangeNotifier.addObserver( self.__sizeObserver ) @property def assignedMemoryUnits( self ) : """ :return: The number of memory units currently consumed by registers. """ totalSize = 0 for register in self.__coreData[ 'registers' ].value.values() : totalSize += register.sizeMemoryUnits return totalSize @property def baseAddress( self ) : """ Address of the first register of the module (the "base" address of the module), or the fixed address if a 'fixedAddress' constraint is applied. """ return self.__element[ 0 ].startAddress @property def canonicalId( self ) : canonicalName = self.__coreData[ 'name' ].value return canonicalName @property def endAddress( self ) : """ The last address of the last module instance. """ maxIndex = max( self.__element.keys() ) return self.__element[ maxIndex ].endAddress @property def memory( self ) : """ :return: Module local alias of for the memory space definitions of the register map. """ return self.__memory @property def offset( self ) : """ :return: The offset of the module relative to the base address of the register map. """ return self.baseAddress - self.__memory.baseAddress @property def previousElement( self ) : """ :return: The module preceding this module in memory. """ return self.__previousModule @previousElement.setter def previousElement( self, value ) : self.__previousModule = value # If the previous module changes address or size, then these events could both impact the address of the # current register. self.__previousModule.sizeChangeNotifier.addObserver( self.__addressObserver ) self.__previousModule.addressChangeNotifier.addObserver( self.__addressObserver ) self.reviewAddressChange() @property def spanMemoryUnits( self ) : """ :return: The current number of memory units spanned by the registers in the module. """ return self.__calculateTotalSpan() def addRegister( self, name ) : """ Create a new register of the specified name to be added to the module. :param name: Name of the register. :return: The added register. """ register = RegisterInstance( self.__memory, parent = self, setCollection = self.__setCollection ) register[ 'name' ] = name self.__validateAddedRegister( register ) # Don't add the register until all the checks have passed self.__setCollection.registerSet.add( register ) self.__coreData[ 'registers' ].value[ register[ 'name' ] ] = register log.debug( 'Notifying on register change in module' ) self.reviewSizeChange() return register def __validateAddedRegister( self, register ) : def checkSpan() : currentSpan = self.__calculateRegisterOnlySingleModuleSpan() if currentSpan is not None : newSpan = currentSpan + register.sizeMemoryUnits constrainedSize = self.__coreData[ 'constraints' ].value.applySizeConstraints( newSpan ) if constrainedSize < newSpan : raise ConfigurationError( 'Adding new register breaks fixed size constraint, {0}'.format( register.canonicalId ) ) def checkUniqueName() : foundRegisters = [ x[ 'name' ] for x in self.__coreData[ 'registers' ].value.values() if x[ 'name' ] == register[ 'name' ] ] if len( foundRegisters ) != 0 : raise ConfigurationError( 'Created register names must be unique within a module, {0}'.format( register[ 'name' ] ) ) checkUniqueName() checkSpan() def reviewSizeChange( self ) : numberInstances = self.__coreData[ 'instances' ].value if len( self.__element ) != numberInstances : # Number of instances has changed. # Can only increase the size, for now. assert self.__coreData[ 'instances' ].value > len( self.__element ) for x in range( len( self.__element ), numberInstances ) : self.__element[ x ] = AddressableMemoryElement( self.__memory, sizeObject = self.__moduleInstance ) newSpanMemoryUnits = self.__calculateSingleModuleSpan() if (newSpanMemoryUnits is not None) \ and ((newSpanMemoryUnits * self.__memory.memoryUnitBits) != self.__moduleInstance.sizeBits) : self.__moduleInstance.sizeBits = newSpanMemoryUnits * self.__memory.memoryUnitBits self.sizeChangeNotifier.notifyObservers() def reviewAddressChange( self ) : def updateFirstRegister() : nonlocal self if self.__coreData[ 'registers' ].firstElement is not None : self.__coreData[ 'registers' ].firstElement.endAddress = newStartAddress - 1 newStartAddress = self.__calculateStartAddress() if (newStartAddress is not None) \ and (newStartAddress != self.__element[ 0 ].startAddress) : self.__element[ 0 ].startAddress = newStartAddress updateFirstRegister() self.reviewSizeChange() self.addressChangeNotifier.notifyObservers() def __recalculateInstanceStartAddresses( self, singleInstanceSize ) : assert (len( self.__element ) == self.__coreData[ 'instances' ].value), \ 'Number of instances defined and instances realized is not the same' for index in range( 0, (len( self.__element ) - 1) ) : nextInstanceStartAddress = self.__coreData[ 'constraints' ].value.applyAddressConstraints( self.__element[ index ].startAddress + singleInstanceSize ) self.__element[ index + 1 ].startAddress = nextInstanceStartAddress def __calculateStartAddress( self ) : if (self.__previousModule is not None) and (self.__previousModule.endAddress is not None) : # Page register impact is calculate before application of constraints. This means that constraints could # still affect the address. eg. if address alignment modified the affect of page register on the address. proposedAddress = self.__previousModule.endAddress + 1 initialAddress = self.__memory.calculatePageRegisterImpact( proposedAddress ) else : initialAddress = None newAddress = self.__coreData[ 'constraints' ].value.applyAddressConstraints( initialAddress ) return newAddress def __calculateTotalSpan( self ) : singleModuleSpan = self.__calculateSingleModuleSpan() if (singleModuleSpan is not None) \ and (singleModuleSpan > self.__DEFAULT_MODULE_SIZE_MEMORY_UNITS) : self.__recalculateInstanceStartAddresses( singleModuleSpan ) maxIndex = max( self.__element.keys() ) finalSize = self.__element[ maxIndex ].endAddress - self.__element[ 0 ].startAddress + 1 else : finalSize = self.__DEFAULT_MODULE_SIZE_MEMORY_UNITS return finalSize def __calculateSingleModuleSpan( self ) : """ Calculate the span of a single module including size constraints. """ singleInstanceSize = self.__calculateRegisterOnlySingleModuleSpan() singleModuleSpan = self.__coreData[ 'constraints' ].value.applySizeConstraints( singleInstanceSize ) return singleModuleSpan def __calculateRegisterOnlySingleModuleSpan( self ) : """ Calculate the span of a single module for registers only (no size constraints). Assume all module are identical and do the calculation on the first module only. :return: number of memory units spanned. """ def sizeCalculationWithAddresses() : nonlocal self # Module size is the difference between the address of the first memory unit and the last memory unit # consumed by the last register startAddress = self.__element[ 0 ].startAddress endAddress = startAddress if len( self.__coreData[ 'registers' ].value ) == 0 : totalRegisterSpan = 0 else : for register in self.__coreData[ 'registers' ].value.values() : if (register.endAddress is not None) and (register.endAddress > endAddress) : endAddress = register.endAddress elif register.endAddress is None : log.debug( 'Register has None end address during span calculation, ' + repr( register[ 'name' ] ) ) totalRegisterSpan = endAddress - startAddress + 1 return totalRegisterSpan if self.__element[ 0 ].startAddress is not None : moduleRegisterSpan = sizeCalculationWithAddresses() else : moduleRegisterSpan = None return moduleRegisterSpan def __getitem__( self, item ) : if item in self.__coreData : value = self.__coreData[ item ].value elif item in self.__userData : value = self.__userData[ item ].value else : raise KeyError( 'Module parameter not in core or user data, {0} ({1})'.format( item, self.canonicalId ) ) return value def __setitem__( self, key, value ) : if key in self.__coreData : self.__coreData[ key ].value = value else : assert not key.startswith( '_' ) log.info( 'Creating user defined module parameter, {0}={1} ({2})'.format( key, value, self.canonicalId ) ) self.__userData[ key ] = Parameter( name = key, value = value ) # Assume that any change events in registers or constraints will be taken care of using registered observers of # the relevant objects. @classmethod def from_yamlData( cls, yamlData, memorySpace, setCollection, optional = False ) : module = cls( memorySpace, setCollection ) setCollection.moduleSet.add( module ) goodResult = module.__decodeModule( yamlData, optional ) if (not optional) \ and (not goodResult) : raise ParseError( 'Error parsing Module YAML data' ) return module def __decodeModule( self, yamlData, optional ) : def acquireConstraints( thisData ) : nonlocal self self.__coreData[ 'constraints' ] = ConstraintsParameter.from_yamlData( thisData, self.__memory, optional = True ) self.__registerConstraintNotifiers() def acquireDescription( thisData ) : nonlocal self self.__coreData[ 'description' ] = Parameter.from_yamlData( thisData, 'description', optional = True ) def acquireName( thisData ) : nonlocal self self.__coreData[ 'name' ] = Parameter.from_yamlData( thisData, 'name', optional = False ) def acquireRegisters( thisData ) : nonlocal self self.__coreData[ 'registers' ] = RegistersParameter.from_yamlData( thisData, self, self.__memory, self.__setCollection, optional = True, parent = self ) def acquireSummary( thisData ) : nonlocal self self.__coreData[ 'summary' ] = Parameter.from_yamlData( thisData, 'summary', optional = True ) def acquireUserDefinedParameters( thisData ) : nonlocal self for name, value in thisData.items() : # Only add user defined parameters if the YAML item is not in core data and doesn't begin with '_' # '_' are ready only data that should always be ignored on import. if (name not in self.__coreData) \ and (not name.startswith( '_' )) : self.__userData[ name ] = Parameter( name = name, value = value ) def getParameters( thisData ) : acquireConstraints( thisData ) acquireDescription( thisData ) acquireName( thisData ) acquireRegisters( thisData ) acquireSummary( thisData ) acquireUserDefinedParameters( thisData ) # Legacy artifact of not using exceptions to signal problems. return True return complexParameter( yamlData, Module.__YAML_NAME, getParameters, optional = optional ) def __encodeCoreParameters( self ) : """ Encode Module core parameters ready for use with yaml.dump. :return: List of encoded parameters. """ encodedParameters = list() encodedParameters.append( parameter( '_address', self.baseAddress ) ) encodedParameters.append( parameter( '_spanMemoryUnits', self.spanMemoryUnits ) ) for parameterData in self.__coreData.values() : parameterYamlData = parameterData.to_yamlData() encodedParameters.append( parameterYamlData ) return encodedParameters def __encodeUserParameters( self ) : """ Encode Module user parameters ready for use with yaml.dump. :return: List of encoded parameters. """ encodedParameters = list() for parameterData in self.__userData.values() : parameterYamlData = parameterData.to_yamlData() encodedParameters.append( parameterYamlData ) return encodedParameters def to_yamlData( self ) : """ Encode Module ready for use with yaml.dump. :return: Encoded YAML data structure """ yamlData = { self.__YAML_NAME : { } } coreParameters = self.__encodeCoreParameters() userParameters = self.__encodeUserParameters() parameters = coreParameters + userParameters for thisParameter in parameters : yamlData[ self.__YAML_NAME ].update( thisParameter ) return yamlData PK&NԚ 3registerMap/structure/elements/module/parameters.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.exceptions import ParseError from registerMap.utility.observer import \ Observable, \ SizeChangeObserver from ..base import ElementList from ..base.parameter import Parameter from ..register import RegisterInstance class RegistersParameter( Parameter ) : __parameterName = 'registers' class FirstRegister : def __init__( self, endAddress = None ) : self.addressChangeNotifier = Observable() self.sizeChangeNotifier = Observable() self.__endAddress = endAddress @property def endAddress( self ) : return self.__endAddress @endAddress.setter def endAddress( self, value ) : self.__endAddress = value # Notify observers that their address might need to change. self.addressChangeNotifier.notifyObservers() def __init__( self, owner ) : super().__init__( self.__parameterName, ElementList( self ) ) self.__owner = owner self.firstElement = None self.sizeObserver = SizeChangeObserver( self.__owner ) self.__createFirstRegisterPrevious() def __createFirstRegisterPrevious( self ) : if self.__owner.baseAddress is None : # Have to deal with None addresses as a special case thisEndAddress = None else : thisEndAddress = (self.__owner.baseAddress - 1) self.firstElement = RegistersParameter.FirstRegister( endAddress = thisEndAddress ) @classmethod def from_yamlData( cls, yamlData, owner, memorySpace, setCollection, optional = False, parent = None ) : parameter = cls( owner ) if (not optional) and (cls.__parameterName not in yamlData.keys()) : raise ParseError( 'Registers not defined in yaml data' ) elif cls.__parameterName in yamlData.keys() : for registerYamlData in yamlData[ cls.__parameterName ] : register = RegisterInstance.from_yamlData( registerYamlData, memorySpace, setCollection, parent = parent ) parameter.value[ register[ 'name' ] ] = register return parameter def to_yamlData( self ) : yamlData = { self.__parameterName : list() } for register in self.value.values() : yamlData[ self.__parameterName ].append( register.to_yamlData() ) return yamlData PK&N7registerMap/structure/elements/module/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NwSIregisterMap/structure/elements/module/tests/commonModuleInterfaceTests.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc import unittest.mock from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from .mocks import MockPreviousModule class CommonModuleInterfaceTests : class CommonTestInterface( metaclass = abc.ABCMeta ) : @abc.abstractmethod def constructInstanceUnderTest( self ) : """ Instantiate the module class object to be tested. :return: Instance of module class under test. """ pass class TestModuleConstraints( unittest.TestCase, metaclass = abc.ABCMeta ) : @abc.abstractmethod def constructInstanceUnderTest( self ) : """ Instantiate the module class object to be tested. :return: Instance of module class under test. """ pass def setUp( self ) : self.mock_memory = MemoryConfiguration() self.mock_setCollection = SetCollection() self.mock_previousElement = MockPreviousModule( endAddress = None ) self.moduleUnderTest = self.constructInstanceUnderTest() self.moduleUnderTest.previousElement = self.mock_previousElement def testFixedAddress( self ) : self.mock_previousElement.endAddress = 0x10 expectedValue = 0x15 self.assertGreater( expectedValue, self.mock_previousElement.endAddress ) self.assertNotEqual( expectedValue, self.moduleUnderTest.baseAddress ) self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest.baseAddress ) def testAlignedAddress( self ) : self.mock_previousElement.endAddress = 0x10 alignmentValue = 2 expectedValue = self.mock_previousElement.endAddress + 2 self.assertEqual( 0, (expectedValue % alignmentValue) ) self.assertLess( self.moduleUnderTest.baseAddress, expectedValue ) self.assertNotEqual( expectedValue, self.moduleUnderTest.baseAddress ) self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = alignmentValue self.assertEqual( expectedValue, self.moduleUnderTest.baseAddress ) def testFixedAddressConstraintPreviousElementNone( self ) : """ Fixed address constraint returns None if the previous element end address is None. """ self.mock_previousElement.endAddress = None expectedValue = 0x500 self.assertNotEqual( expectedValue, self.moduleUnderTest.baseAddress ) self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest.baseAddress ) class TestModuleOffsetProperty( unittest.TestCase, CommonTestInterface ) : def setUp( self ) : self.setCollection = SetCollection() self.mock_memory = MemoryConfiguration() self.mock_memory.baseAddress = 0x100 self.mock_previousElement = MockPreviousModule( endAddress = 0xff ) self.moduleUnderTest = self.constructInstanceUnderTest() self.moduleUnderTest.previousElement = self.mock_previousElement def testDefault( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = self.mock_memory.baseAddress self.assertEqual( self.mock_memory.baseAddress, self.moduleUnderTest.baseAddress ) self.assertEqual( 0, self.moduleUnderTest.offset ) def testAddressChanged( self ) : expectedAddress = 0x300 expectedOffset = expectedAddress - self.mock_memory.baseAddress self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedAddress self.assertEqual( expectedAddress, self.moduleUnderTest.baseAddress ) self.assertEqual( expectedOffset, self.moduleUnderTest.offset ) def testOffsetProperty( self ) : self.mock_previousElement.endAddress = 0x1ff expectedOffset = 0x100 expectedAddress = 0x200 self.assertEqual( expectedOffset, self.moduleUnderTest.offset ) self.assertEqual( expectedAddress, self.moduleUnderTest.baseAddress ) class TestModulePreviousElementProperty( unittest.TestCase, CommonTestInterface ) : def setUp( self ) : self.setCollection = SetCollection() self.mock_memory = MemoryConfiguration() self.mock_memory.baseAddress = 0x100 self.mock_previousElement = MockPreviousModule( endAddress = 0xff ) self.moduleUnderTest = self.constructInstanceUnderTest() def testPreviousElementAssignment( self ) : self.moduleUnderTest.previousElement = self.mock_previousElement self.assertEqual( self.mock_previousElement, self.moduleUnderTest.previousElement ) def testDefaultValue( self ) : self.assertIsNone( self.moduleUnderTest.previousElement ) def testAssignPreviousModuleNoneEndAddress( self ) : previousModule = MockPreviousModule() self.moduleUnderTest.previousElement = previousModule self.assertIsNone( self.moduleUnderTest.endAddress ) def testUpdatePreviousModuleEndAddress( self ) : previousModule = MockPreviousModule() self.moduleUnderTest.previousElement = previousModule expectedAddress = 0x10 previousModule.endAddress = expectedAddress - 1 self.assertEqual( expectedAddress, self.moduleUnderTest.baseAddress ) class TestModuleNameParameter( unittest.TestCase, CommonTestInterface ) : def setUp( self ) : self.setCollection = SetCollection() self.mock_memory = MemoryConfiguration() self.moduleUnderTest = self.constructInstanceUnderTest() def testDefaultValue( self ) : self.assertIsNone( self.moduleUnderTest[ 'name' ] ) def testNameAssignment( self ) : expectedValue = 'some-name' self.moduleUnderTest[ 'name' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest[ 'name' ] ) PK&N/軣4registerMap/structure/elements/module/tests/mocks.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.utility.observer import Observable class MockPreviousModule : def __init__( self, endAddress = None ) : self.addressChangeNotifier = Observable() self.sizeChangeNotifier = Observable() self.__endAddress = endAddress @property def endAddress( self ) : return self.__endAddress @endAddress.setter def endAddress( self, value ) : self.__endAddress = value self.sizeChangeNotifier.notifyObservers() PK&N_<<>registerMap/structure/elements/module/tests/testCanonicalId.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest import registerMap.structure.set.fieldSet as rmsfs import registerMap.structure.memory.configuration as rmm from .. import Module class TestModuleCananicalId( unittest.TestCase ) : def setUp( self ) : self.fieldSet = rmsfs.FieldSet() self.memorySpace = rmm.MemoryConfiguration() self.testModule = Module( self.memorySpace, self.fieldSet ) def testCanonicalIdOkay( self ) : expectedName = 'someName' self.testModule[ 'name' ] = expectedName self.assertEqual( self.testModule.canonicalId, expectedName ) if __name__ == '__main__' : unittest.main() PK&ND B B9registerMap/structure/elements/module/tests/testModule.py""" Unit test Module class """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest.mock from registerMap.exceptions import ConstraintError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.tests.mockObserver import MockObserver from ..module import \ Module, \ RegistersParameter from .commonModuleInterfaceTests import CommonModuleInterfaceTests from .mocks import MockPreviousModule log = logging.getLogger( __name__ ) class TestFirstRegister( unittest.TestCase ) : def setUp( self ) : pass def testGetEndAddressProperty( self ) : expectedValue = 0x10 firstRegister = RegistersParameter.FirstRegister( endAddress = expectedValue ) self.assertEqual( expectedValue, firstRegister.endAddress ) def testSetEndAddressProperty( self ) : expectedValue = 0x10 firstRegister = RegistersParameter.FirstRegister( endAddress = 0x20 ) self.assertNotEqual( firstRegister.endAddress, expectedValue ) firstRegister.endAddress = expectedValue self.assertEqual( expectedValue, firstRegister.endAddress ) class TestModule( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule[ 'name' ] = 'module' self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testDefaultMemory( self ) : self.assertEqual( 8, self.testModule.memory.memoryUnitBits ) self.assertIsNone( self.testModule.baseAddress ) self.assertIsNone( self.testModule.endAddress ) self.assertIsNone( self.testModule.previousElement ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) def testAddSingleRegister( self ) : self.assertEqual( 8, self.testModule.memory.memoryUnitBits ) r = self.testModule.addRegister( 'r1' ) self.assertIsNone( self.testModule.baseAddress ) self.assertIsNone( self.testModule.endAddress ) self.assertIsNone( self.testModule.previousElement ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 1, self.testModule.assignedMemoryUnits ) self.assertEqual( 'module.r1', r.canonicalId ) def testReviewAddressChangeEmptyModule( self ) : testModule = Module( self.testSpace, self.setCollection ) self.assertEqual( 0, len( testModule[ 'registers' ] ) ) # No exceptions should be thrown testModule.reviewAddressChange() self.assertIsNone( testModule.baseAddress ) def testReviewAddressChangeEmptyModuleFromYaml( self ) : testModule = Module( self.testSpace, self.setCollection ) self.assertEqual( 0, len( testModule[ 'registers' ] ) ) yamlData = testModule.to_yamlData() generatedModule = Module.from_yamlData( yamlData, self.testSpace, self.setCollection ) # No exceptions should be thrown generatedModule.reviewAddressChange() self.assertIsNone( generatedModule.baseAddress ) class TestModuleWithPreviousModule( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x10 ) self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule.previousElement = self.previousModule self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testDefaultMemory( self ) : self.assertEqual( 8, self.testModule.memory.memoryUnitBits ) self.assertEqual( (self.previousModule.endAddress + 1), self.testModule.baseAddress ) # size 0 implies the end address of the module must be "before" the base address. self.assertEqual( (self.testModule.baseAddress - 1), self.testModule.endAddress ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) def testAddSingleRegister( self ) : self.assertEqual( 8, self.testModule.memory.memoryUnitBits ) self.testModule.addRegister( 'r1' ) self.assertEqual( (self.previousModule.endAddress + 1), self.testModule.baseAddress ) # size 1 implies the end address of the module must be the same as the base address. self.assertEqual( self.testModule.baseAddress, self.testModule.endAddress ) self.assertEqual( 1, self.testModule.spanMemoryUnits ) self.assertEqual( 1, self.testModule.assignedMemoryUnits ) class TestModuleConstraints( CommonModuleInterfaceTests.TestModuleConstraints ) : def constructInstanceUnderTest( self ) : testModule = Module( self.mock_memory, self.mock_setCollection ) self.mock_observer = MockObserver() testModule.sizeChangeNotifier.addObserver( self.mock_observer ) testModule.addressChangeNotifier.addObserver( self.mock_observer ) return testModule def testAddRegisterOverFixedSizeRaises( self ) : self.assertEqual( 0, self.moduleUnderTest.spanMemoryUnits ) self.assertEqual( 0, self.moduleUnderTest.assignedMemoryUnits ) self.assertEqual( 8, self.mock_memory.memoryUnitBits ) self.mock_previousElement.endAddress = 0x10 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 3 r1 = self.moduleUnderTest.addRegister( 'r1' ) r1.addField( 'f1', [ 0, 10 ], (0, 10) ) self.moduleUnderTest.addRegister( 'r2' ) self.assertEqual( 3, self.moduleUnderTest.spanMemoryUnits ) with self.assertRaisesRegex( ConstraintError, '^Fixed size exceeded' ) : # A register has a size of one memory unit even if it has no bit fields. # So adding a third register must exceed the size limit self.moduleUnderTest.addRegister( 'r3' ) class TestModuleDescription( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertEqual( '', self.testModule[ 'description' ] ) class TestModuleNameParameter( CommonModuleInterfaceTests.TestModuleNameParameter ) : def constructInstanceUnderTest( self ) : testModule = Module( self.mock_memory, self.setCollection ) self.observer = MockObserver() testModule.sizeChangeNotifier.addObserver( self.observer ) testModule.addressChangeNotifier.addObserver( self.observer ) return testModule class TestModuleOffsetProperty( CommonModuleInterfaceTests.TestModuleOffsetProperty ) : def constructInstanceUnderTest( self ) : moduleUnderTest = Module( self.mock_memory, self.setCollection ) moduleUnderTest.addRegister( 'r1' ) return moduleUnderTest class TestModulePageRegisterInteraction( unittest.TestCase ) : def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.previousModule = MockPreviousModule( endAddress = 0 ) self.testModule.previousElement = self.previousModule def testModuleOnPageRegister( self ) : self.assertEqual( 32, self.testSpace.addressBits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.previousModule.endAddress = 0x27b log.debug( 'Mock previous module end address: ' + hex( self.previousModule.endAddress ) ) self.assertEqual( 0x27b, self.previousModule.endAddress ) log.debug( 'Test module start address no page size: ' + hex( self.testModule.baseAddress ) ) log.debug( 'Test module end address no page size: ' + hex( self.testModule.endAddress ) ) self.assertEqual( 0x27c, self.testModule.baseAddress ) self.testSpace.pageSize = 0x80 log.debug( 'Test module start address page size {0}: {1}'.format( hex( self.testSpace.pageSize ), hex( self.testModule.baseAddress ) ) ) log.debug( 'Test module end address page size {0}: {1}'.format( hex( self.testSpace.pageSize ), hex( self.testModule.endAddress ) ) ) self.assertEqual( 0x280, self.testModule.baseAddress ) class TestModulePreviousModule( CommonModuleInterfaceTests.TestModulePreviousElementProperty ) : def constructInstanceUnderTest( self ) : testModule = Module( self.mock_memory, self.setCollection ) self.observer = MockObserver() testModule.sizeChangeNotifier.addObserver( self.observer ) testModule.addressChangeNotifier.addObserver( self.observer ) return testModule class TestModuleSizePreviousConcreteAddresses( unittest.TestCase ) : # Module size is the number of memory units spanned by registers from the lowest memory unit to the highest # memory unit. # - If a module has a fixed address then the lowest memory unit is always the fixed address. # - If a page size is specified, then register addresses must miss paging registers (a fixed address on a page # register must raise). def setUp( self ) : self.observer = MockObserver() self.previousModule = MockPreviousModule( endAddress = 0x10 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule.previousElement = self.previousModule self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) def testContiguousRegisters( self ) : self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) r1 = self.testModule.addRegister( 'r1' ) self.assertEqual( 1, self.testModule.spanMemoryUnits ) self.assertEqual( 1, self.testModule.assignedMemoryUnits ) r1.addField( 'f1', [ 0, 10 ], [ 0, 10 ] ) self.assertEqual( 2, self.testModule.spanMemoryUnits ) self.assertEqual( 2, self.testModule.assignedMemoryUnits ) r2 = self.testModule.addRegister( 'r2' ) self.assertEqual( 3, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) def testDiscontiguousRegisters( self ) : self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertEqual( (self.previousModule.endAddress + 1), self.testModule.baseAddress ) r1 = self.testModule.addRegister( 'r1' ) r1.addField( 'f1', [ 0, 10 ], (0, 10) ) self.assertEqual( 2, self.testModule.spanMemoryUnits ) self.assertEqual( 2, self.testModule.assignedMemoryUnits ) r2 = self.testModule.addRegister( 'r2' ) self.assertEqual( 1, r2.sizeMemoryUnits ) self.assertEqual( 3, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) expectedAddress = 0x15 r2[ 'constraints' ][ 'fixedAddress' ] = expectedAddress self.assertEqual( r2.startAddress, expectedAddress ) self.assertEqual( (expectedAddress - self.testModule.baseAddress + 1), self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) def testDiscontiguousRegistersWithMultiunitRegister( self ) : self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertEqual( (self.previousModule.endAddress + 1), self.testModule.baseAddress ) r1 = self.testModule.addRegister( 'r1' ) self.assertEqual( 1, self.testModule.spanMemoryUnits ) r2 = self.testModule.addRegister( 'r2' ) r2.addField( 'f1', [ 0, 10 ], (0, 10) ) self.assertEqual( 2, r2.sizeMemoryUnits ) self.assertEqual( 3, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) expectedAddress = 0x15 r2[ 'constraints' ][ 'fixedAddress' ] = expectedAddress self.assertEqual( expectedAddress, r2.startAddress ) self.assertEqual( 6, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) class TestModuleSizePreviousNoneAddresses( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.previousModule = MockPreviousModule( endAddress = None ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule.previousElement = self.previousModule self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testDiscontiguousRegisters( self ) : self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 0, self.testModule.assignedMemoryUnits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertIsNone( self.testModule.baseAddress ) r1 = self.testModule.addRegister( 'r1' ) r1.addField( 'f1', [ 0, 10 ], (0, 10) ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 2, self.testModule.assignedMemoryUnits ) r2 = self.testModule.addRegister( 'r2' ) self.assertEqual( 1, r2.sizeMemoryUnits ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) expectedAddress = 0x15 r2[ 'constraints' ][ 'fixedAddress' ] = expectedAddress self.assertEqual( r2.startAddress, expectedAddress ) self.assertEqual( 0, self.testModule.spanMemoryUnits ) self.assertEqual( 3, self.testModule.assignedMemoryUnits ) class TestModuleSpanPreviousAddressChange( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x0 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testModule = Module( self.testSpace, self.setCollection ) self.testModule.previousElement = self.previousModule self.observer = MockObserver() self.testModule.sizeChangeNotifier.addObserver( self.observer ) self.testModule.addressChangeNotifier.addObserver( self.observer ) def testSpanAfterPreviousAddressChange( self ) : r1 = self.testModule.addRegister( 'r1' ) r1[ 'constraints' ][ 'fixedAddress' ] = 0x15 self.previousModule.endAddress = 0x10 # Because of the fixedAddress constraint on the register, the module span is implicitly a function of the # base address and the fixed address constraint. self.assertEqual( 0x11, self.testModule.baseAddress ) self.assertEqual( 5, self.testModule.spanMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&NQAregisterMap/structure/elements/module/tests/testModuleInstance.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from ..instance import ModuleInstance from ..module import Module from .commonModuleInterfaceTests import CommonModuleInterfaceTests class TestModuleInstance( unittest.TestCase ) : def setUp( self ) : self.mock_memory = unittest.mock.MagicMock() self.mock_moduleParent = unittest.mock.create_autospec( Module ) self.mock_moduleParent.canonicalId = 'one.two' self.mock_moduleParent.memory = self.mock_memory self.elementUnderTest = ModuleInstance( self.mock_moduleParent ) self.elementUnderTest[ 'name' ] = 'm1' def testAssignedMemoryUnitsProperty( self ) : self.mock_moduleParent.assignedMemoryUnits = 5 self.assertEqual( self.mock_moduleParent.assignedMemoryUnits, self.elementUnderTest.assignedMemoryUnits ) def testCanonicalIdProperty( self ) : self.mock_previousElement = unittest.mock.MagicMock() self.mock_previousElement.endAddress = 0x100 self.elementUnderTest.previousElement = self.mock_previousElement self.assertEqual( 0x101, self.elementUnderTest.baseAddress ) self.assertEqual( 'one.two[0x101]', self.elementUnderTest.canonicalId ) def testMemoryProperty( self ) : self.assertEqual( self.mock_memory, self.elementUnderTest.memory ) class TestModuleInstanceBaseAddressProperty( unittest.TestCase ) : def setUp( self ) : self.mock_memory = unittest.mock.MagicMock() self.mock_previousElement = unittest.mock.MagicMock() self.mock_previousElement.endAddress = None self.mock_moduleParent = unittest.mock.create_autospec( Module ) self.mock_moduleParent.canonicalId = 'one.two' self.mock_moduleParent.memory = self.mock_memory self.elementUnderTest = ModuleInstance( self.mock_moduleParent ) self.elementUnderTest[ 'name' ] = 'm1' self.elementUnderTest.previousElement = self.mock_previousElement def testDefault( self ) : """ With no constraints and no previous element specified, the base address can only be `None`. """ self.assertIsNone( self.elementUnderTest.baseAddress ) def testNoConstraintsNonePreviousEndAddress( self ) : """ With no constraints applied and a previous element with undefined end address, the base address can only be `None`. """ self.mock_previousElement.endAddress = None self.elementUnderTest.previousElement = self.mock_previousElement self.assertIsNone( self.elementUnderTest.baseAddress ) def testNoConstraintsPreviousEndAddressDefined( self ) : """ With no constraints applied and a previous element with defined end address, the base address can only be the next address. """ self.mock_previousElement.endAddress = 0x100 expectedValue = self.mock_previousElement.endAddress + 1 self.assertEqual( expectedValue, self.elementUnderTest.baseAddress ) class TestModuleInstanceConstraints( CommonModuleInterfaceTests.TestModuleConstraints ) : def constructInstanceUnderTest( self ) : self.mock_moduleParent = unittest.mock.create_autospec( Module ) self.mock_moduleParent.canonicalId = 'one.two' self.mock_moduleParent.memory = self.mock_memory elementUnderTest = ModuleInstance( self.mock_moduleParent ) elementUnderTest[ 'name' ] = 'm1' return elementUnderTest class TestModuleInstanceOffsetProperty( CommonModuleInterfaceTests.TestModuleOffsetProperty ) : def constructInstanceUnderTest( self ) : self.mock_moduleParent = unittest.mock.create_autospec( Module ) self.mock_moduleParent.canonicalId = 'one.two' self.mock_moduleParent.memory = self.mock_memory moduleUnderTest = ModuleInstance( self.mock_moduleParent ) moduleUnderTest[ 'name' ] = 'm1' return moduleUnderTest class TestModuleInstancePreviousElementProperty( CommonModuleInterfaceTests.TestModulePreviousElementProperty ) : def constructInstanceUnderTest( self ) : self.mock_moduleParent = unittest.mock.create_autospec( Module ) self.mock_moduleParent.memory = self.mock_memory elementUnderTest = ModuleInstance( self.mock_moduleParent ) elementUnderTest[ 'name' ] = 'm1' return elementUnderTest class TestModuleNameParameter( CommonModuleInterfaceTests.TestModuleNameParameter ) : def constructInstanceUnderTest( self ) : self.mock_moduleParent = Module( self.mock_memory, self.setCollection ) elementUnderTest = ModuleInstance( self.mock_moduleParent ) return elementUnderTest def testParentNameAssignment( self ) : """ A name assigned to a module instance assigns the name to the parent module. """ expectedValue = 'some-name' self.moduleUnderTest[ 'name' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest[ 'name' ] ) self.assertEqual( expectedValue, self.mock_moduleParent[ 'name' ] ) if __name__ == '__main__' : unittest.main() PK&NЦJregisterMap/structure/elements/module/tests/testModuleMultipleInstances.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.tests.mockObserver import MockObserver from ..module import Module from .mocks import MockPreviousModule class TestModuleMultipleInstances( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x10 ) self.sizeObserver = MockObserver() self.addressObserver = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest[ 'name' ] = 'module' self.moduleUnderTest.sizeChangeNotifier.addObserver( self.sizeObserver ) self.moduleUnderTest.addressChangeNotifier.addObserver( self.addressObserver ) self.moduleUnderTest.previousElement = self.previousModule r1 = self.moduleUnderTest.addRegister( 'r1' ) r1.addField( 'r1f1', (2, 4) ) r1.addField( 'r1f2', (5, 7) ) r2 = self.moduleUnderTest.addRegister( 'r2' ) r2.addField( 'r2f1', (2, 9) ) r2.addField( 'r2f2', (13, 18) ) def testSingleInstanceSpan( self ) : self.assertEqual( 1, self.moduleUnderTest[ 'instances' ] ) expectedSize = 4 self.assertEqual( expectedSize, self.moduleUnderTest.spanMemoryUnits ) def testMultipleInstanceContinuousSpan( self ) : # Module in the series are immediately adjacent to each other. self.assertEqual( 1, self.moduleUnderTest[ 'instances' ] ) singleInstanceSize = self.moduleUnderTest.spanMemoryUnits self.moduleUnderTest[ 'instances' ] = 4 self.assertEqual( 4, self.moduleUnderTest[ 'instances' ] ) expectedMultipleInstanceSize = self.moduleUnderTest[ 'instances' ] * singleInstanceSize self.assertEqual( expectedMultipleInstanceSize, self.moduleUnderTest.spanMemoryUnits ) def testInstanceChangeNotifiesObservers( self ) : self.assertEqual( 4, self.sizeObserver.updateCount ) self.assertEqual( 1, self.addressObserver.updateCount ) self.moduleUnderTest[ 'instances' ] = 10 self.assertTrue( 5, self.sizeObserver.updateCount ) self.assertTrue( 2, self.addressObserver.updateCount ) class TestModuleInstanceAddresses( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x10 ) self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest[ 'name' ] = 'm1' self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.addressChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.previousElement = self.previousModule self.m2 = Module( self.testSpace, self.setCollection ) self.m2.previousElement = self.moduleUnderTest def testDefaultMultipleInstanceAddress( self ) : """ Since a module has no size until registers are added, changing the number of instances consumes doesn't change the addresses. """ self.assertEqual( 0x11, self.moduleUnderTest.baseAddress ) self.assertEqual( 0x11, self.m2.baseAddress ) self.moduleUnderTest[ 'instances' ] = 4 self.assertEqual( 0x11, self.moduleUnderTest.baseAddress ) self.assertEqual( 0x11, self.m2.baseAddress ) class TestModuleInstancesConstraints( unittest.TestCase ) : def setUp( self ) : self.mockPreviousModule = MockPreviousModule( endAddress = 0x10 ) self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest[ 'name' ] = 'module' self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.addressChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.previousElement = self.mockPreviousModule r1 = self.moduleUnderTest.addRegister( 'r1' ) r1.addField( 'r1f1', (2, 4) ) r1.addField( 'r1f2', (5, 7) ) r2 = self.moduleUnderTest.addRegister( 'r2' ) r2.addField( 'r2f1', (2, 10) ) self.assertEqual( 3, self.moduleUnderTest.spanMemoryUnits ) def testAlignmentConstrainedInstancesSpan( self ) : self.assertEqual( 0x10, self.mockPreviousModule.endAddress ) # Prior to instances or alignment the span is the size of a single module. self.assertEqual( 3, self.moduleUnderTest.spanMemoryUnits ) numberInstances = 4 # Applying instances and the size is the instance multiple of the single module size. self.moduleUnderTest[ 'instances' ] = numberInstances self.assertEqual( 12, self.moduleUnderTest.spanMemoryUnits ) alignment = 4 self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = alignment # 15 = (3 * 4 [span caused by alignment]) + 3 [last instance span] expectedInstancesSpan = 15 self.assertEqual( expectedInstancesSpan, self.moduleUnderTest.spanMemoryUnits ) def testFixedSizeConstrainedInstancesSpan( self ) : expectedModuleSize = 10 numberInstances = 4 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = expectedModuleSize self.assertEqual( expectedModuleSize, self.moduleUnderTest.spanMemoryUnits ) self.moduleUnderTest[ 'instances' ] = numberInstances expectedInstancesSpan = expectedModuleSize * numberInstances self.assertEqual( expectedInstancesSpan, self.moduleUnderTest.spanMemoryUnits ) def testFixedSizeAndAlignmentInstancesSpan( self ) : numberInstances = 4 expectedModuleSize = 5 self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = expectedModuleSize # Expect 8 memory units to be consumed by each module in the series, except the last module. # The next module could start at the next available memory unit, unless it also has an alignment constraint (which # would be sensible, but not necessary). self.assertEqual( expectedModuleSize, self.moduleUnderTest.spanMemoryUnits ) self.moduleUnderTest[ 'instances' ] = numberInstances expectedInstancesSpan = 8 * (numberInstances - 1) + expectedModuleSize self.assertEqual( expectedInstancesSpan, self.moduleUnderTest.spanMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&NgWCregisterMap/structure/elements/module/tests/testModuleParameters.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import unittest import registerMap.structure.elements.base as rmbs import registerMap.structure.memory.configuration as rmms from registerMap.structure.set import SetCollection from ..module import \ Module, \ ParseError, \ RegisterInstance from ..parameters import RegistersParameter class TestModuleRegistersParameter( unittest.TestCase ) : def setUp( self ) : self.sourceCollection = SetCollection() self.memorySpace = rmms.MemoryConfiguration() self.module = Module( self.memorySpace, self.sourceCollection ) self.acquiredCollection = SetCollection() def testInitialization( self ) : p = RegistersParameter( self.module ) self.assertEqual( p.name, 'registers' ) self.assertTrue( isinstance( p.value, rmbs.ElementList ) ) def testEmptyBitFieldsToYamlData( self ) : p = RegistersParameter( self.module ) expectedYamlData = { 'registers' : list() } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testSingleRegisterToYamlData( self ) : p = RegistersParameter( self.module ) p.value[ 'r1' ] = self.createRegister( 'r1' ) expectedYamlData = { 'registers' : [ p.value[ 'r1' ].to_yamlData() ] } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testMultipleRegistersToYamlData( self ) : p = RegistersParameter( self.module ) p.value[ 'r1' ] = self.createRegister( 'r1' ) p.value[ 'r2' ] = self.createRegister( 'r2', 0x12 ) expectedYamlData = { 'registers' : [ p.value[ 'r1' ].to_yamlData(), p.value[ 'r2' ].to_yamlData() ] } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def createRegister( self, name, fixedAddress = 0x10 ) : register = RegisterInstance( self.memorySpace, setCollection = self.sourceCollection ) register[ 'constraints' ][ 'fixedAddress' ] = fixedAddress register[ 'description' ] = 'some description' register[ 'mode' ] = 'ro' register[ 'name' ] = name register[ 'public' ] = False register[ 'summary' ] = 'a summary' register.addField( 'f1', [ 3, 5 ], (0, 2) ) register.addField( 'f2', [ 7, 7 ], (0, 0) ) return register def testFromGoodYamlData( self ) : p = RegistersParameter( self.module ) p.value[ 'r1' ] = self.createRegister( 'r1' ) p.value[ 'r2' ] = self.createRegister( 'r2', 0x12 ) yamlData = p.to_yamlData() gp = RegistersParameter.from_yamlData( yamlData, self.module, self.memorySpace, self.acquiredCollection ) self.assertEqual( gp.value[ 'r1' ][ 'fields' ][ 'f1' ][ 'name' ], 'f1' ) self.assertEqual( gp.value[ 'r1' ][ 'fields' ][ 'f1' ][ 'size' ], 3 ) self.assertEqual( gp.value[ 'r1' ][ 'fields' ][ 'f2' ][ 'name' ], 'f2' ) self.assertEqual( gp.value[ 'r1' ][ 'fields' ][ 'f2' ][ 'size' ], 1 ) self.assertEqual( gp.value[ 'r2' ][ 'fields' ][ 'f1' ][ 'name' ], 'f1' ) self.assertEqual( gp.value[ 'r2' ][ 'fields' ][ 'f1' ][ 'size' ], 3 ) self.assertEqual( gp.value[ 'r2' ][ 'fields' ][ 'f2' ][ 'name' ], 'f2' ) self.assertEqual( gp.value[ 'r2' ][ 'fields' ][ 'f2' ][ 'size' ], 1 ) def testFromBadYamlData( self ) : yamlData = { 'mode' : 'ro' } with self.assertRaisesRegex( ParseError, '^Registers not defined in yaml data' ) : RegistersParameter.from_yamlData( yamlData, self.module, self.memorySpace, self.acquiredCollection ) def testOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } gp = RegistersParameter.from_yamlData( yamlData, self.module, self.memorySpace, self.sourceCollection, optional = True ) if __name__ == '__main__' : unittest.main() PK&NjjJregisterMap/structure/elements/module/tests/testModuleRegisterAddresses.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.tests.mockObserver import MockObserver from .mocks import MockPreviousModule from ..module import \ ConfigurationError, \ Module class TestModuleAddRegisterNoneAddresses( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = None ) self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.addressChangeNotifier.addObserver( self.observer ) def testAddSingleRegister( self ) : expectedName = 'r1' self.assertEqual( 0, len( self.moduleUnderTest[ 'registers' ] ) ) addedRegister = self.moduleUnderTest.addRegister( expectedName ) self.assertEqual( 1, len( self.moduleUnderTest[ 'registers' ] ) ) self.assertEqual( expectedName, self.moduleUnderTest[ 'registers' ][ expectedName ][ 'name' ] ) # The addRegister method returns the created register self.assertEqual( addedRegister, self.moduleUnderTest[ 'registers' ][ expectedName ] ) self.assertIsNone( addedRegister.startAddress ) def testAddDuplicateRegisterRaises( self ) : # A register name is unique to its module expectedName = 'r1' self.moduleUnderTest.addRegister( expectedName ) with self.assertRaisesRegex( ConfigurationError, '^Created register names must be unique within a module' ) : self.moduleUnderTest.addRegister( expectedName ) def testAddMultipleRegistersWithSubsequentConcreteAddress( self ) : r1 = self.moduleUnderTest.addRegister( 'r1' ) self.assertIsNone( r1.startAddress ) r2 = self.moduleUnderTest.addRegister( 'r2' ) self.assertIsNone( r2.startAddress ) previousModule = MockPreviousModule( endAddress = 0x10 ) self.moduleUnderTest.previousElement = previousModule self.assertEqual( 0x11, self.moduleUnderTest.baseAddress ) self.assertEqual( 0x11, r1.startAddress ) self.assertEqual( 0x12, r2.startAddress ) class TestModuleAddRegisterConcreteAddresses( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x10 ) self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.moduleUnderTest.addressChangeNotifier.addObserver( self.observer ) def testAddSingleRegister( self ) : expectedName = 'r1' self.assertEqual( 0, len( self.moduleUnderTest[ 'registers' ] ) ) addedRegister = self.moduleUnderTest.addRegister( expectedName ) self.assertEqual( 1, len( self.moduleUnderTest[ 'registers' ] ) ) self.assertEqual( expectedName, self.moduleUnderTest[ 'registers' ][ expectedName ][ 'name' ] ) # The addRegister method returns the created register self.assertEqual( addedRegister, self.moduleUnderTest[ 'registers' ][ expectedName ] ) self.assertEqual( self.moduleUnderTest.baseAddress, addedRegister.startAddress ) def testAddRegisterAfterMultibyte( self ) : r1 = self.moduleUnderTest.addRegister( 'r1' ) r1.addField( 'f1', (0, 10) ) self.assertEqual( self.moduleUnderTest.baseAddress, r1.startAddress ) self.assertEqual( 2, r1.sizeMemoryUnits ) r2 = self.moduleUnderTest.addRegister( 'r2' ) expectedR2Address = self.moduleUnderTest.baseAddress + r1.sizeMemoryUnits self.assertEqual( expectedR2Address, r2.startAddress ) if __name__ == '__main__' : unittest.main() PK&NiMregisterMap/structure/elements/module/tests/testModuleUserDefinedParameter.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from ..module import Module class TestModuleUserDefinedParameter( unittest.TestCase ) : def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) def testAssignUserParameterOk( self ) : expectedValue = 'some value' self.moduleUnderTest[ 'my-parameter' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest[ 'my-parameter' ] ) def testBadParameterRaises( self ) : with self.assertRaisesRegex( KeyError, 'Module parameter not in core or user data' ) : self.moduleUnderTest[ 'bad-parameter' ] def testUnderscorePrefixAsserts( self ) : with self.assertRaises( AssertionError ) : self.moduleUnderTest[ '_my-parameter' ] = 2 if __name__ == '__main__' : unittest.main() PK&Ncϓ}"}"9registerMap/structure/elements/module/tests/testYamlIo.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest from ..module import \ Module, \ ParseError from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.set import SetCollection from registerMap.structure.elements.tests.mockObserver import MockObserver from .mocks import MockPreviousModule log = logging.getLogger( __name__ ) class TestModuleYamlLoadSave( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.previousModule = MockPreviousModule( endAddress = 0x0 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule self.moduleUnderTest[ 'name' ] = 'module' self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.setCollection.moduleSet.add( self.moduleUnderTest ) self.acquiredSetCollection = SetCollection() def testEncodeDecode( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x10 self.createRegister( 'r1' ) encodedYamlData = self.moduleUnderTest.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedModule = Module.from_yamlData( encodedYamlData, self.testSpace, self.acquiredSetCollection ) self.assertEqual( decodedModule[ 'constraints' ][ 'fixedAddress' ], self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] ) self.assertEqual( decodedModule[ 'description' ], self.moduleUnderTest[ 'description' ] ) self.assertEqual( decodedModule[ 'summary' ], self.moduleUnderTest[ 'summary' ] ) self.assertEqual( len( self.acquiredSetCollection.moduleSet ), 1 ) decodedModule.previousElement = self.previousModule # No exceptions should be thrown decodedModule.reviewAddressChange() def createRegister( self, name ) : self.moduleUnderTest.addRegister( name ) self.moduleUnderTest[ 'registers' ][ name ][ 'constraints' ][ 'fixedAddress' ] = 0x10 self.moduleUnderTest[ 'registers' ][ name ][ 'description' ] = 'some description' self.moduleUnderTest[ 'registers' ][ name ][ 'mode' ] = 'ro' self.moduleUnderTest[ 'registers' ][ name ][ 'public' ] = False self.moduleUnderTest[ 'registers' ][ name ][ 'summary' ] = 'a summary' self.moduleUnderTest[ 'registers' ][ name ].addField( 'f1', [ 3, 5 ], (3, 5) ) self.moduleUnderTest[ 'registers' ][ name ].addField( 'f2', [ 7, 7 ], (7, 7) ) def testFromBadYamlData( self ) : yamlData = { 'mode' : 'ro' } with self.assertRaisesRegex( ParseError, '^Yaml data does not specify module' ) : Module.from_yamlData( yamlData, self.testSpace, self.acquiredSetCollection ) def testFromOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } decodedModule = Module.from_yamlData( yamlData, self.testSpace, self.acquiredSetCollection, optional = True ) self.assertEqual( len( decodedModule[ 'constraints' ] ), 0 ) self.assertEqual( decodedModule[ 'description' ], '' ) self.assertIsNone( decodedModule[ 'name' ] ) self.assertEqual( len( decodedModule[ 'registers' ] ), 0 ) self.assertEqual( decodedModule[ 'summary' ], '' ) class TestModuleYamlParameters( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x215 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule def testYamlDataAddress( self ) : # The address data is automatically generated so it is prefixed by '_'. self.assertEqual( self.previousModule.endAddress, 0x215 ) expectedName = '_address' expectedValue = 0x216 self.assertEqual( self.moduleUnderTest.baseAddress, expectedValue ) yamlData = self.moduleUnderTest.to_yamlData() self.assertEqual( yamlData[ 'module' ][ expectedName ], expectedValue ) def testYamlDataSpan( self ) : # The address data is automatically generated so it is prefixed by '_'. expectedName = '_spanMemoryUnits' expectedValue = 0 self.assertEqual( self.moduleUnderTest.spanMemoryUnits, expectedValue ) yamlData = self.moduleUnderTest.to_yamlData() self.assertEqual( yamlData[ 'module' ][ expectedName ], expectedValue ) def testYamlDataNoneAddress( self ) : testModule = Module( self.testSpace, self.setCollection ) yamlData = testModule.to_yamlData() self.assertIsNone( yamlData[ 'module' ][ '_address' ] ) class TestLoadSaveUserDefinedParameters( unittest.TestCase ) : def setUp( self ) : self.previousModule = MockPreviousModule( endAddress = 0x0 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule self.moduleUnderTest[ 'name' ] = 'module' self.setCollection.moduleSet.add( self.moduleUnderTest ) self.acquiredSetCollection = SetCollection() def testEncodeDecode( self ) : expectedValue = 'some value' self.moduleUnderTest[ 'my-parameter' ] = expectedValue encodedYamlData = self.moduleUnderTest.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedModule = Module.from_yamlData( encodedYamlData, self.testSpace, self.acquiredSetCollection ) self.assertEqual( expectedValue, decodedModule[ 'my-parameter' ] ) class TestModuleYamlAddressRestoration( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.previousModule = MockPreviousModule( endAddress = 0x0 ) self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.moduleUnderTest = Module( self.testSpace, self.setCollection ) self.moduleUnderTest.previousElement = self.previousModule self.moduleUnderTest[ 'name' ] = 'module' self.moduleUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.setCollection.moduleSet.add( self.moduleUnderTest ) self.acquiredSetCollection = SetCollection() def testEncodeDecodeAddressesRestored( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x10 r1 = self.moduleUnderTest.addRegister( 'r1' ) r1.addField( 'f1', (5, 11) ) r2 = self.moduleUnderTest.addRegister( 'r2' ) r2.addField( 'f2', (3, 5) ) r2.addField( 'f3', (6, 7) ) encodedYamlData = self.moduleUnderTest.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedModule = Module.from_yamlData( encodedYamlData, self.testSpace, self.acquiredSetCollection ) # This is needed to have the sizes from the export registered correctly. decodedModule.reviewAddressChange() decodedModule.reviewSizeChange() self.assertEqual( self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ], decodedModule[ 'constraints' ][ 'fixedAddress' ] ) self.assertEqual( self.moduleUnderTest[ 'description' ], decodedModule[ 'description' ] ) self.assertEqual( self.moduleUnderTest[ 'summary' ], decodedModule[ 'summary' ] ) self.assertEqual( 1, len( self.acquiredSetCollection.moduleSet ) ) decodedR1 = decodedModule[ 'registers' ][ 'r1' ] self.assertEqual( r1.startAddress, decodedR1.startAddress ) decodedR2 = decodedModule[ 'registers' ][ 'r2' ] self.assertEqual( r2.startAddress, decodedR2.startAddress ) if __name__ == '__main__' : unittest.main() PK&N  3registerMap/structure/elements/register/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .instance import RegisterInstance from .register import Register PK&N3wJ3registerMap/structure/elements/register/instance.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.structure.memory.element import AddressableMemoryElement from registerMap.export.io import yaml from registerMap.export.io.yaml.parameters.encode import parameter from registerMap.utility.observer import \ AddressChangeObserver, \ Observable, \ SizeChangeObserver from ..base import \ AddressObservableInterface, \ IdentityElement from .interface import RegisterInterface from .register import Register class RegisterInstance( IdentityElement, RegisterInterface, AddressObservableInterface, yaml.Export, yaml.Import ) : """ An instantiation of a register, which means assigning an address. Multiple RegisterInstance objects may refer to the same Register object. """ def __init__( self, memorySpace, parent = None, register = None, setCollection = None ) : super().__init__() self.addressChangeNotifier = Observable() self.__addressObserver = AddressChangeObserver( self ) self.__memory = memorySpace self.__sizeObserver = SizeChangeObserver( self ) if register is None : # parent is still optional. assert setCollection is not None self.__register = Register( memorySpace, setCollection, parent = parent ) else : self.__register = register self.__register.sizeChangeNotifier.addObserver( self.__sizeObserver ) self.__element = AddressableMemoryElement( memorySpace, sizeObject = self.__register.size ) self.__previousRegister = None self.__registerConstraintNotifiers() def __registerConstraintNotifiers( self ) : self.__register.memory.addressChangeNotifier.addObserver( self.__addressObserver ) # RegisterInstance only cares about address constraints. Size constraints are managed by the Register object. self.__register[ 'constraints' ].addressChangeNotifier.addObserver( self.__addressObserver ) def reviewAddressChange( self ) : newStartAddress = self.__calculateStartAddress() if newStartAddress != self.__element.startAddress : self.__element.startAddress = newStartAddress self.addressChangeNotifier.notifyObservers() def __calculateStartAddress( self ) : if (self.__previousRegister is not None) and (self.__previousRegister.endAddress is not None) : # Page register impact is calculate before application of constraints. This means that constraints could # still affect the address. eg. if address alignment modified the affect of page register on the address. proposedAddress = self.__previousRegister.endAddress + 1 initialAddress = self.__register.memory.calculatePageRegisterImpact( proposedAddress ) else : initialAddress = None newAddress = self.__register[ 'constraints' ].applyAddressConstraints( initialAddress ) return newAddress def reviewSizeChange( self ) : pass @property def startAddress( self ) : """ The first memory unit (the smallest numerical address value) used by the register. """ return self.__element.startAddress @property def endAddress( self ) : """ The last memory unit (the largest numerical address value) used by the register. """ return self.__element.endAddress @property def memory( self ) : """ The memory space defining the register map memory. """ return self.__register.memory @property def moduleOffset( self ) : """ The offset of the register instance relative to its parent module. """ if (self.__register.parent is not None) \ and (self.__element.startAddress is not None) : value = self.__element.startAddress - self.__register.parent.baseAddress else : value = None return value @property def offset( self ) : """ Offset address relative to the memory space base address. """ return self.__element.offset @property def bitMap( self ) : return self.__register.bitMap @property def canonicalId( self ) : return self.__register.canonicalId @property def previousElement( self ) : """ The previous register from which to derive the address of the current register. """ return self.__previousRegister @previousElement.setter def previousElement( self, previousRegister ) : """ When a Register is added to a Module it is added to the modules ElementList. ElementList uses this property to link this Register with the previous Register in the list. This property is where the address and size notification relationships between adjacent registers are assigned. :param previousRegister: """ self.__previousRegister = previousRegister self.__previousRegister.sizeChangeNotifier.addObserver( self.__addressObserver ) self.__previousRegister.addressChangeNotifier.addObserver( self.__addressObserver ) # An address or size change in the previous register can affect the address of the current register, but the # previous register should have no effect on the size of the current register which is determined by # constraints and bit fields. self.reviewAddressChange() @property def sizeBits( self ) : return self.__register.sizeBits @property def sizeMemoryUnits( self ) : return self.__register.sizeMemoryUnits @property def sizeChangeNotifier( self ) : return self.__register.sizeChangeNotifier def addField( self, name, registerBitInterval, fieldBitInterval = None, isGlobal = False ) : newRegister = self.__register.addField( name, registerBitInterval, fieldBitInterval = fieldBitInterval, isGlobal = isGlobal ) return newRegister def __getitem__( self, item ) : return self.__register[ item ] def __setitem__( self, key, value ) : self.__register[ key ] = value @classmethod def from_yamlData( cls, yamlData, memorySpace, setCollection, optional = False, parent = None ) : thisRegister = Register.from_yamlData( yamlData, memorySpace, setCollection, optional = optional, parent = parent ) thisObject = cls( memorySpace, parent = parent, register = thisRegister, setCollection = setCollection ) setCollection.registerSet.add( thisObject ) return thisObject def to_yamlData( self ) : registerYaml = self.__register.to_yamlData() registerYaml[ 'register' ].update( parameter( '_address', self.startAddress ) ) return registerYaml PK&NyO4registerMap/structure/elements/register/interface.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc from registerMap.structure.memory.interface import AddressableElementInterface class RegisterInterface( AddressableElementInterface, metaclass = abc.ABCMeta ) : @property @abc.abstractmethod def bitMap( self ) : pass @property @abc.abstractmethod def canonicalId( self ) : pass @property @abc.abstractmethod def sizeBits( self ) : pass @abc.abstractmethod def addField( self, name, registerBitInterval, fieldBitInterval = None, isGlobal = False ) : pass @abc.abstractmethod def __getitem__( self, item ) : pass @abc.abstractmethod def __setitem__( self, key, value ) : pass PK&No5registerMap/structure/elements/register/parameters.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections from registerMap.exceptions import ConfigurationError from ..field import Field from ..base.parameter import Parameter class BitFieldsParameter( Parameter ) : __parameterName = 'bitFields' def __init__( self ) : super().__init__( self.__parameterName, collections.OrderedDict() ) @classmethod def from_yamlData( cls, yamlData, optional = False, parent = None ) : parameter = cls() if (not optional) and (cls.__parameterName not in yamlData.keys()) : raise ConfigurationError( 'Bitfields not defined in yaml data' ) elif cls.__parameterName in yamlData.keys() : for bitFieldYamlData in yamlData[ cls.__parameterName ] : bitField = Field.from_yamlData( bitFieldYamlData, parentRegister = parent ) parameter.value[ bitField[ 'name' ] ] = bitField return parameter def to_yamlData( self ) : yamlData = { self.__parameterName : list() } for bitField in self.value.values() : yamlData[ self.__parameterName ].append( bitField.to_yamlData() ) return yamlData class ModeParameter( Parameter ) : # The default to_yamlData method implemented in Parameter is adequate for this child. validModes = [ 'ro', 'rw', 'wo', 'w1c', 'w0c' ] __parameterName = 'mode' def __init__( self, value = 'rw' ) : super().__init__( self.__parameterName, value ) self.validate( value ) def validate( self, value ) : if value not in self.validModes : raise ConfigurationError( 'Invalid value, ' + repr( value ) + ' valid value are, ' + repr( self.validModes ) ) @classmethod def from_yamlData( cls, yamlData, optional = False ) : parameter = super( ModeParameter, cls ).from_yamlData( yamlData, cls.__parameterName, optional = optional ) if optional and (parameter.value is None) : parameter.value = 'rw' elif not optional : parameter.validate( parameter.value ) return parameter class GlobalParameter( Parameter ) : __parameterName = 'global' def __init__( self, element ) : super().__init__( self.__parameterName, element ) self.__element = element def validate( self, value ) : pass @property def value( self ) : isGlobal = False if self.__element.parent is None : isGlobal = True return isGlobal @value.setter def value( self, v ) : # This method cannot be used, but need to override the behaviour from parent class. assert False @classmethod def from_yamlData( cls, yamlData, optional = True ) : pass class PublicParameter( Parameter ) : # The default to_yamlData method implemented in Parameter is adequate for this child. __parameterName = 'public' def __init__( self, value = True ) : super().__init__( self.__parameterName, value ) self.validate( value ) def validate( self, value ) : if not isinstance( value, bool ) : raise ConfigurationError( 'Public must be specified as boolean' ) @classmethod def from_yamlData( cls, yamlData, optional = False ) : parameter = super( PublicParameter, cls ).from_yamlData( yamlData, cls.__parameterName, optional = optional ) if optional and (parameter.value is None) : parameter.value = True elif not optional : parameter.validate( parameter.value ) return parameter PK&NwiXiX3registerMap/structure/elements/register/register.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections import logging import math from registerMap.exceptions import ParseError from registerMap.structure.elements.field import Field from registerMap.structure.bitmap import BitMap from registerMap.structure.bitrange import BitRange from registerMap.structure.memory import BitsMemoryElement from registerMap.export.io import yaml from registerMap.export.io.yaml.parameters.encode import parameter from registerMap.export.io.yaml.parameters.parse import complexParameter from registerMap.utility.observer import \ Observable, \ SizeChangeObserver from ..base import \ BitStoreInterface, \ IdentityElement, \ SizeObservableInterface from ..base.parameter import \ ConstraintsParameter, \ Parameter from .parameters import \ BitFieldsParameter, \ GlobalParameter, \ ModeParameter, \ PublicParameter log = logging.getLogger( __name__ ) class Register( IdentityElement, BitStoreInterface, SizeObservableInterface, yaml.Export, yaml.Import ) : """ Representation of the size of a register, it's fields and "core" and user defined parameters. Fields and constraints define the registers size. """ __DEFAULT_SIZE_MEMORY_UNITS = 1 __YAML_NAME = 'register' def __init__( self, memorySpace, setCollection, parent = None ) : super().__init__() self.sizeChangeNotifier = Observable() self.__setCollection = setCollection self.__bitMap = BitMap( self ) # self.__element is only used here for tracking the size. self.__elementSize = BitsMemoryElement( memorySpace ) self.__elementSize.sizeBits = self.__DEFAULT_SIZE_MEMORY_UNITS * memorySpace.memoryUnitBits self.__memory = memorySpace self.__parentModule = parent self.__sizeChangeMade = False self.__sizeObserver = SizeChangeObserver( self ) self.__coreData = { 'fields' : BitFieldsParameter(), 'constraints' : ConstraintsParameter( self.__memory ), 'description' : Parameter( 'description', '' ), 'global' : GlobalParameter( self ), 'mode' : ModeParameter( 'rw' ), 'name' : Parameter( 'name', None ), 'public' : PublicParameter( True ), 'summary' : Parameter( 'summary', '' ) } self.__userData = collections.OrderedDict() self.__registerConstraintNotifiers() def __registerConstraintNotifiers( self ) : """ Subscribe to size change notificatioins from constraints. """ self.__coreData[ 'constraints' ].value.sizeChangeNotifier.addObserver( self.__sizeObserver ) def reviewSizeChange( self ) : """ Used by size change subscriptions to notify a Register object that it may need to reconsider it's size. The Register notifies its own subscribers if there is a change. """ newSizeMemoryUnits = self.__calculateExtentMemoryUnits() if (newSizeMemoryUnits is not None) \ and ((newSizeMemoryUnits * self.__memory.memoryUnitBits) != self.__elementSize.sizeBits) : self.__elementSize.sizeBits = newSizeMemoryUnits * self.__memory.memoryUnitBits self.sizeChangeNotifier.notifyObservers() def __calculateExtentMemoryUnits( self ) : """ The total number of memory units in the register after any constraints have been applied. Since the number of memory units is quantized to the memory unit size, then the result of this function implicitly includes both assigned and unassigned bits. """ allBits = self.sizeAllocatedFields sizeMemoryUnits = math.ceil( float( allBits ) / self.__memory.memoryUnitBits ) finalSize = self.__coreData[ 'constraints' ].value.applySizeConstraints( sizeMemoryUnits ) if finalSize != sizeMemoryUnits : log.info( 'Constraint applied in calculating register size, {0}'.format( self[ 'name' ] ) ) return finalSize @property def bitMap( self ) : return self.__bitMap @property def canonicalId( self ) : if self.__parentModule is not None : canonicalName = '{0}.{1}'.format( self.__parentModule[ 'name' ], self.__coreData[ 'name' ].value ) else : canonicalName = '{0}'.format( self.__coreData[ 'name' ].value ) return canonicalName @property def coreParameters( self ) : """ The dictionary cannot be used to modify the parameters. :return: A dictionary of the core parameters. """ value = dict() for key, parameter in self.__coreData.items() : value[ key ] = parameter.value return value @property def userParameters( self ) : """ The dictionary cannot be used to modify the parameters. :return: A dictionary of the core parameters. """ value = dict() for key, parameter in self.__userData.items() : value[ key ] = parameter.value return value @property def memory( self ) : return self.__memory @property def parent( self ) : return self.__parentModule @property def size( self ) : """ Size object used for tracking Register size. """ return self.__elementSize @property def sizeAllocatedFields( self ) : """ The total number of bits in the field intervals allocated to this register. """ allocatedBits = 0 for thisInterval in self.__bitMap.sourceIntervals : allocatedBits += thisInterval.numberBits return allocatedBits @property def sizeBits( self ) : """ The number of bits in the memory units used by the register. """ numberBits = self.__elementSize.sizeBits return numberBits @property def sizeMemoryUnits( self ) : """ The integer number of memory units used by the register. """ assert (self.__elementSize.sizeBits % self.__memory.memoryUnitBits) == 0 return int( self.__elementSize.sizeBits / self.__memory.memoryUnitBits ) def addField( self, name, registerBitInterval, fieldBitInterval = None, isGlobal = False ) : """ :param name: Name of new field. Must be unique to the register the field is a member of, except special names 'reserved' and 'unassigned'. If isGlobal is True then the name must be unique in the set of global fields, otherwise the specified ranges will be added to the existing global field definition. :param registerBitInterval: Range of register bits allocated to the new field. :param fieldBitInterval: Range of field bits allocated to the register. :param isGlobal: Is the new field referencing a global field definition? :return: """ def createNewField() : nonlocal fieldBitInterval, isGlobal, name, registerBitInterval, self log.debug( 'Creating new bit field, {0}.{1}, {2}<=>{3}'.format( self[ 'name' ], name, registerBitInterval, fieldBitInterval ) ) if fieldBitInterval is None : fieldBitInterval = ((max( registerBitInterval ) - min( registerBitInterval )), 0) if not isGlobal : newField = Field( parent = self ) else : newField = Field() newField[ 'name' ] = name newField[ 'size' ] = max( fieldBitInterval ) + 1 # Need to consider the impact of the new field on register size now, otherwise mapping bits can raise. self.__reviewRegisterSize( registerBitInterval ) self.__bitMap.mapBits( BitRange( registerBitInterval ), BitRange( fieldBitInterval ), newField ) self.__setCollection.fieldSet.add( newField ) self.__coreData[ 'fields' ].value[ newField[ 'name' ] ] = newField return newField def linkToExistingGlobalField() : """ Link existing global Field to Register. :return: """ nonlocal existingFields, fieldBitInterval, name, registerBitInterval, self log.debug( 'Modifying the existing global field, {0}'.format( name ) ) globalField = [ x for x in existingFields if x[ 'global' ] ] # If there's 0, or >1 then something has gone wrong in the function above. assert len( globalField ) == 1 revisedField = self.__createFieldToRegisterMapping( globalField[ 0 ], registerBitInterval, fieldBitInterval ) return revisedField def linkToExistingLocalField( localField ) : """ Link local (non-global) Field to Register. :param localField: :return: """ nonlocal name, self log.debug( 'Modifying the existing local field, {0}'.format( name ) ) revisedField = self.__createFieldToRegisterMapping( localField, registerBitInterval, fieldBitInterval ) return revisedField existingFields = self.__setCollection.fieldSet.find( name ) existingFieldsThisRegister = [ x for x in existingFields if (not x[ 'global' ]) and all( [ y == self for y in x.bitMap.destinations ] ) ] if existingFields \ and (not isGlobal) \ and any( existingFieldsThisRegister ) : # User has requested a local field # If there's 0, or >1 then something has gone wrong; there can be only one local field with a given name # in a register. assert len( existingFieldsThisRegister ) == 1 field = linkToExistingLocalField( existingFieldsThisRegister[ 0 ] ) elif existingFields \ and isGlobal \ and any( [ x[ 'global' ] for x in existingFields ] ) : # User has requested a global field and one already exists. field = linkToExistingGlobalField() else : # Create a new field. field = createNewField() log.debug( 'Subscribing to field changes, {0}, for {1}'.format( field[ 'name' ], self.__coreData[ 'name' ] ) ) # Watch the field for size changes. field.sizeChangeNotifier.addObserver( self.__sizeObserver ) if self.__sizeChangeMade : self.sizeChangeNotifier.notifyObservers() self.__sizeChangeMade = False return field def __createFieldToRegisterMapping( self, thisField, registerBitInterval, fieldBitInterval ) : """ Creating mapping of Field to Register. :param thisField: :return: """ assert fieldBitInterval is not None # Need to consider the impact of the new field on register and field size now, otherwise mapping bits can raise. self.__reviewRegisterSize( registerBitInterval ) self.__reviewFieldSize( thisField, fieldBitInterval ) self.__bitMap.mapBits( BitRange( registerBitInterval ), BitRange( fieldBitInterval ), thisField ) return thisField def __reviewRegisterSize( self, registerInterval ) : # Register size only needs to be increased by the size of the interval being allocated to the register. # The field size could be larger even though it is new, for various reasons. # eg. register[2:4] <=> field[5:7] => field size = 8, interval size = 3 # therefore the register potentially only needs to increase by 3 bits (interval size) proposedRegisterExtent = max( registerInterval ) + 1 if proposedRegisterExtent > self.sizeBits : # Increase the size of the register to accommodate. log.debug( 'Register size increasing from adding new field, {0}'.format( self[ 'name' ] ) ) newSizeChangeMemoryUnits = math.ceil( float( proposedRegisterExtent - self.sizeBits ) / self.__memory.memoryUnitBits ) assert (self.__elementSize.sizeBits % self.__memory.memoryUnitBits) == 0 newSizeMemoryUnits = int( self.__elementSize.sizeBits / self.__memory.memoryUnitBits ) \ + newSizeChangeMemoryUnits finalSize = self.__coreData[ 'constraints' ].value.applySizeConstraints( newSizeMemoryUnits ) self.__elementSize.sizeBits = finalSize * self.__memory.memoryUnitBits self.__sizeChangeMade = True def __reviewFieldSize( self, existingField, fieldInterval ) : # A field interval defines the bits in the field being assigned. # The max of the interval indicates the extent of the field. # If the extent from the interval is greater than the current field size (extent) then the field must be # resized. proposedFieldExtent = max( fieldInterval ) + 1 if proposedFieldExtent > existingField.sizeBits : log.debug( 'Existing field size increasing with new interval, {0}'.format( existingField[ 'name' ] ) ) existingField[ 'size' ] = proposedFieldExtent existingField.sizeChangeNotifier.notifyObservers() def fieldExists( self, name ) : fieldInData = name in self.__coreData[ 'fields' ].value return fieldInData def __getitem__( self, item ) : if item in self.__coreData : value = self.__coreData[ item ].value elif item in self.__userData : value = self.__userData[ item ].value else : raise KeyError( 'Register parameter not in core or user data, {0} ({1})'.format( item, self.canonicalId ) ) return value def __setitem__( self, key, value ) : if key in self.__coreData : self.__coreData[ key ].validate( value ) self.__coreData[ key ].value = value else : assert not key.startswith( '_' ) # Assume user data log.info( 'Creating register user defined parameter, {0}={1} ({2})'.format( key, value, self.canonicalId ) ) self.__userData[ key ] = Parameter( name = key, value = value ) # Assume that any change events in bit fields or constraints will be taken care of using registered observers # of the relevant objects. @classmethod def from_yamlData( cls, yamlData, memorySpace, setCollection, optional = False, parent = None ) : register = cls( memorySpace, setCollection, parent = parent ) goodResult = register.__decodeRegister( yamlData, optional = optional ) if (not goodResult) \ and (not optional) : raise ParseError( 'Error parsing Register YAML data' ) return register def __decodeRegister( self, yamlData, optional = True ) : def acquireFields( thisData ) : nonlocal self self.__coreData[ 'fields' ] = BitFieldsParameter.from_yamlData( thisData, optional = True, parent = self ) for field in self.__coreData[ 'fields' ].value.values() : self.__setCollection.fieldSet.add( field ) def acquireBitMap( thisData ) : """ Acquire the register to field bit interval mapping from YAML data. :param thisData: Register YAML data """ nonlocal self try : for thisIntervalData in thisData[ 'bitmap' ] : sourceRangeData = thisIntervalData[ 'source' ] destinationRangeData = thisIntervalData[ 'destination' ] destinationId = thisIntervalData[ 'destinationId' ] foundObjects = [ x for x in self.__setCollection.fieldSet if x.canonicalId == destinationId ] if len( foundObjects ) == 0 : raise ParseError( 'Destination element not found in destination set, {0}'.format( destinationId ) ) assert len( foundObjects ) == 1 sourceRange = BitRange.from_yamlData( { 'range' : sourceRangeData } ) destinationRange = BitRange.from_yamlData( { 'range' : destinationRangeData } ) self.__createFieldToRegisterMapping( foundObjects[ 0 ], list( sourceRange.value ), list( destinationRange.value ) ) except KeyError as e : raise ParseError( 'Mapping not specified in YAML' ) from e def acquireConstraints( thisData ) : nonlocal self self.__coreData[ 'constraints' ] = ConstraintsParameter.from_yamlData( thisData, self.__memory, optional = True ) self.__registerConstraintNotifiers() def acquireDescription( thisData ) : nonlocal self self.__coreData[ 'description' ] = Parameter.from_yamlData( thisData, 'description', optional = True ) def acquireMode( thisData ) : nonlocal self self.__coreData[ 'mode' ] = ModeParameter.from_yamlData( thisData, optional = True ) def acquireName( thisData ) : nonlocal self self.__coreData[ 'name' ] = Parameter.from_yamlData( thisData, 'name', optional = False ) def acquirePublic( thisData ) : nonlocal self self.__coreData[ 'public' ] = PublicParameter.from_yamlData( thisData, optional = True ) def acquireSummary( thisData ) : nonlocal self self.__coreData[ 'summary' ] = Parameter.from_yamlData( thisData, 'summary', optional = True ) def acquireUserDefinedParameters( thisData ) : nonlocal self for name, value in thisData.items() : # Only add user defined parameters if the YAML item is not in core data and doesn't begin with '_' # '_' are ready only data that should always be ignored on import. if (name not in self.__coreData) \ and (not name.startswith( '_' )) : self.__userData[ name ] = Parameter( name = name, value = value ) def getParameters( thisData ) : acquireConstraints( thisData ) acquireDescription( thisData ) acquireMode( thisData ) acquireName( thisData ) acquirePublic( thisData ) acquireSummary( thisData ) # Field acquisition must be done after the basic register data is acquired. acquireFields( thisData ) # BitMap acquisition must come after the other parameters because it uses those parameters as part of the # set up. acquireBitMap( thisData ) acquireUserDefinedParameters( thisData ) # Legacy artifact of not using exceptions to signal problems. return True return complexParameter( yamlData, Register.__YAML_NAME, getParameters, optional = optional ) def __encodeCoreParameters( self ) : """ Encode Register core parameters ready for use with yaml.dump. :return: List of encoded parameters. """ encodedParameters = list() encodedParameters.append( parameter( '_sizeMemoryUnits', self.sizeMemoryUnits ) ) for parameterData in self.__coreData.values() : parameterYamlData = parameterData.to_yamlData() encodedParameters.append( parameterYamlData ) encodedParameters.append( self.__bitMap.to_yamlData() ) return encodedParameters def __encodeUserParameters( self ) : """ Encode Register user parameters ready for use with yaml.dump. :return: List of encoded parameters. """ encodedParameters = list() for parameterData in self.__userData.values() : parameterYamlData = parameterData.to_yamlData() encodedParameters.append( parameterYamlData ) return encodedParameters def to_yamlData( self ) : yamlData = { self.__YAML_NAME : { } } coreParameters = self.__encodeCoreParameters() userParameters = self.__encodeUserParameters() parameters = coreParameters + userParameters for thisParameter in parameters : yamlData[ self.__YAML_NAME ].update( thisParameter ) return yamlData PK&N9registerMap/structure/elements/register/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&NEv v 6registerMap/structure/elements/register/tests/mocks.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from registerMap.utility.observer import Observable class MockPreviousRegister : def __init__( self, startAddress = None, endAddress = None, sizeMemoryUnits = None ) : self.sizeChangeNotifier = Observable() self.addressChangeNotifier = Observable() self.__address = startAddress if (endAddress is not None) and (startAddress is not None) : self.__endAddress = endAddress self.__sizeMemoryUnits = self.__endAddress - self.__address + 1 elif (sizeMemoryUnits is not None) and (startAddress is not None) : self.__sizeMemoryUnits = sizeMemoryUnits self.__endAddress = self.__address + self.__sizeMemoryUnits - 1 elif (sizeMemoryUnits is not None) and (endAddress is not None) : self.__endAddress = endAddress self.__sizeMemoryUnits = sizeMemoryUnits self.__address = self.__endAddress - self.__sizeMemoryUnits + 1 elif (startAddress is None) and (sizeMemoryUnits is not None or endAddress is not None) : raise RuntimeError( 'Must specify address if specifying end address or size' ) else : self.__sizeMemoryUnits = None self.__endAddress = None @property def address( self ) : return self.__address @address.setter def address( self, value ) : if self.__address is not None : addressChange = value - self.__address self.__address = value self.__endAddress += addressChange else : self.__address = value self.__endAddress = self.__address + self.__sizeMemoryUnits - 1 self.addressChangeNotifier.notifyObservers() @property def endAddress( self ) : return self.__endAddress @endAddress.setter def endAddress( self, value ) : self.__endAddress = value # For the purpose of testing, assume that a change in end address always signals a size change. self.__sizeMemoryUnits = self.__endAddress - self.__address + 1 self.sizeChangeNotifier.notifyObservers() @property def sizeMemoryUnits( self ) : return self.__sizeMemoryUnits @sizeMemoryUnits.setter def sizeMemoryUnits( self, value ) : self.__sizeMemoryUnits = value self.__endAddress = self.__address + self.__sizeMemoryUnits - 1 self.sizeChangeNotifier.notifyObservers()PK&NƎF F =registerMap/structure/elements/register/tests/testRegister.py""" Unit tests for Register """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest.mock from registerMap.structure.set import SetCollection from registerMap.structure.memory import MemoryConfiguration from ..register import Register from .commonTests import \ addCommonTestCases log = logging.getLogger( __name__ ) # https://docs.python.org/3.6/library/unittest.html#load-tests-protocol # # nosetests doesn't use the loader, tests, patten arguments with load_tests # so since they aren't being used anyway, just made them optional. def load_tests( loader = None, tests = None, pattern = None ) : thisSuite = unittest.TestSuite() thisSuite = addCommonTestCases( Register, thisSuite ) return thisSuite class TestFieldParametersProperty( unittest.TestCase ) : def setUp( self ) : self.mock_memoryConfiguration = MemoryConfiguration() self.mock_set = SetCollection() self.elementUnderTest = Register( self.mock_memoryConfiguration, self.mock_set ) def testDefaultCoreParametersProperty( self ) : expectedValue = { 'constraints': self.elementUnderTest['constraints'], 'description' : '', 'fields':self.elementUnderTest['fields'], 'global' : True, 'mode':'rw', 'name' : None, 'public': True, 'summary' : '', } actualValue = self.elementUnderTest.coreParameters self.assertEqual( expectedValue, actualValue ) def testDefaultUserParametersProperty( self ) : expectedValue = dict() actualValue = self.elementUnderTest.userParameters self.assertEqual( expectedValue, actualValue ) def testUserParametersProperty( self ) : expectedValue = { 'someValue' : 123, } self.elementUnderTest[ 'someValue' ] = 123 actualValue = self.elementUnderTest.userParameters self.assertEqual( expectedValue, actualValue ) PK&NΞHregisterMap/structure/elements/register/tests/testRegisterCanonicalId.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.module import Module from registerMap.structure.set.fieldSet import FieldSet from registerMap.structure.memory.configuration import MemoryConfiguration from ..register import Register class TestRegisterCanonicalId( unittest.TestCase ) : def setUp( self ) : self.fieldSet = FieldSet() self.memorySpace = MemoryConfiguration() def testGlobalCanonicalId( self ) : registerName = 'someName' testRegister = Register( self.memorySpace, self.fieldSet ) testRegister[ 'name' ] = registerName expectedCanonicalId = '{0}'.format( registerName ) self.assertEqual( testRegister.canonicalId, expectedCanonicalId ) self.assertTrue( testRegister[ 'global' ] ) def testLocalCanonicalId( self ) : moduleName = 'moduleName' registerName = 'someName' parentModule = Module( self.memorySpace, self.fieldSet ) parentModule[ 'name' ] = moduleName testRegister = Register( self.memorySpace, self.fieldSet, parent = parentModule ) testRegister[ 'name' ] = registerName expectedCanonicalId = '{0}.{1}'.format( moduleName, registerName ) self.assertEqual( testRegister.canonicalId, expectedCanonicalId ) self.assertFalse( testRegister[ 'global' ] ) if __name__ == '__main__' : unittest.main() PK&NsEregisterMap/structure/elements/register/tests/testRegisterInstance.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..instance import RegisterInstance from .commonTests import \ addCommonTestCases # https://docs.python.org/3.6/library/unittest.html#load-tests-protocol # # nosetests doesn't use the loader, tests, patten arguments with load_tests # so since they aren't being used anyway, just made them optional. def load_tests( loader = None, tests = None, pattern = None ) : thisSuite = unittest.TestSuite() thisSuite = addCommonTestCases( RegisterInstance, thisSuite ) return thisSuite PK&NڐS55LregisterMap/structure/elements/register/tests/testRegisterInstanceAddress.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest.mock from registerMap.structure.elements.module import Module from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConstraintError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.register.tests.mocks import MockPreviousRegister from ..instance import RegisterInstance log = logging.getLogger( __name__ ) class TestRegisterAddressPreviousNoneAddress( unittest.TestCase ) : """ Test register address when the previous address has no defined address or size. """ def setUp( self ) : self.observer = MockObserver() self.previousRegister = MockPreviousRegister() self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = RegisterInstance( self.testSpace, setCollection = self.testBitFieldSet ) self.registerUnderTest.previousElement = self.previousRegister self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.registerUnderTest.addressChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertIsNone( self.registerUnderTest.startAddress ) self.assertIsNone( self.registerUnderTest.endAddress ) def testFixedAddress( self ) : expectedValue = 0x15 self.assertNotEqual( self.registerUnderTest.startAddress, expectedValue ) self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.registerUnderTest.startAddress ) self.assertEqual( expectedValue, self.registerUnderTest.endAddress ) self.assertEqual( self.observer.updateCount, 1 ) def testAlignedAddress( self ) : alignmentValue = 2 self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = alignmentValue # Attempt to constrain alignment with no concrete addresses does nothing self.assertIsNone( self.registerUnderTest.startAddress ) self.assertIsNone( self.registerUnderTest.endAddress ) self.assertEqual( self.observer.updateCount, 0 ) class TestRegisterAddressPreviousConcreteAddress( unittest.TestCase ) : """ Test register address when the previous register has concrete address and size. """ def setUp( self ) : self.observer = MockObserver() self.previousRegister = MockPreviousRegister( startAddress = 0x10, sizeMemoryUnits = 5 ) self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = RegisterInstance( self.testSpace, setCollection = self.testBitFieldSet ) self.registerUnderTest.previousElement = self.previousRegister self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.registerUnderTest.addressChangeNotifier.addObserver( self.observer ) def testFixedAddress( self ) : expectedValue = 0x16 self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) self.assertNotEqual( self.registerUnderTest.startAddress, expectedValue ) self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.registerUnderTest.startAddress ) self.assertEqual( expectedValue, self.registerUnderTest.endAddress ) self.assertEqual( self.observer.updateCount, 1 ) def testFixedAddressOnPreviousRaises( self ) : expectedValue = self.previousRegister.endAddress with self.assertRaisesRegex( ConstraintError, '^Fixed address exceeded' ) : self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue def testAlignedAddress( self ) : alignmentValue = 2 expectedValue = self.previousRegister.endAddress + 2 self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 0, (expectedValue % alignmentValue) ) self.assertLess( self.registerUnderTest.startAddress, expectedValue ) self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = alignmentValue self.assertEqual( expectedValue, self.registerUnderTest.startAddress ) self.assertEqual( expectedValue, self.registerUnderTest.endAddress ) self.assertEqual( self.observer.updateCount, 1 ) def testEndAddressMultipleMemoryUnits( self ) : f1 = self.registerUnderTest.addField( 'f1', (0, 10) ) self.assertLess( 1, self.registerUnderTest.sizeMemoryUnits ) startAddress = self.registerUnderTest.startAddress expectedEndAddress = startAddress + self.registerUnderTest.sizeMemoryUnits - 1 self.assertEqual( expectedEndAddress, self.registerUnderTest.endAddress ) def testEndAddressMultipleFieldsSameSize( self ) : def checkExpectedEndAddress(): startAddress = self.registerUnderTest.startAddress expectedEndAddress = startAddress + self.registerUnderTest.sizeMemoryUnits - 1 self.assertEqual( expectedEndAddress, self.registerUnderTest.endAddress ) self.registerUnderTest.addField( 'f1', (0, 3) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) checkExpectedEndAddress() # Add a second field that doesn't change the size of the register. self.registerUnderTest.addField( 'f2', (5, 7) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) checkExpectedEndAddress() def testEndAddressMultipleMemoryUnitsMultipleFields( self ) : def checkExpectedEndAddress(): startAddress = self.registerUnderTest.startAddress expectedEndAddress = startAddress + self.registerUnderTest.sizeMemoryUnits - 1 self.assertEqual( expectedEndAddress, self.registerUnderTest.endAddress ) self.registerUnderTest.addField( 'f1', (0, 5) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) checkExpectedEndAddress() # Add an adjacent field that extends to a second memory unit. self.registerUnderTest.addField( 'f2', (6, 10) ) self.assertEqual( 2, self.registerUnderTest.sizeMemoryUnits ) checkExpectedEndAddress() # Add a field with a gap that extends to a third memory unit. self.registerUnderTest.addField( 'f3', (15, 18) ) self.assertEqual( 3, self.registerUnderTest.sizeMemoryUnits ) checkExpectedEndAddress() class TestRegisterPageRegisterInteraction( unittest.TestCase ) : def setUp( self ) : self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = RegisterInstance( self.testSpace, setCollection = self.testBitFieldSet ) self.previousRegister = MockPreviousRegister( startAddress = 0, sizeMemoryUnits = 4 ) self.registerUnderTest.previousElement = self.previousRegister def testPageSize( self ) : self.assertEqual( 32, self.testSpace.addressBits ) self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.previousRegister.address = 0x278 log.debug( 'Mock previous register start address: ' + hex( self.previousRegister.address ) ) log.debug( 'Mock previous register end address: ' + hex( self.previousRegister.endAddress ) ) self.assertEqual( 0x278, self.previousRegister.address ) log.debug( 'Test register start address no page size: ' + hex( self.registerUnderTest.startAddress ) ) log.debug( 'Test register end address no page size: ' + hex( self.registerUnderTest.endAddress ) ) self.assertEqual( 0x27c, self.registerUnderTest.startAddress ) self.testSpace.pageSize = 0x80 log.debug( 'Test register start address page size {0}: {1}'.format( hex( self.testSpace.pageSize ), hex( self.registerUnderTest.startAddress ) ) ) log.debug( 'Test register end address page size {0}: {1}'.format( hex( self.testSpace.pageSize ), hex( self.registerUnderTest.endAddress ) ) ) self.assertEqual( 0x280, self.registerUnderTest.startAddress ) class TestRegisterPreviousRegister( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = RegisterInstance( self.testSpace, setCollection = self.testBitFieldSet ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertIsNone( self.registerUnderTest.previousElement ) def testPreviousRegisterAssign( self ) : expectedValue = 0x10 self.registerUnderTest.previousElement = MockPreviousRegister( startAddress = 0x5, endAddress = (expectedValue - 1) ) self.assertEqual( expectedValue, self.registerUnderTest.startAddress ) def testUnassignedPreviousRegisterNoneAddress( self ) : fixedAddress = 0x10 self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = fixedAddress self.assertEqual( fixedAddress, self.registerUnderTest.startAddress ) def testUnassignedEndAddress( self ) : self.registerUnderTest.previousElement = MockPreviousRegister() actualAddress = self.registerUnderTest.startAddress self.assertIsNone( actualAddress ) def testAssignPreviousRegisterEndAddress( self ) : self.registerUnderTest.previousElement = MockPreviousRegister( startAddress = 0x5 ) self.assertIsNone( self.registerUnderTest.startAddress ) expectedAddress = 0x10 self.registerUnderTest.previousElement.endAddress = expectedAddress - 1 actualAddress = self.registerUnderTest.startAddress self.assertEqual( expectedAddress, actualAddress ) class TestRegisterOffset( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.previousRegister = MockPreviousRegister() self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.testSpace.baseAddress = 0x20f0 self.registerUnderTest = RegisterInstance( self.testSpace, setCollection = self.testBitFieldSet ) self.registerUnderTest.previousElement = self.previousRegister self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.registerUnderTest.addressChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertIsNone( self.registerUnderTest.offset ) def testDataAssignment( self ) : expectedValue = 0xde inputValue = self.testSpace.baseAddress + expectedValue self.assertNotEqual( expectedValue, self.registerUnderTest.offset ) self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = inputValue self.assertEqual( inputValue, self.registerUnderTest.startAddress ) self.assertEqual( expectedValue, self.registerUnderTest.offset ) class TestRegisterModuleOffset( unittest.TestCase ) : def setUp( self ) : self.observer = MockObserver() self.previousRegister = MockPreviousRegister() self.testBitFieldSet = SetCollection() self.testSpace = MemoryConfiguration() self.testSpace.baseAddress = 0x20f0 self.mockModule = unittest.mock.create_autospec(Module) self.mockModule.baseAddress = 0x21f0 self.registerUnderTest = RegisterInstance( self.testSpace, parent = self.mockModule, setCollection = self.testBitFieldSet ) self.registerUnderTest.previousElement = self.previousRegister self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.registerUnderTest.addressChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertIsNone( self.registerUnderTest.offset ) def testDataAssignment( self ) : expectedValue = 0xde inputValue = self.mockModule.baseAddress + expectedValue self.assertNotEqual( expectedValue, self.registerUnderTest.moduleOffset ) self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = inputValue self.assertEqual( inputValue, self.registerUnderTest.startAddress ) self.assertEqual( expectedValue, self.registerUnderTest.moduleOffset ) if __name__ == '__main__' : unittest.main() PK&N<,PregisterMap/structure/elements/register/tests/testRegisterInstanceYamlAddress.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest.mock from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.register.tests.mocks import MockPreviousRegister from ..instance import RegisterInstance class TestRegisterInstanceYamlAddress( unittest.TestCase ) : def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = RegisterInstance( self.testSpace, setCollection = self.setCollection ) self.previousRegister = MockPreviousRegister( endAddress = 0x3e7, sizeMemoryUnits = 4 ) self.testRegister.previousElement = self.previousRegister self.observer = MockObserver() self.testRegister.sizeChangeNotifier.addObserver( self.observer ) def testYamlDataAddressSingleRegister( self ) : # The address data is automatically generated so it is prefixed by '_'. self.assertEqual( self.previousRegister.endAddress, 0x3e7 ) expectedName = '_address' expectedValue = 0x3e8 self.assertEqual( expectedValue, self.testRegister.startAddress ) yamlData = self.testRegister.to_yamlData() self.assertEqual( expectedValue, yamlData[ 'register' ][ expectedName ] ) if __name__ == '__main__' : unittest.main() PK&N9D7KregisterMap/structure/elements/register/tests/testRegisterParameterTypes.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import collections import unittest from registerMap.exceptions import ConfigurationError from ..register import BitFieldsParameter, Field, ModeParameter, PublicParameter class TestBitFieldsParameter( unittest.TestCase ) : def testInitialization( self ) : p = BitFieldsParameter() self.assertEqual( p.name, 'bitFields' ) self.assertTrue( isinstance( p.value, collections.OrderedDict ) ) def testEmptyBitFieldsToYamlData( self ) : p = BitFieldsParameter() expectedYamlData = { 'bitFields' : list() } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testSingleBitFieldToYamlData( self ) : p = BitFieldsParameter() p.value[ 'f1' ] = self.createBitField( 'f1', 3 ) expectedYamlData = { 'bitFields' : [ p.value[ 'f1' ].to_yamlData() ] } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testMultipleBitFieldToYamlData( self ) : p = BitFieldsParameter() p.value[ 'f1' ] = self.createBitField( 'f1', 3 ) p.value[ 'f2' ] = self.createBitField( 'f2', 1 ) expectedYamlData = { 'bitFields' : [ p.value[ 'f1' ].to_yamlData(), p.value[ 'f2' ].to_yamlData() ] } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def createBitField( self, name, size ) : b = Field() b[ 'name' ] = name b[ 'size' ] = size return b def testFromGoodYamlData( self ) : p = BitFieldsParameter() p.value[ 'f1' ] = self.createBitField( 'f1', 3 ) p.value[ 'f2' ] = self.createBitField( 'f2', 1 ) yamlData = p.to_yamlData() gp = BitFieldsParameter.from_yamlData( yamlData ) self.assertEqual( gp.value[ 'f1' ][ 'name' ], 'f1' ) self.assertEqual( gp.value[ 'f1' ][ 'size' ], 3 ) self.assertEqual( gp.value[ 'f2' ][ 'name' ], 'f2' ) self.assertEqual( gp.value[ 'f2' ][ 'size' ], 1 ) def testOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } gp = BitFieldsParameter.from_yamlData( yamlData, optional = True ) class TestModeParameter( unittest.TestCase ) : def testInitialization( self ) : expectedName = 'mode' expectedValue = 'rw' p = ModeParameter( expectedValue ) self.assertEqual( p.name, expectedName ) self.assertEqual( p.value, expectedValue ) def testInitializationBadValueRaises( self ) : badValue = 'badValue' with self.assertRaisesRegex( ConfigurationError, '^Invalid value' ) : ModeParameter( badValue ) def testGoodValueInitializationNoRaise( self ) : for value in ModeParameter.validModes : ModeParameter( value ) def testValidateBadValueRaises( self ) : p = ModeParameter( 'rw' ) badValue = 'badValue' with self.assertRaisesRegex( ConfigurationError, '^Invalid value' ) : p.validate( badValue ) def testToYamlData( self ) : expectedValue = 'ro' p = ModeParameter( expectedValue ) expectedYamlData = { 'mode' : expectedValue } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testFromGoodYamlData( self ) : expectedValue = 'ro' yamlData = { 'mode' : expectedValue } p = ModeParameter.from_yamlData( yamlData ) self.assertEqual( p.name, 'mode' ) self.assertEqual( p.value, expectedValue ) def testBadYamlDataRaises( self ) : yamlData = { 'mode' : 'badvalue' } with self.assertRaisesRegex( ConfigurationError, '^Invalid value' ) : ModeParameter.from_yamlData( yamlData ) def testOptionalYamlData( self ) : yamlData = { 'public' : True } p = ModeParameter.from_yamlData( yamlData, optional = True ) self.assertEqual( p.name, 'mode' ) self.assertEqual( p.value, 'rw' ) class TestPublicParameter( unittest.TestCase ) : def testInitialization( self ) : expectedName = 'public' expectedValue = True p = PublicParameter( expectedValue ) self.assertEqual( p.name, expectedName ) self.assertEqual( p.value, expectedValue ) def testInitializationBadValueRaises( self ) : badValue = 1 with self.assertRaisesRegex( ConfigurationError, '^Public must be specified as boolean' ) : PublicParameter( badValue ) def testValidateBadValueRaises( self ) : p = PublicParameter( False ) badValue = 1 with self.assertRaisesRegex( ConfigurationError, '^Public must be specified as boolean' ) : p.validate( badValue ) def testToYamlData( self ) : expectedValue = True p = PublicParameter( expectedValue ) expectedYamlData = { 'public' : expectedValue } actualYamlData = p.to_yamlData() self.assertEqual( actualYamlData, expectedYamlData ) def testFromGoodYamlData( self ) : expectedValues = [ True, False ] for expectedValue in expectedValues : yamlData = { 'public' : expectedValue } p = PublicParameter.from_yamlData( yamlData ) self.assertEqual( p.name, 'public' ) self.assertEqual( p.value, expectedValue ) def testBadYamlDataRaises( self ) : yamlData = { 'public' : 'true' } with self.assertRaisesRegex( ConfigurationError, '^Public must be specified as boolean' ) : PublicParameter.from_yamlData( yamlData ) def testOptionalYamlData( self ) : expectedValue = True yamlData = { 'other' : 'somevalue' } p = PublicParameter.from_yamlData( yamlData, optional = True ) self.assertEqual( p.name, 'public' ) self.assertEqual( p.value, expectedValue ) if __name__ == '__main__' : unittest.main() PK&Noލ EregisterMap/structure/elements/register/tests/commonTests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import types from .description import CommonDescriptionParameterTests from .fieldInterval import CommonFieldIntervalTests from .fields import CommonFieldTests from .mode import CommonModeParameterTests from .name import CommonNameParameterTests from .public import CommonPublicParameterTests from .sizeBits import CommonSizeBitsTests from .summary import CommonSummaryParameterTests from .userDefinedParameters import CommonUserDefinedParameterTests from .yamlIo import CommonYamlIoTests commonTests = [ CommonDescriptionParameterTests.TestRegisterDescription, CommonFieldIntervalTests.TestRegisterDefaultFieldInterval, CommonFieldTests.TestRegisterFields, CommonFieldTests.TestFieldsMultipleRegisters, CommonModeParameterTests.TestRegisterMode, CommonNameParameterTests.TestRegisterName, CommonPublicParameterTests.TestRegisterPublic, CommonSizeBitsTests.TestRegisterSize, CommonSizeBitsTests.TestRegisterSizeBits, CommonSummaryParameterTests.TestRegisterSummary, CommonUserDefinedParameterTests.TestRegisterUserDefinedParameter, CommonYamlIoTests.TestRegisterYamlLoadSave, CommonYamlIoTests.TestRegisterYamlLoadSaveCanonicalId, CommonYamlIoTests.TestRegisterYamlParameters, CommonYamlIoTests.TestLoadSaveUserDefinedParameter, ] def copyCommonClasses( typename ) : renamedTests = list() for thisTest in commonTests : newTest = type( '{0}_{1}'.format( typename, thisTest.__name__ ), thisTest.__bases__, dict( thisTest.__dict__ ) ) renamedTests.append( newTest ) return renamedTests def addCommonTestCases( UnderTestType, thisSuite ) : thisTests = copyCommonClasses( UnderTestType.__name__ ) for thisTestCase in thisTests : thisTestCase.RegisterType = UnderTestType testMethods = [ x for x, y in thisTestCase.__dict__.items() if (type( y ) == types.FunctionType) and x.startswith( 'test' ) ] for thisTest in testMethods : thisSuite.addTest( thisTestCase( thisTest ) ) return thisSuite PK&N|KKHregisterMap/structure/elements/register/tests/commonTests/description.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonDescriptionParameterTests : class TestRegisterDescription( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = '' self.assertEqual( self.registerUnderTest[ 'description' ], expectedValue ) def testDataAssignmet( self ) : expectedValue = 'register description' self.assertNotEqual( expectedValue, self.registerUnderTest[ 'description' ] ) self.registerUnderTest[ 'description' ] = expectedValue self.assertEqual( self.registerUnderTest[ 'description' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) PK&N  JregisterMap/structure/elements/register/tests/commonTests/fieldInterval.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.set import SetCollection class CommonFieldIntervalTests : class TestRegisterDefaultFieldInterval( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.setCollection = SetCollection() self.memorySpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.memorySpace, setCollection = self.setCollection ) def testDefaultFieldInterval( self ) : # When creating a new field, only specifying the register interval assume the field is the size of the register. self.assertEqual( len( self.setCollection.fieldSet ), 0 ) self.registerUnderTest.addField( 'newField', [ 5, 8 ] ) newFields = self.setCollection.fieldSet.find( 'newField' ) self.assertEqual( len( newFields ), 1 ) newField = newFields.pop() self.assertEqual( newField.sizeBits, 4 ) def testMissingFieldIntervalAsserts( self ) : # Not specifying the field interval when changing an existing field asserts self.registerUnderTest.addField( 'newField', [ 5, 8 ] ) self.assertEqual( len( self.setCollection.fieldSet ), 1 ) with self.assertRaises( AssertionError ) : self.registerUnderTest.addField( 'newField', [ 9, 10 ] ) PK&N&(>%%CregisterMap/structure/elements/register/tests/commonTests/fields.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import collections import logging import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConfigurationError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration log = logging.getLogger( __name__ ) class CommonFieldTests : class TestRegisterFields( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertEqual( self.registerUnderTest[ 'fields' ], collections.OrderedDict() ) def testMultipleFieldsAddedToArbitrarySizeWithoutConstraint( self ) : self.assertEqual( self.testSpace.memoryUnitBits, 8 ) self.assertEqual( len( self.registerUnderTest[ 'fields' ] ), 0 ) self.registerUnderTest.addField( 'testField1', [ 0, 3 ], (0, 3) ) self.registerUnderTest.addField( 'testField2', [ 4, 10 ], (0, 6) ) self.registerUnderTest.addField( 'testField3', [ 11, 25 ], (0, 14) ) self.assertEqual( self.registerUnderTest.sizeMemoryUnits, 4 ) def testOverlappingRegisterIntervalRaises( self ) : self.registerUnderTest.addField( 'field1', [ 0, 5 ], (0, 5) ) self.assertEqual( len( self.registerUnderTest[ 'fields' ] ), 1 ) with self.assertRaisesRegex( ConfigurationError, '^Specifed source interval overlaps existing source intervals' ) : self.registerUnderTest.addField( 'field2', [ 5, 6 ], (0, 1) ) def testOverlappingFieldIntervalRaises( self ) : self.registerUnderTest.addField( 'field1', [ 0, 5 ], (0, 5) ) self.assertEqual( len( self.registerUnderTest[ 'fields' ] ), 1 ) with self.assertRaisesRegex( ConfigurationError, '^Specifed destination interval overlaps existing destination intervals' ) : self.registerUnderTest.addField( 'field1', [ 6, 7 ], (5, 6) ) class TestFieldsMultipleRegisters( unittest.TestCase ) : # The tests will fail unless a child class correctly fulfills this value. RegisterType = None def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() def testAddLocalFieldsToDifferentRegisters( self ) : self.assertEqual( len( self.setCollection.fieldSet ), 0 ) register1 = self.RegisterType( self.testSpace, setCollection = self.setCollection ) register1.addField( 'field1', [ 5, 6 ], (0, 1) ) self.assertEqual( len( self.setCollection.fieldSet ), 1 ) self.assertEqual( list( self.setCollection.fieldSet )[ 0 ][ 'name' ], 'field1' ) register2 = self.RegisterType( self.testSpace, setCollection = self.setCollection ) register2.addField( 'field1', [ 3, 5 ], (4, 6) ) self.assertEqual( len( self.setCollection.fieldSet ), 2 ) self.assertEqual( list( self.setCollection.fieldSet )[ 0 ][ 'name' ], 'field1' ) self.assertEqual( list( self.setCollection.fieldSet )[ 1 ][ 'name' ], 'field1' ) def testAddLocalFieldsToSameRegisters( self ) : self.assertEqual( len( self.setCollection.fieldSet ), 0 ) register1 = self.RegisterType( self.testSpace, setCollection = self.setCollection ) register1.addField( 'field1', [ 5, 6 ], (0, 1) ) self.assertEqual( len( self.setCollection.fieldSet ), 1 ) self.assertEqual( list( self.setCollection.fieldSet )[ 0 ][ 'name' ], 'field1' ) register1.addField( 'field1', [ 2, 4 ], (4, 6) ) self.assertEqual( len( self.setCollection.fieldSet ), 1 ) self.assertEqual( list( self.setCollection.fieldSet )[ 0 ][ 'name' ], 'field1' ) def testAddGlobalFieldToRegisters( self ) : self.assertEqual( len( self.setCollection.fieldSet ), 0 ) register1 = self.RegisterType( self.testSpace, setCollection = self.setCollection ) register1.addField( 'field1', [ 5, 6 ], (0, 1), isGlobal = True ) self.assertEqual( len( self.setCollection.fieldSet ), 1 ) self.assertEqual( list( self.setCollection.fieldSet )[ 0 ][ 'name' ], 'field1' ) register2 = self.RegisterType( self.testSpace, setCollection = self.setCollection ) register2.addField( 'field1', [ 2, 4 ], (2, 4), isGlobal = True ) # The bit field set should not have changed since the initial bitfield was defined as global. self.assertEqual( len( self.setCollection.fieldSet ), 1 ) PK&N\HCregisterMap/structure/elements/register/tests/commonTests/memory.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonMemoryPropertyTests : class TestRegisterMemoryProperty( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) def testMemoryProperty( self ) : self.assertEqual( self.testSpace, self.registerUnderTest.memory ) PK&NAregisterMap/structure/elements/register/tests/commonTests/mode.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConfigurationError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonModeParameterTests : class TestRegisterMode( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.testRegister.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = 'rw' self.assertEqual( self.testRegister[ 'mode' ], expectedValue ) def testDataAssignment( self ) : expectedValue = 'ro' self.assertNotEqual( expectedValue, self.testRegister[ 'mode' ] ) self.testRegister[ 'mode' ] = expectedValue self.assertEqual( self.testRegister[ 'mode' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) def testInvalidValueRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Invalid value' ) : self.testRegister[ 'mode' ] = 'r' PK&NzAregisterMap/structure/elements/register/tests/commonTests/name.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonNameParameterTests : class TestRegisterName( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.testRegister.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : self.assertIsNone( self.testRegister[ 'name' ] ) def testDataAssignment( self ) : expectedValue = 'register name' self.assertNotEqual( expectedValue, self.testRegister[ 'name' ] ) self.testRegister[ 'name' ] = expectedValue self.assertEqual( self.testRegister[ 'name' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) PK&NZCregisterMap/structure/elements/register/tests/commonTests/public.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConfigurationError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonPublicParameterTests : class TestRegisterPublic( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = True self.assertEqual( self.registerUnderTest[ 'public' ], expectedValue ) def testDataAssignment( self ) : self.assertTrue( self.registerUnderTest[ 'public' ] ) self.registerUnderTest[ 'public' ] = False self.assertFalse( self.registerUnderTest[ 'public' ] ) self.assertEqual( self.observer.updateCount, 0 ) def testNonBoolRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Public must be specified as boolean' ) : self.registerUnderTest[ 'public' ] = 'true' PK&NP**EregisterMap/structure/elements/register/tests/commonTests/sizeBits.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ConstraintError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonSizeBitsTests : class TestRegisterSizeBits( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testCorrectSizeForFieldsAdded( self ) : self.assertEqual( 0, self.observer.updateCount ) memoryUnitsSizeBits = self.testSpace.memoryUnitBits self.registerUnderTest.addField( 'f1', [ 0, 7 ], (0, 7) ) self.assertEqual( memoryUnitsSizeBits, self.registerUnderTest.sizeBits ) self.registerUnderTest.addField( 'f2', [ 8, 10 ], (0, 2) ) self.assertEqual( (2 * memoryUnitsSizeBits), self.registerUnderTest.sizeBits ) class TestRegisterSize( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : # A register with no bit fields must allocate one memory unit for itself. self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) def testCorrectSizeForBitFieldsAdded1( self ) : # Adding two intervals to a register increases the register size: # - from different fields # - the second register interval exceeds the existing register size self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f1', [ 0, 7 ], (0, 7) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) # No notifications because the field addition didn't change the register size. self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f2', [ 8, 10 ], (0, 2) ) self.assertEqual( 2, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 1, self.observer.updateCount ) self.assertEqual( 8, self.registerUnderTest[ 'fields' ][ 'f1' ][ 'size' ] ) self.assertEqual( 3, self.registerUnderTest[ 'fields' ][ 'f2' ][ 'size' ] ) def testCorrectSizeForBitFieldsAdded2( self ) : # Adding two intervals to a register increases the register size: # - from different fields # - the first register interval does not exceed the register size, but the second interval does self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f1', [ 0, 3 ], (0, 3) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f2', [ 8, 10 ], (0, 2) ) self.assertEqual( 2, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 1, self.observer.updateCount ) self.assertEqual( 4, self.registerUnderTest[ 'fields' ][ 'f1' ][ 'size' ] ) self.assertEqual( 3, self.registerUnderTest[ 'fields' ][ 'f2' ][ 'size' ] ) def testCorrectSizeForBitFieldsAdded3( self ) : # Adding two intervals to a register does not increase the register size: # - from the same field # - the extent of the new register intervals is less than the size of the register # - the extent of the second field interval changes the size of the field # - the FieldSet does not change size self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f1', [ 0, 3 ], (0, 3) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 4, self.registerUnderTest[ 'fields' ][ 'f1' ][ 'size' ] ) # No notifications because the field addition didn't change the register size. self.assertEqual( 0, self.observer.updateCount ) self.registerUnderTest.addField( 'f1', [ 6, 7 ], (5, 6) ) self.assertEqual( 1, self.registerUnderTest.sizeMemoryUnits ) self.assertEqual( 0, self.observer.updateCount ) self.assertEqual( 7, self.registerUnderTest[ 'fields' ][ 'f1' ][ 'size' ] ) self.assertEqual( 1, len( self.setCollection.fieldSet ) ) self.assertEqual( 2, len( self.registerUnderTest.bitMap.sourceIntervals ) ) def testFixedSizeExceededAddBitfieldRaises( self ) : self.assertEqual( 8, self.testSpace.memoryUnitBits ) self.registerUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 1 self.registerUnderTest.addField( 'f1', [ 0, 6 ], [ 0, 6 ] ) with self.assertRaisesRegex( ConstraintError, '^Fixed size exceeded' ) : self.registerUnderTest.addField( 'f2', [ 8, 10 ], (0, 2) ) def testFixedSizeConstraintReportsAsSize( self ) : self.assertEqual( 8, self.testSpace.memoryUnitBits ) expectedSize = 2 updateCountBeforeAddField = self.observer.updateCount self.registerUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = expectedSize self.assertEqual( self.registerUnderTest.sizeMemoryUnits, expectedSize ) self.assertEqual( (updateCountBeforeAddField + 1), self.observer.updateCount ) def testSingleFieldSpansMultipleBytes( self ) : self.assertEqual( 8, self.testSpace.memoryUnitBits ) expectedSize = 2 updateCountBeforeAddField = self.observer.updateCount self.registerUnderTest.addField( 'f1', [ 0, 10 ] ) self.assertEqual( self.registerUnderTest.sizeMemoryUnits, expectedSize ) self.assertEqual( (updateCountBeforeAddField + 1), self.observer.updateCount ) PK&N&  DregisterMap/structure/elements/register/tests/commonTests/summary.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonSummaryParameterTests : class TestRegisterSummary( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.observer = MockObserver() self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.testRegister.sizeChangeNotifier.addObserver( self.observer ) def testDefaultValue( self ) : expectedValue = '' self.assertEqual( self.testRegister[ 'summary' ], expectedValue ) def testDataAssignment( self ) : expectedValue = 'register summary' self.assertNotEqual( expectedValue, self.testRegister[ 'summary' ] ) self.testRegister[ 'summary' ] = expectedValue self.assertEqual( self.testRegister[ 'summary' ], expectedValue ) self.assertEqual( self.observer.updateCount, 0 ) PK&NpRregisterMap/structure/elements/register/tests/commonTests/userDefinedParameters.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration class CommonUserDefinedParameterTests : class TestRegisterUserDefinedParameter( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.setCollection ) def testAssignNewParameterOk( self ) : expectedValue = 'some value' self.registerUnderTest[ 'my-parameter' ] = expectedValue self.assertEqual( expectedValue, self.registerUnderTest[ 'my-parameter' ] ) def testBadParameterRaises( self ) : with self.assertRaisesRegex( KeyError, 'Register parameter not in core or user data' ) : self.registerUnderTest[ 'bad-parameter' ] def testUnderscorePrefixAsserts( self ) : with self.assertRaises( AssertionError ) : self.registerUnderTest[ '_my-parameter' ] = 2 PK&N R-55CregisterMap/structure/elements/register/tests/commonTests/yamlIo.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest from registerMap.structure.elements.tests.mockObserver import MockObserver from registerMap.exceptions import ParseError from registerMap.structure.set import SetCollection from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.elements.register.tests.mocks import MockPreviousRegister log = logging.getLogger( __name__ ) class MockModule : def __init__( self, name ) : self.__name = name def __getitem__( self, item ) : assert item == 'name' return self.__name class CommonYamlIoTests : class TestRegisterYamlLoadSave( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.sourceCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = self.RegisterType( self.testSpace, setCollection = self.sourceCollection ) self.observer = MockObserver() self.testRegister.sizeChangeNotifier.addObserver( self.observer ) self.acquiredCollection = SetCollection() def testEncodeDecode( self ) : def checkFields() : """ Test the register fields have been recovered correctly. """ nonlocal self, decodedRegister self.assertEqual( decodedRegister[ 'fields' ][ 'f1' ][ 'name' ], self.testRegister[ 'fields' ][ 'f1' ][ 'name' ] ) self.assertEqual( decodedRegister[ 'fields' ][ 'f1' ][ 'size' ], self.testRegister[ 'fields' ][ 'f1' ][ 'size' ] ) self.assertEqual( decodedRegister[ 'fields' ][ 'f2' ][ 'name' ], self.testRegister[ 'fields' ][ 'f2' ][ 'name' ] ) self.assertEqual( decodedRegister[ 'fields' ][ 'f2' ][ 'size' ], self.testRegister[ 'fields' ][ 'f2' ][ 'size' ] ) # Ensure that acquired fields have been added to the field set. self.assertEqual( len( self.sourceCollection.fieldSet ), len( self.testRegister[ 'fields' ] ) ) fieldSetIds = [ x.canonicalId for x in self.sourceCollection.fieldSet ] for thisField in decodedRegister[ 'fields' ].values() : self.assertIn( thisField.canonicalId, fieldSetIds ) def checkParameters() : """ Test the register parameters, other than 'fields', have been recovered correctly. """ nonlocal self, decodedRegister self.assertEqual( decodedRegister[ 'constraints' ][ 'fixedAddress' ], self.testRegister[ 'constraints' ][ 'fixedAddress' ] ) self.assertEqual( decodedRegister[ 'description' ], self.testRegister[ 'description' ] ) self.assertEqual( decodedRegister[ 'mode' ], self.testRegister[ 'mode' ] ) self.assertEqual( decodedRegister[ 'name' ], self.testRegister[ 'name' ] ) self.assertEqual( decodedRegister[ 'public' ], self.testRegister[ 'public' ] ) self.assertEqual( decodedRegister[ 'summary' ], self.testRegister[ 'summary' ] ) def checkBitMap() : nonlocal self, decodedRegister for thisField in self.acquiredCollection.fieldSet : # Assume that this test indicates the bitmap has acquired itself from YAML correctly; # other bit map specific tests will exhaustively test bit map YAML acquisition. self.assertIn( thisField, decodedRegister.bitMap.destinations ) # Check that the reciprocal map has been established. self.assertIn( decodedRegister.bitMap.source, thisField.bitMap.destinations ) self.testRegister[ 'constraints' ][ 'fixedAddress' ] = 0x10 self.testRegister[ 'description' ] = 'some description' self.testRegister[ 'mode' ] = 'ro' self.testRegister[ 'name' ] = 'registerName' self.testRegister[ 'public' ] = False self.testRegister[ 'summary' ] = 'a summary' self.testRegister.addField( 'f1', [ 3, 5 ], (0, 2) ) self.testRegister.addField( 'f2', [ 7, 7 ], (0, 0) ) self.assertEqual( self.testRegister.canonicalId, self.testRegister[ 'name' ] ) encodedYamlData = self.testRegister.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.testSpace, self.acquiredCollection ) checkFields() checkParameters() checkBitMap() def testDefaultEncodeDecode( self ) : encodedYamlData = self.testRegister.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.testSpace, self.sourceCollection ) self.assertEqual( len( decodedRegister[ 'fields' ] ), 0 ) self.assertEqual( len( decodedRegister[ 'constraints' ] ), 0 ) self.assertEqual( decodedRegister[ 'description' ], '' ) self.assertEqual( decodedRegister[ 'mode' ], 'rw' ) self.assertIsNone( decodedRegister[ 'name' ] ) self.assertEqual( decodedRegister[ 'public' ], True ) self.assertEqual( decodedRegister[ 'summary' ], '' ) def testBadYamlDataRaises( self ) : yamlData = { 'mode' : 'ro' } with self.assertRaisesRegex( ParseError, '^Yaml data does not specify register' ) : self.RegisterType.from_yamlData( yamlData, self.testSpace, self.sourceCollection, optional = False ) def testOptionalYamlData( self ) : # Specifying an optional YAML decoding when a register YAML encoding is not present must result in a Register # populated with default values. yamlData = { 'mode' : 'ro' } decodedRegister = self.RegisterType.from_yamlData( yamlData, self.testSpace, self.acquiredCollection, optional = True ) self.assertEqual( len( decodedRegister[ 'fields' ] ), 0 ) self.assertEqual( len( decodedRegister[ 'constraints' ] ), 0 ) self.assertEqual( decodedRegister[ 'description' ], '' ) self.assertEqual( decodedRegister[ 'mode' ], 'rw' ) self.assertIsNone( decodedRegister[ 'name' ] ) self.assertEqual( decodedRegister[ 'public' ], True ) self.assertEqual( decodedRegister[ 'summary' ], '' ) def testRegisterWithFieldLargerThanOneByte( self ) : expectedRegisterSizeBits = 16 self.testRegister[ 'name' ] = 'registerName' self.testRegister.addField( 'f1', (0, 11) ) self.assertEqual( expectedRegisterSizeBits, self.testRegister.sizeBits ) self.assertEqual( self.testRegister.canonicalId, self.testRegister[ 'name' ] ) encodedYamlData = self.testRegister.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.testSpace, self.acquiredCollection ) self.assertEqual( self.testRegister[ 'name' ], decodedRegister[ 'name' ] ) self.assertEqual( expectedRegisterSizeBits, decodedRegister.sizeBits ) def testRegisterWithMultiplesFieldsAcrossByteBoundary( self ) : expectedRegisterSizeBits = 16 self.testRegister[ 'name' ] = 'registerName' # This field allocation implies a two byte register required to encapsulate them. self.testRegister.addField( 'f1', (3, 5) ) self.testRegister.addField( 'f2', (10, 11) ) self.assertEqual( expectedRegisterSizeBits, self.testRegister.sizeBits ) self.assertEqual( self.testRegister.canonicalId, self.testRegister[ 'name' ] ) encodedYamlData = self.testRegister.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.testSpace, self.acquiredCollection ) self.assertEqual( self.testRegister[ 'name' ], decodedRegister[ 'name' ] ) self.assertEqual( expectedRegisterSizeBits, decodedRegister.sizeBits ) class TestRegisterYamlParameters( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.setCollection = SetCollection() self.testSpace = MemoryConfiguration() self.testRegister = self.RegisterType( self.testSpace, setCollection = self.setCollection ) self.previousRegister = MockPreviousRegister( endAddress = 0x3e7, sizeMemoryUnits = 4 ) self.testRegister.previousElement = self.previousRegister self.observer = MockObserver() self.testRegister.sizeChangeNotifier.addObserver( self.observer ) def testYamlDataSpan( self ) : # The address data is automatically generated so it is prefixed by '_'. expectedName = '_sizeMemoryUnits' expectedValue = 1 self.assertEqual( expectedValue, self.testRegister.sizeMemoryUnits ) yamlData = self.testRegister.to_yamlData() self.assertEqual( expectedValue, yamlData[ 'register' ][ expectedName ] ) class TestRegisterYamlLoadSaveCanonicalId( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.sourceCollection = SetCollection() self.space = MemoryConfiguration() self.module = MockModule( 'module' ) self.acquiredCollection = SetCollection() def testEncodeDecode( self ) : """ The canonical ID of the decoded register much match that of the encoded register and is expected to include the module canonical ID. :return: """ testRegister = self.RegisterType( self.space, parent = self.module, setCollection = self.sourceCollection ) testRegister[ 'name' ] = 'register' self.sourceCollection.registerSet.add( testRegister ) self.assertEqual( 'module.register', testRegister.canonicalId ) encodedYamlData = testRegister.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.space, self.acquiredCollection, parent = self.module ) self.assertEqual( testRegister.canonicalId, decodedRegister.canonicalId ) self.assertEqual( 'module.register', testRegister.canonicalId ) class TestLoadSaveUserDefinedParameter( unittest.TestCase ) : # The tests will fail unless a test case loader correctly fulfills this value. RegisterType = None def setUp( self ) : self.sourceCollection = SetCollection() self.testSpace = MemoryConfiguration() self.registerUnderTest = self.RegisterType( self.testSpace, setCollection = self.sourceCollection ) self.observer = MockObserver() self.registerUnderTest.sizeChangeNotifier.addObserver( self.observer ) self.acquiredCollection = SetCollection() def testEncodeDecode( self ) : expectedValue = 'some value' self.registerUnderTest[ 'my-parameter' ] = expectedValue encodedYamlData = self.registerUnderTest.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedRegister = self.RegisterType.from_yamlData( encodedYamlData, self.testSpace, self.acquiredCollection ) self.assertEqual( expectedValue, decodedRegister[ 'my-parameter' ] ) PK&N`0registerMap/structure/elements/tests/__init__.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # PK&Novaa4registerMap/structure/elements/tests/mockObserver.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from registerMap.utility.observer.interface import Observer class MockObserver( Observer ) : def __init__( self ) : self.arguments = None self.updateCount = 0 @property def updated( self ) : isUpdated = False if self.updateCount != 0 : isUpdated = True return isUpdated def update( self, source, arguments ) : self.updateCount += 1 self.arguments = arguments PK&Ngc^^5registerMap/structure/elements/tests/testParameter.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import unittest from registerMap.constraints.constraintTable import ConstraintTable from registerMap.structure.memory.configuration import MemoryConfiguration from ..base.parameter import ConstraintsParameter, Parameter, ParseError class TestParameter( unittest.TestCase ) : def testInitialization( self ) : expectedName = 'someName' expectedValue = 31415 p = Parameter( expectedName, expectedValue ) self.assertEqual( p.name, expectedName ) self.assertEqual( p.value, expectedValue ) def testToYamlData( self ) : expectedName = 'someName' expectedValue = 31415 p = Parameter( expectedName, expectedValue ) expectedYamlData = { expectedName : expectedValue } actualYamlData = p.to_yamlData( ) self.assertEqual( actualYamlData, expectedYamlData ) def testFromGoodYamlData( self ) : expectedName = 'someName' expectedValue = 31415 yamlData = { expectedName : expectedValue } actualParameter = Parameter.from_yamlData( yamlData, expectedName ) self.assertEqual( actualParameter.name, expectedName ) self.assertEqual( actualParameter.value, expectedValue ) def testFromBadYamlDataRaises( self ) : expectedName = 'someName' expectedValue = 31415 yamlData = { 'badname' : expectedValue } with self.assertRaisesRegex( ParseError, '^Parameter is not in yaml data' ) : Parameter.from_yamlData( yamlData, expectedName ) def testOptionalFromYamlDataNoRaise( self ) : expectedName = 'someName' expectedValue = 31415 yamlData = { 'othername' : expectedValue } actualParameter = Parameter.from_yamlData( yamlData, expectedName, optional = True ) self.assertEqual( actualParameter.name, expectedName ) self.assertIsNone( actualParameter.value ) class TestConstraintsParameter( unittest.TestCase ) : def setUp( self ) : self.testMemory = MemoryConfiguration() def testInitialization( self ) : p = ConstraintsParameter( self.testMemory ) self.assertEqual( p.name, 'constraints' ) self.assertTrue( isinstance( p.value, ConstraintTable ) ) def testToYamlData( self ) : p = ConstraintsParameter( self.testMemory ) p.value[ 'fixedAddress' ] = 0x10 p.value[ 'fixedSizeMemoryUnits' ] = 5 p.value[ 'alignmentMemoryUnits' ] = 2 expectedYamlData = { 'constraints' : { 'fixedAddress' : 0x10, 'fixedSize' : 5, 'alignment' : 2 } } actualYamlData = p.to_yamlData( ) self.assertEqual( actualYamlData, expectedYamlData ) def testFromGoodYamlData( self ) : p = ConstraintsParameter( self.testMemory ) p.value[ 'fixedAddress' ] = 0x10 p.value[ 'fixedSizeMemoryUnits' ] = 5 p.value[ 'alignmentMemoryUnits' ] = 2 yamlData = p.to_yamlData( ) generatedParameter = ConstraintsParameter.from_yamlData( yamlData, self.testMemory ) self.assertEqual( p.value[ 'fixedAddress' ], generatedParameter.value[ 'fixedAddress' ] ) self.assertEqual( p.value[ 'fixedSizeMemoryUnits' ], generatedParameter.value[ 'fixedSizeMemoryUnits' ] ) self.assertEqual( p.value[ 'alignmentMemoryUnits' ], generatedParameter.value[ 'alignmentMemoryUnits' ] ) def testGoodDataWithOtherParameter( self ) : p = ConstraintsParameter( self.testMemory ) p.value[ 'fixedAddress' ] = 0x10 p.value[ 'fixedSizeMemoryUnits' ] = 5 p.value[ 'alignmentMemoryUnits' ] = 2 yamlData = p.to_yamlData( ) yamlData[ 'mode' ] = 'ro' generatedParameter = ConstraintsParameter.from_yamlData( yamlData, self.testMemory ) self.assertEqual( p.value[ 'fixedAddress' ], generatedParameter.value[ 'fixedAddress' ] ) self.assertEqual( p.value[ 'fixedSizeMemoryUnits' ], generatedParameter.value[ 'fixedSizeMemoryUnits' ] ) self.assertEqual( p.value[ 'alignmentMemoryUnits' ], generatedParameter.value[ 'alignmentMemoryUnits' ] ) def testBadYamlDataRaises( self ) : yamlData = { 'mode' : 'ro' } with self.assertRaisesRegex( ParseError, '^Yaml data does not specify constraints' ) : ConstraintsParameter.from_yamlData( yamlData, self.testMemory ) def testOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } generatedParameter = ConstraintsParameter.from_yamlData( yamlData, self.testMemory, optional = True ) self.assertEqual( len( generatedParameter.value ), 0 ) PK&NX ⊢*registerMap/structure/interval/__init__.py""" Definition of interval. """ # # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .contiguous import makeContiguous from .element import ClosedIntegerInterval from .overlap import \ anyOverlap, \ isOverlap, \ isEncapsulated from .sort import sortIntervals PK&NnW,registerMap/structure/interval/contiguous.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .element import ClosedIntegerInterval from .sort import sortIntervals def makeContiguous( intervals, maxIndex ) : """ Make the list or set of intervals contiguous by inserting intervals in any necessary gaps. :param intervals: :param maxIndex: The maximum index in the intervals. Enables inserting an interval at the end if necessary. :return: list of revised intervals """ sortedIntervals = sortIntervals( intervals ) contiguousIntervals = list() # Check for gap at the start if min( sortedIntervals[ 0 ].value ) != 0 : maxThisInterval = min( sortedIntervals[ 0 ].value ) - 1 contiguousIntervals.append( ClosedIntegerInterval( (0, maxThisInterval) ) ) for index in range( 0, (len( sortedIntervals ) - 1) ) : contiguousIntervals.append( sortedIntervals[ index ] ) minNextInterval = min( sortedIntervals[ index + 1 ].value ) expectedMinNextInterval = max( sortedIntervals[ index ].value ) + 1 if minNextInterval != expectedMinNextInterval : contiguousIntervals.append( ClosedIntegerInterval( (expectedMinNextInterval, (minNextInterval - 1)) ) ) # Always append the last interval contiguousIntervals.append( sortedIntervals[ -1 ] ) maxLastInterval = max( sortedIntervals[ -1 ].value ) if maxLastInterval != maxIndex : # Add an interval at the end to fill the gap to maxIndex. contiguousIntervals.append( ClosedIntegerInterval( ((maxLastInterval + 1), maxIndex) ) ) return contiguousIntervals PK&N))registerMap/structure/interval/element.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging from registerMap.exceptions import ConfigurationError log = logging.getLogger( __name__ ) class ClosedIntegerInterval : """ An integer mathematically closed interval. The internal representation is `frozenset`, but `set`, `list` and `tuple` can be used to initialise the interval, and for comparison. """ __validContainers = (set, tuple, list) def __init__( self, value = None ) : if value is not None : self.__validateValue( value ) self.__value = frozenset( value ) else : self.__value = value @property def size( self ) : if self.__value is None : thisSize = 0 else : thisSize = max( self.__value ) - min( self.value ) + 1 return thisSize @property def value( self ) : return self.__value @value.setter def value( self, value ) : self.__validateValue( set( value ) ) self.__value = frozenset( value ) def __validateValue( self, value ) : errorMessage = 'Interval must be a set of one or two positive integers, {0}'.format( value ) if not isinstance( value, self.__validContainers ) : raise ConfigurationError( errorMessage ) if any( [ not isinstance( x, int ) for x in value ] ) : raise ConfigurationError( errorMessage ) if any( [ x < 0 for x in value ] ) : raise ConfigurationError( errorMessage ) if len( value ) not in [ 1, 2 ] : raise ConfigurationError( errorMessage ) def __eq__( self, other ) : if other is None : isEqual = self.__value is other elif isinstance( other, self.__validContainers ) : isEqual = self.__value == frozenset( other ) elif other.__value is None : isEqual = self.__value is other.__value else : isEqual = self.__value == other.__value return isEqual def __ne__( self, other ) : return not (self == other) def __hash__( self ) : # Python seems to think the ClosedIntegerInterval class is not hashable (when used as an index in a dict), so # explicitly defining __hash__ method and returning the object id fixes that. return hash( self.__value ) def __add__( self, other ) : if isinstance( other, int ) : result = ClosedIntegerInterval( value = [ x + other for x in self.__value ] ) else : raise ConfigurationError( 'Must add int to ClosedIntegerInterval' ) return result def __sub__( self, other ) : if isinstance( other, int ) : result = ClosedIntegerInterval( value = [ x - other for x in self.__value ] ) else : raise ConfigurationError( 'Must add int to ClosedIntegerInterval' ) return result PK&N8uZ)registerMap/structure/interval/overlap.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # def isOverlap( interval1, interval2 ) : """ Is there any overlap of the two specified intervals? :param interval1: :param interval2: :return: True if the intervals overlap in any way. """ if (max( interval1.value ) >= min( interval2.value )) \ and (max( interval1.value ) <= max( interval2.value )) : return True elif (min( interval1.value ) <= max( interval2.value )) \ and (min( interval1.value ) >= min( interval2.value )) : return True elif (min( interval2.value ) <= max( interval1.value )) \ and (min( interval2.value ) >= min( interval1.value )) : return True return False def isEncapsulated( interval1, interval2 ) : """ Is interval1 encapsulated by interval2? :param interval1: :param interval2: :return: True if interval1 is encapsulated by interval2 (including that they are equal). """ if (max( interval1.value ) <= max( interval2.value )) \ and (min( interval1.value ) >= min( interval2.value )) : return True return False def anyOverlap( intervals ) : """ Detect any overlapping intervals in an iterable of intervals. :param intervals: :return: True if any intervals in the iterable overlap. """ reviewedOverlap = set() intervalSet = set( intervals ) while intervalSet: reviewingInterval = intervalSet.pop() reviewedOverlap.add( any( { isOverlap( reviewingInterval, x ) for x in intervalSet } ) ) return any( reviewedOverlap ) PK&N%{&registerMap/structure/interval/sort.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .overlap import anyOverlap def intervalSortKey( interval ) : return min( interval.value ) def sortIntervals( intervals ) : """ Sort a list or set of integer intervals `ClosedIntegerInterval` into a list of increasing order. eg. { (3, 4), (0, 2), (5, 7) } becomes [ (0, 2), (3, 4), (5, 7) ] :param intervals: :return: list of sorted intervals. """ assert not anyOverlap( intervals ) sortedIntervals = sorted( list( intervals ), key = intervalSortKey ) return sortedIntervals PK&N0registerMap/structure/interval/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nڌ##4registerMap/structure/interval/tests/testInterval.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..element import \ ClosedIntegerInterval, \ ConfigurationError class TestIntervalDefaultConstructor( unittest.TestCase ) : def testDefaultValue( self ) : r = ClosedIntegerInterval() self.assertEqual( r, None ) def testConstructedValue( self ) : expectedValue = { 3, 6 } r = ClosedIntegerInterval( value = expectedValue ) self.assertEqual( r.value, expectedValue ) def testHashable( self ) : # Using ClosedIntegerInterval as key in a dict must not fail. r = ClosedIntegerInterval() x = dict() x[ r ] = 'test' def testHashTwoEqualIntervalsIsSame( self ) : interval = (4, 7) r1 = ClosedIntegerInterval() r1.value = interval r2 = ClosedIntegerInterval() r2.value = interval self.assertEqual( hash( r1 ), hash( r2 ) ) class TestIntervalAssignment( unittest.TestCase ) : def setUp( self ) : self.testInterval = ClosedIntegerInterval() def testBadConstructedValueRaises( self ) : expectedValue = '[3, 6]' with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : ClosedIntegerInterval( value = expectedValue ) def testSetValueAssignment( self ) : expectedValue = { 0, 8 } self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertTrue( self.testInterval == expectedValue ) def testListValueAssignment( self ) : expectedValue = [ 0, 8 ] self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertTrue( self.testInterval == expectedValue ) def testTupleValueAssignment( self ) : expectedValue = (0, 8) self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertEqual( self.testInterval, expectedValue ) def testSetSingleValueAssignment( self ) : expectedValue = { 1 } self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertTrue( self.testInterval == expectedValue ) def testListSingleValueAssignment( self ) : expectedValue = [ 1, 1 ] self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertTrue( self.testInterval == expectedValue ) def testTupleSingleValueAssignment( self ) : expectedValue = (1, 1) self.testInterval.value = expectedValue self.assertTrue( isinstance( self.testInterval, ClosedIntegerInterval ) ) self.assertEqual( self.testInterval, expectedValue ) def testNonListRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testInterval.value = '5' def testListNonIntRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testInterval.value = [ 5, '6' ] def testNegativeValuesRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testInterval.value = [ 5, -7 ] def testWrongLengthRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testInterval.value = [ 5, 7, 6 ] with self.assertRaisesRegex( ConfigurationError, '^Interval must be a set of one or two positive integers' ) : self.testInterval.value = tuple() class TestIntervalSize( unittest.TestCase ) : def setUp( self ) : self.testInterval = ClosedIntegerInterval() def testDefaultSize( self ) : self.assertEqual( self.testInterval.size, 0 ) def testSizeSingle( self ) : self.testInterval.value = (5, 5) self.assertEqual( self.testInterval.size, 1 ) def testSizeMultiple( self ) : self.testInterval.value = (5, 8) self.assertEqual( self.testInterval.size, 4 ) class TestEqualOperator( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.testInterval = ClosedIntegerInterval( value = self.expectedValue ) def testEqualSet( self ) : self.assertTrue( self.testInterval == { 3, 7 } ) def testEqualList( self ) : self.assertTrue( self.testInterval == [ 3, 7 ] ) def testEqualTuple( self ) : self.assertTrue( self.testInterval == (3, 7) ) def testNone( self ) : self.assertFalse( self.testInterval == None ) def testBitRange( self ) : self.assertTrue( self.testInterval == ClosedIntegerInterval( value = self.expectedValue ) ) self.assertFalse( self.testInterval == ClosedIntegerInterval( value = [ 0, 4 ] ) ) class TestNotEqualOperator( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.testInterval = ClosedIntegerInterval( value = self.expectedValue ) def testList( self ) : self.assertTrue( self.testInterval != [ 0, 4 ] ) def testNone( self ) : self.assertTrue( self.testInterval != None ) def testBitRange( self ) : self.assertFalse( self.testInterval != ClosedIntegerInterval( value = self.expectedValue ) ) self.assertTrue( self.testInterval != ClosedIntegerInterval( value = [ 0, 4 ] ) ) class TestIntegerOffsetArithmetic( unittest.TestCase ) : def setUp( self ) : self.expectedValue = [ 3, 7 ] self.interval = ClosedIntegerInterval( value = self.expectedValue ) def testAddInteger( self ) : expectedResult = ClosedIntegerInterval( value = (6, 10) ) actualResult = self.interval + 3 self.assertEqual( actualResult, expectedResult ) def testIntegerAddInPlace( self ) : expectedResult = ClosedIntegerInterval( value = (6, 10) ) self.interval += 3 self.assertEqual( self.interval, expectedResult ) def testSubtractInteger( self ) : expectedResult = ClosedIntegerInterval( value = (0, 4) ) actualResult = self.interval - 3 self.assertEqual( actualResult, expectedResult ) def testIntegerSubtractInPlace( self ) : expectedResult = ClosedIntegerInterval( value = (0, 4) ) self.interval -= 3 self.assertEqual( self.interval, expectedResult ) if __name__ == '__main__' : unittest.main() PK&N*! >registerMap/structure/interval/tests/testIntervalContiguous.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..contiguous import makeContiguous from ..element import ClosedIntegerInterval class TestMakeContiguous( unittest.TestCase ) : def testContiguousIntervalsUnchanged( self ) : inputValue = { ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (5, 7) ), } expectedValues = [ ClosedIntegerInterval( (0, 2) ).value, ClosedIntegerInterval( (3, 4) ).value, ClosedIntegerInterval( (5, 7) ).value, ] contiguousIntervals = makeContiguous( inputValue, 7 ) actualValues = [ x.value for x in contiguousIntervals ] self.assertEqual( expectedValues, actualValues ) def testNoncontiguousIntervalsAdded( self ) : inputValue = { ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (0, 1) ), ClosedIntegerInterval( (7, 7) ), } expectedValues = [ ClosedIntegerInterval( (0, 1) ).value, ClosedIntegerInterval( (2, 2) ).value, ClosedIntegerInterval( (3, 4) ).value, ClosedIntegerInterval( (5, 6) ).value, ClosedIntegerInterval( (7, 7) ).value, ] contiguousIntervals = makeContiguous( inputValue, 7 ) actualValues = [ x.value for x in contiguousIntervals ] self.assertEqual( expectedValues, actualValues ) def testLastNoncontiguousIntervalAdded( self ) : inputValue = { ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (0, 1) ), ClosedIntegerInterval( (7, 7) ), } expectedValues = [ ClosedIntegerInterval( (0, 1) ).value, ClosedIntegerInterval( (2, 2) ).value, ClosedIntegerInterval( (3, 4) ).value, ClosedIntegerInterval( (5, 6) ).value, ClosedIntegerInterval( (7, 7) ).value, ClosedIntegerInterval( (8, 10) ).value, ] contiguousIntervals = makeContiguous( inputValue, 10 ) actualValues = [ x.value for x in contiguousIntervals ] self.assertEqual( expectedValues, actualValues ) if __name__ == '__main__' : unittest.main() PK&NL;registerMap/structure/interval/tests/testIntervalOverlap.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..element import ClosedIntegerInterval from ..overlap import \ anyOverlap, \ isEncapsulated, \ isOverlap class TestIntervalOverlap( unittest.TestCase ) : def testUpperOverlap1( self ) : # The first interval overlaps the upper edge of the second interval. i1 = ClosedIntegerInterval( (4, 8) ) i2 = ClosedIntegerInterval( (2, 4) ) self.assertTrue( isOverlap( i1, i2 ) ) def testUpperOverlap2( self ) : # The second interval overlaps the upper edge of the first interval. i1 = ClosedIntegerInterval( (2, 4) ) i2 = ClosedIntegerInterval( (4, 8) ) self.assertTrue( isOverlap( i1, i2 ) ) def testLowerOverlap1( self ) : # The first interval overlaps the lower edge of the second interval. i1 = ClosedIntegerInterval( (2, 3) ) i2 = ClosedIntegerInterval( (3, 6) ) self.assertTrue( isOverlap( i1, i2 ) ) def testLowerOverlap2( self ) : # The second interval overlaps the lower edge of the first interval. i1 = ClosedIntegerInterval( (3, 6) ) i2 = ClosedIntegerInterval( (2, 3) ) self.assertTrue( isOverlap( i1, i2 ) ) def testNoOverlap( self ) : # The intervals do not overlap. i1 = ClosedIntegerInterval( (2, 3) ) i2 = ClosedIntegerInterval( (4, 7) ) self.assertFalse( isOverlap( i1, i2 ) ) def testInsideOverlap1( self ) : # The second interval is entirely inside the first interval. i1 = ClosedIntegerInterval( (3, 9) ) i2 = ClosedIntegerInterval( (4, 6) ) self.assertTrue( isOverlap( i1, i2 ) ) def testInsideOverlap2( self ) : # The first interval is entirely inside the second interval. i1 = ClosedIntegerInterval( (4, 6) ) i2 = ClosedIntegerInterval( (3, 9) ) self.assertTrue( isOverlap( i1, i2 ) ) def testEqualOverlap( self ) : # The first interval is equal to the second interval. i1 = ClosedIntegerInterval( (4, 6) ) i2 = ClosedIntegerInterval( (4, 6) ) self.assertTrue( isOverlap( i1, i2 ) ) class TestIsEncapsulated( unittest.TestCase ) : def testIsEncapsulated( self ) : # The first interval is entirely inside the second interval. i1 = ClosedIntegerInterval( (4, 6) ) i2 = ClosedIntegerInterval( (2, 9) ) self.assertTrue( isEncapsulated( i1, i2 ) ) def testIsNotEncapsulated( self ) : # The second interval is entirely inside the first interval. i1 = ClosedIntegerInterval( (2, 9) ) i2 = ClosedIntegerInterval( (4, 6) ) self.assertFalse( isEncapsulated( i1, i2 ) ) def testEqualOverlap( self ) : # The first interval is equal to the second interval. i1 = ClosedIntegerInterval( (4, 6) ) i2 = ClosedIntegerInterval( (4, 6) ) self.assertTrue( isEncapsulated( i1, i2 ) ) class TestAnyOverlap( unittest.TestCase ) : def testOverlapTrue( self ) : inputValue = [ ClosedIntegerInterval( (4, 6) ), ClosedIntegerInterval( (6, 8) ) ] self.assertTrue( anyOverlap( inputValue ) ) def testOverlapTrue( self ) : inputValue = [ ClosedIntegerInterval( (4, 6) ), ClosedIntegerInterval( (7, 8) ) ] self.assertFalse( anyOverlap( inputValue ) ) if __name__ == '__main__' : unittest.main() PK&N@4 8registerMap/structure/interval/tests/testIntervalSort.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..element import ClosedIntegerInterval from ..sort import sortIntervals class TestIntervalSort( unittest.TestCase ) : def testSortIntervalList( self ) : inputValue = [ ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (5, 7) ), ] actualValue = sortIntervals( inputValue ) expectedValue = [ ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (5, 7) ), ] self.assertEqual( expectedValue, actualValue ) def testSortContiguousIntervalSet( self ) : inputValue = { ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (5, 7) ), } actualValue = sortIntervals( inputValue ) expectedValue = [ ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (3, 4) ), ClosedIntegerInterval( (5, 7) ), ] self.assertEqual( expectedValue, actualValue ) def testSortNoncontiguousIntervalSet( self ) : inputValue = { ClosedIntegerInterval( (4, 4) ), ClosedIntegerInterval( (0, 1) ), ClosedIntegerInterval( (6, 7) ), } actualValue = sortIntervals( inputValue ) expectedValue = [ ClosedIntegerInterval( (0, 1) ), ClosedIntegerInterval( (4, 4) ), ClosedIntegerInterval( (6, 7) ), ] self.assertEqual( expectedValue, actualValue ) def testOverlappingIntervalAsserts( self ) : inputValue = { ClosedIntegerInterval( (3, 5) ), ClosedIntegerInterval( (0, 2) ), ClosedIntegerInterval( (5, 7) ), } with self.assertRaises( AssertionError ) : sortIntervals( inputValue ) if __name__ == '__main__' : unittest.main() PK&NFogg(registerMap/structure/memory/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .address import AddressQueryResult from .element import \ AddressableMemoryElement, \ BitsMemoryElement from .configuration import MemoryConfiguration PK&N5'registerMap/structure/memory/address.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # class AddressQueryResult : """ Reference the memory elements located at the specified address. Normally returned from and address query of a memory space. """ def __init__( self ) : self.address = None self.fields = list() self.module = None self.register = None PK&N⊃$$-registerMap/structure/memory/configuration.py""" Define register map memory space parameters. These parameters typically relate to physical properties of underlying hardware. """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import math import registerMap.export.io.yaml.parameters.encode as rye import registerMap.export.io.yaml.parameters.parse as ryp import registerMap.utility.observer as rmo from registerMap.export.io import yaml from registerMap.exceptions import ConfigurationError, ParseError class MemoryConfiguration( yaml.Export, yaml.Import ) : def __init__( self ) : super().__init__() self.addressChangeNotifier = rmo.Observable() self.sizeChangeNotifier = rmo.Observable() self.__baseAddress = 0 self.__addressBits = 32 self.__memoryUnitBits = 8 self.__pageSize = None self.__maximumMemoryAddress = pow( 2, self.__addressBits ) @property def addressBits( self ) : """ :return: The maximum number of bits for register map addresses. :default: 32 """ return self.__addressBits @addressBits.setter def addressBits( self, value ) : if (not isinstance( value, int )) or (value < 1) : raise ConfigurationError( 'Memory address bits must be specified as positive non-zero integer' ) maximumMemoryAddress = pow( 2, value ) if maximumMemoryAddress < self.__baseAddress : raise ConfigurationError( 'Addressable memory must be greater than the base address, ' + hex( maximumMemoryAddress ) + ' < ' + hex( self.__baseAddress ) ) self.__addressBits = value self.__maximumMemoryAddress = maximumMemoryAddress if self.__pageSize is not None : self.addressChangeNotifier.notifyObservers( arguments = 'addressBits' ) @property def baseAddress( self ) : """ :return: The address of offset zero in the register map; the first address location. :default: 0x0 """ return self.__baseAddress @baseAddress.setter def baseAddress( self, value ) : if (not isinstance( value, int )) \ or (value < 0) : raise ConfigurationError( 'Base address must be specified as non-negative integer' ) if value > self.__maximumMemoryAddress : raise ConfigurationError( 'Base address must be less than maximum addressable memory, ' + hex( value ) + ' < ' + hex( self.__maximumMemoryAddress ) ) self.__baseAddress = value self.addressChangeNotifier.notifyObservers( arguments = 'baseAddress' ) @property def maximumMemoryAddress( self ) : return self.__maximumMemoryAddress @property def memoryUnitBits( self ) : """ :return: The maximum number of bits for a register map location. :default: 8 """ return self.__memoryUnitBits @memoryUnitBits.setter def memoryUnitBits( self, value ) : if (not isinstance( value, int )) or (value < 1) : raise ConfigurationError( 'Memory unit bits must be specified as positive non-zero integer' ) self.__memoryUnitBits = value if self.__pageSize is not None : self.addressChangeNotifier.notifyObservers( arguments = 'memoryUnitBits' ) @property def pageSize( self ) : """ By default, paging is disabled and pageSize is None. If paging is enabled, then the last N bits of the page are reserved for page addressing, where N is equal to memoryAddressBits. :return: The maximum number of memory units in a page. :default: None """ return self.__pageSize @pageSize.setter def pageSize( self, newPageSize ) : if (newPageSize is not None) and (not isinstance( newPageSize, int )) : raise ConfigurationError( 'Page size must be specified as integer' ) elif newPageSize is None : self.__pageSize = None else : # Must be an integer pageRegisterReservedUnits = self.__calculateNumberPageRegisters() if (newPageSize - pageRegisterReservedUnits) < 0 : raise ConfigurationError( 'Bad page size, ' + repr( newPageSize ) ) self.__pageSize = newPageSize self.addressChangeNotifier.notifyObservers( arguments = 'pageSize' ) def __calculateNumberPageRegisters( self ) : pageRegisterReservedUnits = math.ceil( float( self.__addressBits ) / self.__memoryUnitBits ) return pageRegisterReservedUnits def __calculatePageRegisterOffsets( self ) : pageRegisterOffsets = None if self.__pageSize is not None : numberPageRegisters = self.__calculateNumberPageRegisters() pageRegisterOffsets = list() for offset in range( numberPageRegisters, 0, -1 ) : pageRegisterOffsets.append( self.__pageSize - offset ) return pageRegisterOffsets def calculatePageRegisterImpact( self, proposedAddress ) : if self.__pageSize is not None : if self.isPageRegister( proposedAddress ) : # Propose the first address of the next page. proposedAddress = self.pageBaseAddress( proposedAddress ) + self.__pageSize return proposedAddress def isPageRegister( self, address ) : """ Determine if specified address is a page register. Always returns False if page size is not specified. :param address: Address to be evaluated :return: True if address is a page register. """ result = False if self.__pageSize is not None : pageRegisterOffsets = self.__calculatePageRegisterOffsets() if (address % self.__pageSize) in pageRegisterOffsets : result = True return result def pageBaseAddress( self, address ) : """ Determine base address of page for specfied address. :param address: :return: Page base address, or None if page size is not specified. """ thisPageBaseAddress = None if self.__pageSize is not None : thisPageBaseAddress = math.floor( float( address ) / self.__pageSize ) * self.__pageSize return thisPageBaseAddress @classmethod def from_yamlData( cls, yamlData ) : memorySpace = cls() goodResult = memorySpace.__decodeMemorySpace( yamlData ) if not goodResult : raise ParseError( 'Processing memory space data failed. Check log for details. ' + repr( yamlData ) ) return memorySpace def __decodeMemorySpace( self, yamlData ) : def recordBaseAddress( value ) : nonlocal self self.__baseAddress = value def recordAddressBits( value ) : nonlocal self self.__addressBits = value def recordMemoryUnitBits( value ) : nonlocal self self.__memoryUnitBits = value def recordPageSizeMemoryUnits( value ) : nonlocal self self.__pageSize = value def getParameters( thisData ) : thisGoodResult = ryp.integerParameter( thisData, 'baseAddress', recordBaseAddress, optional = True ) thisGoodResult &= ryp.integerParameter( thisData, 'addressBits', recordAddressBits, optional = True ) thisGoodResult &= ryp.integerParameter( thisData, 'memoryUnitBits', recordMemoryUnitBits, optional = True ) thisGoodResult &= ryp.integerParameter( thisData, 'pageSizeMemoryUnits', recordPageSizeMemoryUnits, optional = True, noneValid = True ) return thisGoodResult keyName = 'memorySpace' return ryp.complexParameter( yamlData, keyName, getParameters ) def to_yamlData( self ) : parameters = [ rye.parameter( 'baseAddress', rye.HexInt( self.__baseAddress ) ), rye.parameter( 'addressBits', self.__addressBits ), rye.parameter( 'memoryUnitBits', self.__memoryUnitBits ), rye.parameter( 'pageSizeMemoryUnits', self.__pageSize ) ] keyName = 'memorySpace' yamlData = { keyName : { } } for thisParameter in parameters : yamlData[ keyName ].update( thisParameter ) return yamlData PK&Nˁ--'registerMap/structure/memory/element.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import typing from registerMap.exceptions import ConfigurationError from registerMap.utility.observer import \ Observable, \ SizeChangeObserver from .interface import AddressableElementInterface from .configuration import MemoryConfiguration SizeValue = typing.NewType( 'SizeValue', int ) class BitsMemoryElement( Observable ) : """ Fundamental object of a memory space expresses the objects size in bits. The `BitsMemoryElement` is `Observable` so that the user can receive notification of a size change if needed. """ def __init__( self, sizeBits: SizeValue = None ) : super().__init__() self.__sizeObserver = SizeChangeObserver( self ) self.__sizeBits = SizeValue( sizeBits ) @property def sizeBits( self ) -> SizeValue : """ Number of bits spanned by the element. """ return self.__sizeBits @sizeBits.setter def sizeBits( self, v: SizeValue ) : self.__sizeBits = v self.notifyObservers() def __setattr__( self, key, value ) : """ Create a "set only" property for ``sizeBitsNoNotify``. :param key: :param value: """ if key == 'sizeBitsNoNotify' : # assign the bits and don't notify self.__sizeBits = value else: super().__setattr__( key, value ) class MemoryUnitMemoryElement( BitsMemoryElement ) : def __init__( self, memoryUnitBits: SizeValue, sizeMemoryUnits: SizeValue = None ) : sizeBits = None if sizeMemoryUnits is not None : sizeBits = sizeMemoryUnits * memoryUnitBits super().__init__( sizeBits = sizeBits ) self.__memoryUnitBits = memoryUnitBits @BitsMemoryElement.sizeBits.setter def sizeBits( self, v: SizeValue ) : """ Overload the BitMemoryElement sizeBits property setter to check that the assigned bits are an integer multiple of the memory unit bits. :param v: :return: """ if (v % self.__memoryUnitBits) != 0 : raise RuntimeError( 'Cannot assign bits a non integer multiple of memory units, {0}'.format( v ) ) BitsMemoryElement.sizeBits.fset( self, v ) @property def sizeMemoryUnits( self ) -> SizeValue : """ Number of memory units spanned by the element. """ if self.sizeBits is not None : assert (self.sizeBits % self.__memoryUnitBits) == 0 value = SizeValue( int( self.sizeBits / self.__memoryUnitBits ) ) else : value = self.sizeBits return value @sizeMemoryUnits.setter def sizeMemoryUnits( self, v: SizeValue ) : self.sizeBits = v * self.__memoryUnitBits def __setattr__( self, key, value ) : if key == 'sizeMemoryUnitsNoNotify' : pass super().__setattr__( key, value ) AddressValue = typing.NewType( 'AddressValue', int ) class AddressableMemoryElement( AddressableElementInterface ) : """ Basic address properties of a memory element. The assumption is that an addressable memory element prefers to express size in terms of memory units rather than bits. For the purpose of enabling the separation of instances from the element object (say, `Register` and `RegisterInstance`) the MemoryElement to use for size related calculations can be supplied in the constructor. `AddressableMemoryElement` composites `MemoryElement` so that memory element instances such as `RegisterInstance` can refer to an independent object for size. """ __DEFAULT_SIZE_MEMORY_UNITS = 1 def __init__( self, memoryConfiguration: MemoryConfiguration, startAddress: AddressValue = None, endAddress: AddressValue = None, sizeMemoryUnits: SizeValue = None, sizeObject: typing.Type[ BitsMemoryElement ] = None ) : super().__init__() self.memoryConfiguration = memoryConfiguration if (endAddress is not None) and (sizeMemoryUnits is not None) : raise ConfigurationError( 'Cannot specify both endAddress and sizeMemoryUnits, {0}, {1}'.format( endAddress, sizeMemoryUnits ) ) self.__sizeObserver = SizeChangeObserver( self ) if sizeObject is not None : self.__size = sizeObject elif sizeMemoryUnits is not None : sizeBits = self.__calculateSizeBits( sizeMemoryUnits ) self.__size = BitsMemoryElement( sizeBits ) else : sizeBits = self.__calculateSizeBits( self.__DEFAULT_SIZE_MEMORY_UNITS ) self.__size = BitsMemoryElement( sizeBits ) self.__size.addObserver( self.__sizeObserver ) self.__startAddress = startAddress if startAddress is None : self.__endAddress = None else : assert startAddress is not None # Assume the start address is numerical # If a sizeObject is specified, assume that it's size is valid. if endAddress is not None : self.__evaluateSizeFromEndAddressChange( endAddress ) elif sizeMemoryUnits is not None : self.__evaluateEndAddressFromSizeChange( sizeMemoryUnits ) elif sizeObject is None : self.__endAddress = self.__startAddress def __evaluateEndAddressFromSizeChange( self, newSizeMemoryUnits: SizeValue ) : """ Adjust end address assuming the start address is constant. :param newSizeMemoryUnits: """ if newSizeMemoryUnits is None : self.__endAddress = None elif self.__startAddress is not None : self.__endAddress = self.__startAddress + newSizeMemoryUnits - 1 self.__updateSizeBits( newSizeMemoryUnits ) def __updateSizeBits( self, newSizeMemoryUnits: SizeValue ) : if newSizeMemoryUnits is not None : self.__size.sizeBitsNoNotify = newSizeMemoryUnits * self.memoryConfiguration.memoryUnitBits else : self.__size.sizeBitsNoNotify = None def __evaluateEndAddressFromStartAddressChange( self, newAddress: AddressValue ) : """ Adjust end address assuming the size is constant. :param newAddress: """ if newAddress is None : self.__endAddress = None elif self.__size.sizeBits is not None : self.__endAddress = newAddress + self.sizeMemoryUnits - 1 self.__startAddress = newAddress def __evaluateStartAddressFromSizeChange( self, newSizeMemoryUnits: SizeValue ) : """ Adjust start address assuming the end address is constant. :param newSizeMemoryUnits: """ if newSizeMemoryUnits is None : self.__startAddress = None elif self.__endAddress is not None : self.__startAddress = self.__endAddress - newSizeMemoryUnits + 1 self.__updateSizeBits( newSizeMemoryUnits ) def __evaluateStartAddressFromEndAddressChange( self, newAddress: AddressValue ) : """ Adjust start address assuming the size is constant. :param newAddress: """ if newAddress is None : self.__endAddress = None elif self.__size.sizeBits is not None : self.__startAddress = newAddress - self.sizeMemoryUnits + 1 self.__endAddress = newAddress def __evaluateSizeFromStartAddressChange( self, newAddress: AddressValue ) : """ Adjust size assuming the end address is constant. :param newAddress: """ if newAddress is None : self.__startAddress = None elif self.__endAddress is not None : self.__updateSizeBits( SizeValue( self.__endAddress - newAddress + 1 ) ) self.__startAddress = newAddress def __evaluateSizeFromEndAddressChange( self, newAddress: AddressValue ) : """ Adjust size assuming the start address is constant. :param newAddress: """ if newAddress is None : self.__startAddress = None elif self.__startAddress is not None : self.__updateSizeBits( newAddress - self.__startAddress + 1 ) self.__endAddress = newAddress @property def offset( self ) : """ Address offset relative to the memory space base address. """ if self.__startAddress is None : offset = None else : offset = self.__startAddress - self.memoryConfiguration.baseAddress return offset def __calculateSizeBits( self, sizeMemoryUnits: SizeValue ) -> SizeValue : sizeBits = None if sizeMemoryUnits is not None : sizeBits = sizeMemoryUnits * self.memoryConfiguration.memoryUnitBits return sizeBits @property def sizeMemoryUnits( self ) -> SizeValue : if self.__size.sizeBits is None : value = None else : assert isinstance( self.__size.sizeBits, int ) assert (self.__size.sizeBits % self.memoryConfiguration.memoryUnitBits) == 0 value = SizeValue( int( self.__size.sizeBits / self.memoryConfiguration.memoryUnitBits ) ) return value @sizeMemoryUnits.setter def sizeMemoryUnits( self, value: SizeValue ) : # Assume the start address is fixed and adjust the end address. self.__evaluateEndAddressFromSizeChange( value ) @property def startAddress( self ) -> AddressValue : """ The start address of the element, corresponding to the lowest numerical value of the addresses spanned by the element. """ return self.__startAddress @startAddress.setter def startAddress( self, value: AddressValue ) : # Assume the size is fixed and adjust the end address. self.__evaluateEndAddressFromStartAddressChange( value ) @property def endAddress( self ) -> AddressValue : """ The end address of the element, corresponding to the highest numerical value of the addresses spanned by the element. """ return self.__endAddress @endAddress.setter def endAddress( self, value: AddressValue ) : if self.__startAddress is None : raise ConfigurationError( 'Must define start address before attempting to define end address' ) else : # Assume the start address is fixed and adjust the size. self.__evaluateSizeFromEndAddressChange( value ) def reviewSizeChange( self ) : if self.__size.sizeBits is not None : assert (self.__size.sizeBits % self.memoryConfiguration.memoryUnitBits) == 0 self.__evaluateEndAddressFromSizeChange( self.sizeMemoryUnits ) PK&N  )registerMap/structure/memory/interface.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import abc class AddressableElementInterface( metaclass = abc.ABCMeta ) : @property @abc.abstractmethod def startAddress( self ) : pass @property @abc.abstractmethod def endAddress( self ) : pass @property @abc.abstractmethod def sizeMemoryUnits( self ) : pass PK&N.registerMap/structure/memory/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N"\,<registerMap/structure/memory/tests/testAddressQueryResult.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..address import AddressQueryResult class TestAddressQueryResult( unittest.TestCase ) : def setUp( self ) : self.elementUnderTest = AddressQueryResult() def testDefault( self ) : self.assertIsNone( self.elementUnderTest.address ) self.assertIsNone( self.elementUnderTest.module ) self.assertIsNone( self.elementUnderTest.register ) # fields must be an empty list self.assertTrue( not self.elementUnderTest.fields ) if __name__ == '__main__' : unittest.main() PK&N <-<-BregisterMap/structure/memory/tests/testAddressableMemoryElement.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """ Test ``AddressableMemoryElement`` methods and properties. """ import logging import unittest from registerMap.exceptions import ConfigurationError from ..element import \ AddressableMemoryElement, \ BitsMemoryElement from ..configuration import MemoryConfiguration log = logging.getLogger( __name__ ) class TestDefaultConstructor( unittest.TestCase ) : """ Test ``AddressableMemoryElement`` default constructor. """ def setUp( self ) : self.memoryConfiguration = MemoryConfiguration() self.assertEqual( 8, self.memoryConfiguration.memoryUnitBits ) def testDefaultArguments( self ) : testElement = AddressableMemoryElement( self.memoryConfiguration ) self.assertIsNone( testElement.startAddress ) self.assertIsNone( testElement.endAddress ) self.assertEqual( 1, testElement.sizeMemoryUnits ) def testAssignStartAddressWithNoneSizeEnd( self ) : testElement = AddressableMemoryElement( self.memoryConfiguration ) testElement.startAddress = 2 testElement.sizeMemoryUnits = None self.assertEqual( 2, testElement.startAddress ) self.assertIsNone( testElement.endAddress ) self.assertIsNone( testElement.sizeMemoryUnits ) def testAssignStartAddressWithDefaultSize( self ) : testElement = AddressableMemoryElement( self.memoryConfiguration ) testElement.startAddress = 2 self.assertEqual( 2, testElement.startAddress ) self.assertEqual( 2, testElement.endAddress ) def testNoneSizeEndThenAssignStartAddress( self ) : testElement = AddressableMemoryElement( self.memoryConfiguration ) testElement.sizeMemoryUnits = None testElement.startAddress = 2 self.assertEqual( 2, testElement.startAddress ) self.assertIsNone( testElement.endAddress ) self.assertIsNone( testElement.sizeMemoryUnits ) def testValidStartAddressArgument( self ) : expectedValue = 0x10 testElement = AddressableMemoryElement( self.memoryConfiguration, startAddress = expectedValue ) self.assertEqual( expectedValue, testElement.startAddress ) self.assertEqual( expectedValue, testElement.endAddress ) self.assertEqual( 1, testElement.sizeMemoryUnits ) def testValidStartEndAddressArguments( self ) : expectedStartAddress = 0x10 expectedEndAddress = 0x15 testElement = AddressableMemoryElement( self.memoryConfiguration, startAddress = expectedStartAddress, endAddress = expectedEndAddress ) self.assertEqual( expectedStartAddress, testElement.startAddress ) self.assertEqual( expectedEndAddress, testElement.endAddress ) self.assertEqual( (expectedEndAddress - expectedStartAddress + 1), testElement.sizeMemoryUnits ) def testValidStartAddressSizeArguments( self ) : expectedStartAddress = 0x10 expectedSize = 5 testElement = AddressableMemoryElement( self.memoryConfiguration, startAddress = expectedStartAddress, sizeMemoryUnits = expectedSize ) self.assertEqual( expectedStartAddress, testElement.startAddress ) self.assertEqual( expectedSize, testElement.sizeMemoryUnits ) self.assertEqual( (expectedStartAddress + expectedSize - 1), testElement.endAddress ) def testSpecifyBothEndAddressAndSizeRaises( self ) : with self.assertRaisesRegex( ConfigurationError, '^Cannot specify both endAddress and sizeMemoryUnits' ) : AddressableMemoryElement( self.memoryConfiguration, endAddress = 4, sizeMemoryUnits = 6 ) def testSizeObjectNonDefaultSizeNoneStart( self ) : expectedSizeBits = 16 size = BitsMemoryElement( self.memoryConfiguration ) size.sizeBits = expectedSizeBits elementUnderTest = AddressableMemoryElement( self.memoryConfiguration, sizeObject = size ) self.assertEqual( int( expectedSizeBits / self.memoryConfiguration.memoryUnitBits ), elementUnderTest.sizeMemoryUnits ) def testSizeObjectNonDefaultSizeNumericStart( self ) : expectedSizeBits = 16 size = BitsMemoryElement( self.memoryConfiguration ) size.sizeBits = expectedSizeBits elementUnderTest = AddressableMemoryElement( self.memoryConfiguration, sizeObject = size, startAddress = 0x10 ) self.assertEqual( int( expectedSizeBits / self.memoryConfiguration.memoryUnitBits ), elementUnderTest.sizeMemoryUnits ) class TestMemoryElementOffset( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.memory.baseAddress = 0x2010 self.elementUnderTest = AddressableMemoryElement( self.memory ) def testDefaultValue( self ) : self.assertIsNone( self.elementUnderTest.offset ) def testOffset( self ) : self.elementUnderTest.startAddress = 0x21e4 expectedValue = self.elementUnderTest.startAddress - self.memory.baseAddress self.assertEqual( expectedValue, self.elementUnderTest.offset ) class TestMemoryElementStartAddress( unittest.TestCase ) : """ Test ``MemoryElement`` start address behaviour """ def setUp( self ) : self.memory = MemoryConfiguration() self.testElement = AddressableMemoryElement( self.memory ) def testDefaultValue( self ) : self.assertIsNone( self.testElement.startAddress ) def testAssignValueNoSize( self ) : expectedValue = 0x10 self.assertNotEqual( self.testElement.startAddress, expectedValue ) self.testElement.startAddress = expectedValue self.assertEqual( expectedValue, self.testElement.startAddress ) self.assertEqual( self.testElement.endAddress, self.testElement.startAddress ) def testAssignValueSizeDefined( self ) : """ Assigning a start address when the size is already defined, correctly defines the end address. """ self.testElement.sizeMemoryUnits = 5 expectedStartAddress = 0x10 expectedEndAddress = 0x14 # Test that the element doesn't already have these values. self.assertNotEqual( expectedStartAddress, self.testElement.startAddress ) self.assertNotEqual( expectedEndAddress, self.testElement.endAddress ) # Assign the start address self.testElement.startAddress = expectedStartAddress # Test that start and end addresses are correct. self.assertEqual( expectedStartAddress, self.testElement.startAddress ) self.assertEqual( expectedEndAddress, self.testElement.endAddress ) def testAssignValueWithEndAddress( self ) : initialStartAddress = 0x10 self.assertNotEqual( initialStartAddress, self.testElement.startAddress ) self.testElement.startAddress = initialStartAddress self.testElement.sizeMemoryUnits = 5 expectedStartAddress = 0x10 self.testElement.startAddress = expectedStartAddress log.debug( 'Size after start address change: ' + repr( self.testElement.sizeMemoryUnits ) ) self.assertEqual( expectedStartAddress, self.testElement.startAddress ) self.assertEqual( (expectedStartAddress + self.testElement.sizeMemoryUnits - 1), self.testElement.endAddress ) def testUnassignedStartAddressRaises( self ) : testElement = AddressableMemoryElement( self.memory ) with self.assertRaisesRegex( ConfigurationError, '^Must define start address before attempting to define end address' ) : testElement.endAddress = 0x5 def testAssignNone( self ) : expectedValue = 0x10 self.testElement.startAddress = expectedValue self.assertEqual( expectedValue, self.testElement.startAddress ) self.testElement.startAddress = None self.assertIsNone( self.testElement.startAddress ) self.assertIsNone( self.testElement.endAddress ) class TestMemoryElementEndAddress( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.testElement = AddressableMemoryElement( self.memory ) def testDefaultValue( self ) : self.assertIsNone( self.testElement.endAddress ) def testAssignValue( self ) : # Assign the start address self.testElement.startAddress = 0x10 expectedEndAddress = 0x20 self.assertNotEqual( expectedEndAddress, self.testElement.endAddress ) # Assign the end address self.testElement.endAddress = expectedEndAddress # Expect the size to be modified as a result of the end address assignment. self.assertEqual( expectedEndAddress, self.testElement.endAddress ) self.assertEqual( (expectedEndAddress - self.testElement.startAddress + 1), self.testElement.sizeMemoryUnits ) class TestMemoryElementSize( unittest.TestCase ) : """ Test ``AddressableMemoryElement`` size property. """ def setUp( self ) : self.memory = MemoryConfiguration() self.testElement = AddressableMemoryElement( self.memory ) def testDefaultValue( self ) : self.assertEqual( 1, self.testElement.sizeMemoryUnits ) def testValueAfterInitialStartAddressAssign( self ) : self.testElement.startAddress = 0x10 self.assertEqual( 1, self.testElement.sizeMemoryUnits ) def testAssignValue( self ) : """ Assigning a size to a memory element with a pre-defined start address assigns the size and re-defines the end address of the element. """ self.testElement.startAddress = 0x10 expectedSize = 5 self.assertNotEqual( expectedSize, self.testElement.sizeMemoryUnits ) self.testElement.sizeMemoryUnits = expectedSize self.assertEqual( expectedSize, self.testElement.sizeMemoryUnits ) self.assertEqual( (self.testElement.startAddress + self.testElement.sizeMemoryUnits - 1), self.testElement.endAddress ) def testPrematureAssignmentNoRaise( self ) : self.assertIsNone( self.testElement.startAddress ) self.assertIsNone( self.testElement.endAddress ) expectedValue = 5 self.testElement.sizeMemoryUnits = expectedValue self.assertEqual( expectedValue, self.testElement.sizeMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&Nٮ ;registerMap/structure/memory/tests/testBitsMemoryElement.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # """ Test ``BitsMemoryELement``. """ import unittest.mock from ..configuration import MemoryConfiguration from ..element import BitsMemoryElement class TestBitsMemoryElementConstructor( unittest.TestCase ) : """ Test ``BitsMemoryElement`` constructor. """ def setUp( self ) : self.memoryConfiguration = MemoryConfiguration() def testDefaultArguments( self ) : testElement = BitsMemoryElement() self.assertIsNone( testElement.sizeBits ) def testConstructSize( self ) : expectedSize = 10 testElement = BitsMemoryElement( expectedSize ) self.assertEqual( expectedSize, testElement.sizeBits ) class TestBitsMemoryElementSizeProperties( unittest.TestCase ) : """ Test ``BitsMemoryElement`` size properties. """ def setUp( self ) : self.memoryConfiguration = MemoryConfiguration() self.mockObserver = unittest.mock.MagicMock() self.elementUnderTest = BitsMemoryElement() self.elementUnderTest.addObserver( self.mockObserver ) def testAssignSizeObserverNotified( self ) : self.assertIsNone( self.elementUnderTest.sizeBits ) expectedSize = 1 self.elementUnderTest.sizeBits = expectedSize self.assertEqual( expectedSize, self.elementUnderTest.sizeBits ) self.mockObserver.update.assert_called_once() def testAssignSizeObserverNotNotified( self ) : self.assertIsNone( self.elementUnderTest.sizeBits ) expectedSize = 1 self.elementUnderTest.sizeBitsNoNotify = expectedSize self.assertEqual( expectedSize, self.elementUnderTest.sizeBits ) self.mockObserver.update.assert_not_called() if __name__ == '__main__' : unittest.main() PK&N$w@w@=registerMap/structure/memory/tests/testMemoryConfiguration.py""" Unit tests for MemorySpace. """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest import registerMap.structure.memory.configuration as rmm from registerMap.structure.elements.tests.mockObserver import MockObserver log = logging.getLogger( __name__ ) class TestBaseAddress( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() self.observer = MockObserver( ) self.thisSpace.addressChangeNotifier.addObserver( self.observer ) self.thisSpace.sizeChangeNotifier.addObserver( self.observer ) def testDefaultBaseAddress( self ) : expectedBaseAddress = 0 actualBaseAddress = self.thisSpace.baseAddress self.assertTrue( isinstance( actualBaseAddress, int ) ) self.assertEqual( actualBaseAddress, expectedBaseAddress ) self.assertEqual( self.observer.updateCount, 0 ) def testSetBaseAddressGoodValue( self ) : expectedBaseAddress = 25 # Don't test with the default value self.assertNotEqual( expectedBaseAddress, self.thisSpace.baseAddress ) self.thisSpace.baseAddress = expectedBaseAddress actualBaseAddress = self.thisSpace.baseAddress self.assertEqual( actualBaseAddress, expectedBaseAddress ) self.assertEqual( self.observer.updateCount, 1 ) self.assertEqual( self.observer.arguments, 'baseAddress' ) def testNonIntRaises( self ) : expectedBaseAddress = '25' with self.assertRaisesRegex( rmm.ConfigurationError, '^Base address must be specified as non-negative integer' ) : self.thisSpace.baseAddress = expectedBaseAddress def testNegativeRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Base address must be specified as non-negative integer' ) : self.thisSpace.baseAddress = -1 def testBaseAddressGreaterThanMemoryAddressBitsRaises( self ) : self.thisSpace.addressBits = 4 expectedBaseAddress = 20 with self.assertRaisesRegex( rmm.ConfigurationError, '^Base address must be less than maximum addressable memory' ) : self.thisSpace.baseAddress = expectedBaseAddress class TestMaximumAddressableMemory( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() def testDefaultMaximumAddressableMemory( self ) : expectedMaximumAddressableMemory = pow( 2, self.thisSpace.addressBits ) actualMaximumAddressableMemory = self.thisSpace.maximumMemoryAddress self.assertEqual( actualMaximumAddressableMemory, expectedMaximumAddressableMemory ) def testSetNumberOfAddressBits( self ) : numberBits = 24 self.assertNotEqual( self.thisSpace.addressBits, numberBits ) self.thisSpace.addressBits = numberBits self.assertEqual( self.thisSpace.addressBits, numberBits ) self.assertEqual( self.thisSpace.maximumMemoryAddress, pow( 2, numberBits ) ) class TestMemoryAddress( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() self.observer = MockObserver( ) self.thisSpace.addressChangeNotifier.addObserver( self.observer ) def testDefaultMemoryAddressBits( self ) : expectedMemoryAddressBits = 32 actualMemoryAddressBits = self.thisSpace.addressBits self.assertTrue( isinstance( actualMemoryAddressBits, int ) ) self.assertEqual( actualMemoryAddressBits, expectedMemoryAddressBits ) def testSetGoodValue( self ) : expectedMemoryAddressBits = 20 self.assertNotEqual( expectedMemoryAddressBits, self.thisSpace.addressBits ) self.thisSpace.addressBits = expectedMemoryAddressBits actualMemoryAddressBits = self.thisSpace.addressBits self.assertEqual( actualMemoryAddressBits, expectedMemoryAddressBits ) def testNonIntRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Memory address bits must be specified as positive non-zero integer' ) : self.thisSpace.addressBits = '20' def testZeroNegativeRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Memory address bits must be specified as positive non-zero integer' ) : self.thisSpace.addressBits = 0 def testSetMemoryAddressBitsLessThanBaseAddressRaises( self ) : self.thisSpace.baseAddress = 20 expectedMemoryAddressBits = 4 with self.assertRaisesRegex( rmm.ConfigurationError, '^Addressable memory must be greater than the base address' ) : self.thisSpace.addressBits = expectedMemoryAddressBits def testNonePageSizeNoNotifyOnChange( self ) : self.assertIsNone( self.thisSpace.pageSize ) self.assertEqual( self.observer.updateCount, 0 ) self.thisSpace.addressBits = 16 self.assertEqual( self.observer.updateCount, 0 ) def testAssignedPageSizeNotifyOnChange( self ) : self.thisSpace.pageSize = 0x80 # One notification for the page size change self.assertEqual( self.observer.updateCount, 1 ) self.assertEqual( self.observer.arguments, 'pageSize' ) self.thisSpace.addressBits = 16 self.assertEqual( self.observer.updateCount, 2 ) self.assertEqual( self.observer.arguments, 'addressBits' ) class TestMemoryUnit( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() self.observer = MockObserver( ) self.thisSpace.addressChangeNotifier.addObserver( self.observer ) def testDefaultMemoryUnitBits( self ) : expectedMemoryUnitBits = 8 actualMemoryUnitBits = self.thisSpace.memoryUnitBits self.assertTrue( isinstance( actualMemoryUnitBits, int ) ) self.assertEqual( actualMemoryUnitBits, expectedMemoryUnitBits ) def testDirectAssignment( self ) : expectedValue = 16 self.assertNotEqual( expectedValue, self.thisSpace.memoryUnitBits ) self.thisSpace.memoryUnitBits = expectedValue self.assertEqual( self.thisSpace.memoryUnitBits, expectedValue ) def testNonIntRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Memory unit bits must be specified as positive non-zero integer' ) : self.thisSpace.memoryUnitBits = '5' def testZeroRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Memory unit bits must be specified as positive non-zero integer' ) : self.thisSpace.memoryUnitBits = 0 def testNegativeRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Memory unit bits must be specified as positive non-zero integer' ) : self.thisSpace.memoryUnitBits = -1 def testNonePageSizeNoNotifyOnChange( self ) : self.assertIsNone( self.thisSpace.pageSize ) self.assertEqual( self.observer.updateCount, 0 ) self.thisSpace.memoryUnitBits = 16 self.assertEqual( self.observer.updateCount, 0 ) def testAssignedPageSizeNotifyOnChange( self ) : self.thisSpace.pageSize = 0x80 # One notification for the page size change self.assertEqual( self.observer.updateCount, 1 ) self.assertEqual( self.observer.arguments, 'pageSize' ) self.thisSpace.memoryUnitBits = 16 self.assertEqual( self.observer.updateCount, 2 ) self.assertEqual( self.observer.arguments, 'memoryUnitBits' ) class TestPageSize( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() self.observer = MockObserver( ) self.thisSpace.addressChangeNotifier.addObserver( self.observer ) def testDefaultPageSize( self ) : actualPageSize = self.thisSpace.pageSize self.assertIsNone( actualPageSize ) def testPageSizeAssignment( self ) : expectedPageSize = 128 self.assertNotEqual( expectedPageSize, self.thisSpace.pageSize ) self.thisSpace.pageSize = expectedPageSize actualPageSize = self.thisSpace.pageSize self.assertEqual( actualPageSize, expectedPageSize ) def testNonIntRaises( self ) : with self.assertRaisesRegex( rmm.ConfigurationError, '^Page size must be specified as integer' ) : self.thisSpace.pageSize = '5' def testNoneOkay( self ) : self.thisSpace.pageSize = None self.assertIsNone( self.thisSpace.pageSize ) def testPageSizeLessThanMemoryAddressRaises( self ) : expectedPageSize = 3 self.assertEqual( self.thisSpace.memoryUnitBits, 8 ) self.assertEqual( self.thisSpace.addressBits, 32 ) with self.assertRaisesRegex( rmm.ConfigurationError, '^Bad page size' ) : self.thisSpace.pageSize = expectedPageSize def testChangePageSizeNotifiesObserver( self ) : self.assertEqual( self.observer.updateCount, 0 ) self.thisSpace.pageSize = 0x80 self.assertEqual( self.observer.updateCount, 1 ) self.assertEqual( self.observer.arguments, 'pageSize' ) class TestPageRegisters( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() def testPageRegisters( self ) : self.thisSpace.addressBits = 32 self.thisSpace.memoryUnitBits = 8 expectedNumberPageRegisters = int( self.thisSpace.addressBits / self.thisSpace.memoryUnitBits ) self.thisSpace.pageSize = 0x80 expectedPageRegisterTest = [ True, True, True, True, False, False ] actualPageRegisterTest = list( ) for offset in range( expectedNumberPageRegisters, 0, -1 ) : thisAddress = (self.thisSpace.pageSize * 3) - offset actualPageRegisterTest.append( self.thisSpace.isPageRegister( thisAddress ) ) actualPageRegisterTest.append( self.thisSpace.isPageRegister( 5 * self.thisSpace.pageSize ) ) actualPageRegisterTest.append( self.thisSpace.isPageRegister( (self.thisSpace.pageSize * 4) - 5 ) ) self.assertEqual( actualPageRegisterTest, expectedPageRegisterTest ) def testPageBaseAddress( self ) : self.thisSpace.pageSize = 0x80 expectedPageBaseAddresses = [ self.thisSpace.pageSize * 2, self.thisSpace.pageSize * 4, self.thisSpace.pageSize * 7 ] testAddresses = [ expectedPageBaseAddresses[ 0 ], expectedPageBaseAddresses[ 1 ] + 0x7f, expectedPageBaseAddresses[ 2 ] + 3 ] for thisAddress, pageBaseAddress in zip( testAddresses, expectedPageBaseAddresses ) : actualPageBaseAddress = self.thisSpace.pageBaseAddress( thisAddress ) self.assertEqual( actualPageBaseAddress, pageBaseAddress ) class TestCalculatePageRegisterImpact( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() self.thisSpace.pageSize = 0x80 def testNoShiftNonPageRegister( self ) : self.assertEqual( self.thisSpace.addressBits, 32 ) self.assertEqual( self.thisSpace.memoryUnitBits, 8 ) expectedAddress = 0x27b actualAddress = self.thisSpace.calculatePageRegisterImpact( expectedAddress ) self.assertEqual( actualAddress, expectedAddress ) def testShiftOnPageRegister( self ) : self.assertEqual( self.thisSpace.addressBits, 32 ) self.assertEqual( self.thisSpace.memoryUnitBits, 8 ) expectedAddress = 0x400 inputAddress = 0x3fc actualAddress = self.thisSpace.calculatePageRegisterImpact( inputAddress ) self.assertEqual( actualAddress, expectedAddress ) class TestYamlLoadSave( unittest.TestCase ) : def setUp( self ) : self.thisSpace = rmm.MemoryConfiguration() def testEncodeDecode( self ) : encodedYamlData = self.thisSpace.to_yamlData( ) log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( encodedYamlData ) self.assertEqual( decodedMemorySpace.addressBits, self.thisSpace.addressBits ) self.assertEqual( decodedMemorySpace.baseAddress, self.thisSpace.baseAddress ) self.assertEqual( decodedMemorySpace.memoryUnitBits, self.thisSpace.memoryUnitBits ) self.assertEqual( decodedMemorySpace.pageSize, self.thisSpace.pageSize ) def testNonDefaultValues( self ) : self.thisSpace.baseAddress = 0x10 self.thisSpace.addressBits = 24 self.thisSpace.memoryUnitBits = 16 self.thisSpace.pageSize = 128 encodedYamlData = self.thisSpace.to_yamlData( ) log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( encodedYamlData ) self.assertEqual( decodedMemorySpace.addressBits, self.thisSpace.addressBits ) self.assertEqual( decodedMemorySpace.baseAddress, self.thisSpace.baseAddress ) self.assertEqual( decodedMemorySpace.memoryUnitBits, self.thisSpace.memoryUnitBits ) self.assertEqual( decodedMemorySpace.pageSize, self.thisSpace.pageSize ) def testOptionalAddressBits( self ) : yamlData = { 'memorySpace' : { 'baseAddress' : 0x10, 'memoryUnitBits' : 16, 'pageSizeMemoryUnits' : 128 } } decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( yamlData ) self.assertEqual( decodedMemorySpace.addressBits, 32 ) self.assertEqual( decodedMemorySpace.baseAddress, 0x10 ) self.assertEqual( decodedMemorySpace.memoryUnitBits, 16 ) self.assertEqual( decodedMemorySpace.pageSize, 128 ) def testOptionalBaseAddress( self ) : yamlData = { 'memorySpace' : { 'addressBits' : 24, 'memoryUnitBits' : 16, 'pageSizeMemoryUnits' : 128 } } decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( yamlData ) self.assertEqual( decodedMemorySpace.addressBits, 24 ) self.assertEqual( decodedMemorySpace.baseAddress, 0 ) self.assertEqual( decodedMemorySpace.memoryUnitBits, 16 ) self.assertEqual( decodedMemorySpace.pageSize, 128 ) def testOptionalMemoryUnitBits( self ) : yamlData = { 'memorySpace' : { 'addressBits' : 24, 'baseAddress' : 0x10, 'pageSizeMemoryUnits' : 128 } } decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( yamlData ) self.assertEqual( decodedMemorySpace.addressBits, 24 ) self.assertEqual( decodedMemorySpace.baseAddress, 0x10 ) self.assertEqual( decodedMemorySpace.memoryUnitBits, 8 ) self.assertEqual( decodedMemorySpace.pageSize, 128 ) def testOptionalPageSizeMemoryUnits( self ) : yamlData = { 'memorySpace' : { 'addressBits' : 24, 'memoryUnitBits' : 16, 'baseAddress' : 0x10 } } decodedMemorySpace = rmm.MemoryConfiguration.from_yamlData( yamlData ) self.assertEqual( decodedMemorySpace.addressBits, 24 ) self.assertEqual( decodedMemorySpace.baseAddress, 0x10 ) self.assertEqual( decodedMemorySpace.memoryUnitBits, 16 ) self.assertIsNone( decodedMemorySpace.pageSize ) if __name__ == '__main__' : unittest.main( ) PK&NZoo7registerMap/structure/memory/tests/testMemoryElement.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest from ..element import \ MemoryUnitMemoryElement, \ SizeValue log = logging.getLogger( __name__ ) class TestMemoryUnitsMemoryElementDefaultConstructor( unittest.TestCase ) : def setUp( self ) : self.memoryUnitBits = SizeValue( 8 ) def testDefaultArguments( self ) : testElement = MemoryUnitMemoryElement( self.memoryUnitBits ) self.assertIsNone( testElement.sizeBits ) self.assertIsNone( testElement.sizeMemoryUnits ) def testAssignSizeBits( self ) : testElement = MemoryUnitMemoryElement( self.memoryUnitBits ) testElement.sizeBits = 16 self.assertEqual( 16, testElement.sizeBits ) self.assertEqual( 2, testElement.sizeMemoryUnits ) def testAssignSizeMemoryUnits( self ) : testElement = MemoryUnitMemoryElement( self.memoryUnitBits ) testElement.sizeMemoryUnits = 4 self.assertEqual( 32, testElement.sizeBits ) self.assertEqual( 4, testElement.sizeMemoryUnits ) def testAssignSizeBitsRaises( self ) : """ Assigning a non integer multiple of memoryUnitBits raises an exception """ testElement = MemoryUnitMemoryElement( self.memoryUnitBits ) with self.assertRaisesRegex( RuntimeError, '^Cannot assign bits a non integer multiple of memory units' ) : testElement.sizeBits = 15 if __name__ == '__main__' : unittest.main() PK&NaT%registerMap/structure/set/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .elementSet import ElementSet class SetCollection : def __init__( self ) : self.fieldSet = ElementSet() self.moduleSet = ElementSet() self.registerSet = ElementSet() PK&Nգ. # import collections # https://code.activestate.com/recipes/576694/ class OrderedSet( collections.MutableSet ) : def __init__( self, iterable = None ) : self.end = end = [ ] end += [ None, end, end ] # sentinel node for doubly linked list self.map = { } # key --> [key, prev, next] if iterable is not None : self |= iterable def __len__( self ) : return len( self.map ) def __contains__( self, key ) : return key in self.map def add( self, key ) : if key not in self.map : end = self.end curr = end[ 1 ] curr[ 2 ] = end[ 1 ] = self.map[ key ] = [ key, curr, end ] def discard( self, key ) : if key in self.map : key, prev, next = self.map.pop( key ) prev[ 2 ] = next next[ 1 ] = prev def remove( self, key ) : if key in self.map : key, prev, next = self.map.pop( key ) prev[ 2 ] = next next[ 1 ] = prev else : raise KeyError( 'item not in set' ) def __iter__( self ) : end = self.end curr = end[ 2 ] while curr is not end : yield curr[ 0 ] curr = curr[ 2 ] def __reversed__( self ) : end = self.end curr = end[ 1 ] while curr is not end : yield curr[ 0 ] curr = curr[ 1 ] def pop( self, last = True ) : if not self : raise KeyError( 'set is empty' ) key = self.end[ 1 ][ 0 ] if last else self.end[ 2 ][ 0 ] self.discard( key ) return key def __repr__( self ) : if not self : return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list( self )) def __eq__( self, other ) : if isinstance( other, OrderedSet ) : return len( self ) == len( other ) and list( self ) == list( other ) return set( self ) == set( other ) class ElementSet( OrderedSet ) : def __init__( self ) : super().__init__() def find( self, name ) : """ Find Element's in the ElementSet with the specified name. Assumes Element's have a name property for comparison. :param name: Name of Element to find in set. :return: Set of Element. """ foundFromName = { x for x in self if x[ 'name' ] == name } return foundFromName PK&N}]" " %registerMap/structure/set/fieldSet.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import registerMap.structure.set.elementSet as rmese from registerMap.exceptions import ConfigurationError class FieldSet( rmese.ElementSet ) : def __init__( self ) : super().__init__() def add( self, bitField ) : """ Add a specified bit field. :param bitField: :return: """ globalStateOfSameName = self.findGlobalStateSameName( bitField[ 'name' ] ) if (not any( globalStateOfSameName )) \ or (not bitField[ 'global' ]) : # A non-global bit field must always be added. # A global bit field can only be added if there is no existing global bit field with that name. super().add( bitField ) else : raise ConfigurationError( 'Only one global field of a name can exist, {0}'.format( bitField[ 'name' ] ) ) def remove( self, bitField ) : """ Remove a specified bit field. :param bitField: :return: """ try : super().remove( bitField ) except KeyError as e : raise ConfigurationError( 'Field does not exist in set, {0}'.format( bitField[ 'name' ] ) ) def findGlobalStateSameName( self, name ) : """ Find the global state of Bit Fields with the same name. :param name: Bit Field name to search for. :return: List of the global state of each found Bit Field. """ sameName = self.find( name ) globalSame = list() for x in sameName : globalSame.append( x[ 'global' ] ) return globalSame PK&N+registerMap/structure/set/tests/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N6registerMap/structure/set/tests/elementSet/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N`<registerMap/structure/set/tests/elementSet/testElementSet.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest import registerMap.structure.set.elementSet as rmese class MockElement( object ) : def __init__( self, name = 'testElement' ) : self.__data = dict() self.__data[ 'name' ] = name def __getitem__( self, item ) : return self.__data[ item ] class TestConstructElementSet( unittest.TestCase ) : def testDefaultConstructor( self ) : s = rmese.ElementSet() self.assertEqual( len( s ), 0 ) class ElementSetTestBase( object ) : def getTestType( self ) : """ Children may override this method to deliver their class under test for testing. :return: Type to be used for testing. """ return rmese.ElementSet def generateElement( self, name = None ) : """ Children may override this method to deliver a set element for test. :param name: :return: """ if name is None : return MockElement() else : return MockElement( name = name ) class TestElementSetAdd( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.testSet = self.getTestType()() def testAddElement( self ) : self.assertEqual( len( self.testSet ), 0 ) self.testSet.add( self.generateElement() ) self.assertEqual( len( self.testSet ), 1 ) class TestElementSetDiscard( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.element = self.generateElement() self.testSet = self.getTestType()() self.testSet.add( self.element ) def testDiscardElement( self ) : self.assertEqual( len( self.testSet ), 1 ) self.testSet.discard( self.element ) self.assertEqual( len( self.testSet ), 0 ) def testDiscardAbsentElement( self ) : self.assertEqual( len( self.testSet ), 1 ) self.testSet.discard( self.generateElement() ) # The element in the set is not the same element being discarded, so the set doesn't change. self.assertEqual( len( self.testSet ), 1 ) class TestElementSetRemove( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.element = self.generateElement() self.testSet = self.getTestType()() self.testSet.add( self.element ) def testRemoveElement( self ) : self.assertEqual( len( self.testSet ), 1 ) self.testSet.remove( self.element ) self.assertEqual( len( self.testSet ), 0 ) def testRemoveAbsentElementRaises( self ) : self.assertEqual( len( self.testSet ), 1 ) with self.assertRaises( KeyError ) : self.testSet.remove( self.generateElement() ) class TestElementSetOrder( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.testSet = self.getTestType()() def testSetOrder( self ) : numberElements = 5 expectedOrderedNames = [ ] # Add the elements in order for x in range( 0, numberElements ) : expectedOrderedNames.append( repr( x ) ) self.testSet.add( self.generateElement( name = expectedOrderedNames[ x ] ) ) elements = list( self.testSet ) actualOrderedNames = [ x[ 'name' ] for x in elements ] self.assertEqual( actualOrderedNames, expectedOrderedNames ) class TestElementSetSingleElement( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.testSet = self.getTestType()() numberElements = 1 for thisIndex in range( 0, numberElements ) : thisName = '{0}'.format( thisIndex ) self.testSet.add( self.generateElement( name = thisName ) ) def testFindSingleItem( self ) : self.assertEqual( len( self.testSet ), 1 ) x = list( self.testSet ) self.assertEqual( x[ 0 ][ 'name' ], '0' ) # Look for the only item known to be in the set. actualItemsFound = self.testSet.find( '0' ) self.assertEqual( len( actualItemsFound ), 1 ) y = list( actualItemsFound ) self.assertEqual( y[ 0 ][ 'name' ], '0' ) def testItemsFoundEmptyWhenElementNotInSet( self ) : self.assertEqual( len( self.testSet ), 1 ) x = list( self.testSet ) self.assertEqual( x[ 0 ][ 'name' ], '0' ) # Look for an item known to not be in the set. actualItemsFound = self.testSet.find( 'a' ) # Items found is empty. self.assertEqual( len( actualItemsFound ), 0 ) class TestElementSetMultipleElements( unittest.TestCase, ElementSetTestBase ) : def setUp( self ) : self.testSet = self.getTestType()() for i in range( 0, 4 ) : self.testSet.add( self.generateElement( name = repr( i ) ) ) self.numberRepeatedElements = 3 for i in range( 0, self.numberRepeatedElements ) : self.testSet.add( self.generateElement( name = 'a' ) ) def testFindMultipleItems( self ) : # Look for the items known to be in the set. actualItemsFound = self.testSet.find( 'a' ) self.assertEqual( len( actualItemsFound ), self.numberRepeatedElements ) if __name__ == '__main__' : unittest.main() PK&N4registerMap/structure/set/tests/fieldSet/__init__.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&N|8registerMap/structure/set/tests/fieldSet/testAddField.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field import Field from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.set.fieldSet import \ ConfigurationError, \ FieldSet from registerMap.structure.memory.configuration import MemoryConfiguration class TestAddField( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.setUnderTest = FieldSet() self.register = RegisterInstance( self.memory, setCollection = self.setUnderTest ) def testAddSingleFieldOkay( self ) : """ When: a first bit field with the default name is added Then: the size of the bit field set is 1 """ b = Field( parent = self.register ) self.assertEqual( len( self.setUnderTest ), 0 ) self.setUnderTest.add( b ) self.assertEqual( len( self.setUnderTest ), 1 ) def testAddNonGlobalFieldsOkay( self ) : """ When: a second bit field is added And: the new bit field has the same name as the first bit field And: the new bit field is defined as non-global And: the first bit field is defined as non-global Then: the size of the bit field set is 2 """ b1 = Field( parent = self.register ) b2 = Field( parent = self.register ) self.assertEqual( len( self.setUnderTest ), 0 ) self.setUnderTest.add( b1 ) self.setUnderTest.add( b2 ) self.assertEqual( len( self.setUnderTest ), 2 ) def testAddGlobalFieldsRaises( self ) : """ When: a second bit field is added And: the new bit field has the same name as the first bit field And: the new bit field is defined as global And: the first bit field is defined as global Then: an exception is raised """ b1 = Field() b2 = Field() self.assertEqual( len( self.setUnderTest ), 0 ) self.setUnderTest.add( b1 ) with self.assertRaisesRegex( ConfigurationError, '^Only one global field of a name can exist' ) : self.setUnderTest.add( b2 ) def testAddGlobalFieldNonGlobalBitFieldOkay( self ) : """ When: a second bit field is added And: the new bit field has the same name as the first bit field And: the new bit field is defined as global And: the first bit field is defined as non-global Then: the size of the bit field set is 2 """ b1 = Field( parent = self.register ) self.assertFalse( b1[ 'global' ] ) b2 = Field() self.assertTrue( b2[ 'global' ] ) self.assertEqual( len( self.setUnderTest ), 0 ) self.setUnderTest.add( b1 ) self.setUnderTest.add( b2 ) self.assertEqual( len( self.setUnderTest ), 2 ) def testAddNonGlobalFieldGlobalBitFieldOkay( self ) : """ When: a second bit field is added And: the new bit field has the same name as the first bit field And: the new bit field is defined as non-global And: the first bit field is defined as global Then: the size of the bit field set is 2 """ b1 = Field() b2 = Field( parent = self.register ) self.assertEqual( len( self.setUnderTest ), 0 ) self.setUnderTest.add( b1 ) self.setUnderTest.add( b2 ) self.assertEqual( len( self.setUnderTest ), 2 ) class TestFieldSetMultipleElements( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.setUnderTest = FieldSet() self.numberUniqueElements = 4 for i in range( 0, self.numberUniqueElements ) : f = Field() f[ 'name' ] = repr( i ) self.setUnderTest.add( f ) self.numberRepeatedElements = 3 self.registers = list() for i in range( 0, self.numberRepeatedElements ) : self.registers.append( RegisterInstance( self.memory, setCollection = self.setUnderTest ) ) f = Field( parent = self.registers[ i ] ) f[ 'name' ] = 'a' self.setUnderTest.add( f ) def testFindMultipleItems( self ) : # Look for the items known to be in the set. actualItemsFound = self.setUnderTest.find( 'a' ) self.assertEqual( len( self.setUnderTest ), (self.numberRepeatedElements + self.numberUniqueElements) ) self.assertEqual( len( actualItemsFound ), self.numberRepeatedElements ) if __name__ == '__main__' : unittest.main() PK&N0~T 8registerMap/structure/set/tests/fieldSet/testFieldSet.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field import Field from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.set.fieldSet import FieldSet from registerMap.structure.memory.configuration import MemoryConfiguration from registerMap.structure.set.tests.elementSet import testElementSet as rmstes class TestConstructFieldSet( unittest.TestCase ) : def testDefaultConstructor( self ) : b = FieldSet() self.assertEqual( len( b ), 0 ) class TestSetAdd( rmstes.TestElementSetAdd ) : def getTestType( self ) : return FieldSet def generateElement( self, name = None ) : f = Field() return f class TestSetDiscard( rmstes.TestElementSetDiscard ) : def getTestType( self ) : return FieldSet def generateElement( self, name = None ) : f = Field() return f class TestSetSingleElement( rmstes.TestElementSetSingleElement ) : def getTestType( self ) : return FieldSet def generateElement( self, name = None ) : f = Field() f[ 'name' ] = name return f class TestSetMultipleElements( rmstes.TestElementSetMultipleElements ) : memory = MemoryConfiguration() registers = list() fieldSet = FieldSet() def getTestType( self ) : return FieldSet def generateElement( self, name = None ) : self.registers.append( RegisterInstance( self.memory, setCollection = self.fieldSet ) ) f = Field( parent = self.registers[ -1 ] ) f[ 'name' ] = name return f if __name__ == '__main__' : unittest.main() PK&Nb ;registerMap/structure/set/tests/fieldSet/testRemoveField.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from registerMap.structure.elements.field import Field from registerMap.structure.elements.register import RegisterInstance from registerMap.structure.set.fieldSet import \ ConfigurationError, \ FieldSet from registerMap.structure.memory.configuration import MemoryConfiguration class TestRemoveField( unittest.TestCase ) : def setUp( self ) : self.memory = MemoryConfiguration() self.setUnderTest = FieldSet() self.register = RegisterInstance( self.memory, setCollection = self.setUnderTest ) def testNonexistentFieldRemoveRaises( self ) : """ When: a bit field is removed And: the bit field does not exist in the bit field set Then: an exception is raised """ bf = Field() self.assertEqual( len( self.setUnderTest ), 0 ) with self.assertRaisesRegex( ConfigurationError, '^Field does not exist in set' ) : self.setUnderTest.remove( bf ) def testSingleNonGlobalFieldRemove( self ) : """ When: a bit field is removed And: the bit field exists in the bit field set And: the bit field is defined as non-global Then: the size of the bit field set is reduced by 1 """ def checkInitialSet() : nonlocal self, expectedName self.assertEqual( len( self.setUnderTest ), 1 ) bitFields = self.setUnderTest.find( expectedName ) self.assertEqual( len( bitFields ), 1 ) thisField = bitFields.pop() self.assertEqual( thisField[ 'global' ], False ) expectedName = 'test' bf = Field( parent = self.register ) bf[ 'name' ] = expectedName self.setUnderTest.add( bf ) checkInitialSet() self.setUnderTest.remove( bf ) self.assertEqual( len( self.setUnderTest ), 0 ) def testSingleGlobalFieldRemove( self ) : """ When: a bit field is removed And: there is a single bit field in the bit field set And: the bit field is defined as non-global Then: the size of the bit field set is reduced by 1 """ def checkInitialSet() : nonlocal self, expectedName self.assertEqual( len( self.setUnderTest ), 1 ) bitFields = self.setUnderTest.find( expectedName ) self.assertEqual( len( bitFields ), 1 ) thisField = bitFields.pop() self.assertEqual( thisField[ 'global' ], True ) expectedName = 'test' bf = Field() bf[ 'name' ] = expectedName self.assertTrue( bf[ 'global' ] ) self.setUnderTest.add( bf ) checkInitialSet() self.setUnderTest.remove( bf ) self.assertEqual( len( self.setUnderTest ), 0 ) if __name__ == '__main__' : unittest.main() PK&NregisterMap/tests/__init__.pyPK&NjVU#registerMap/tests/expectedActual.py# # Copyright 2017 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # def simpleComparison( testObject, actualValue, expectedValue, valueTypeText ) : testObject.assertTrue( (actualValue == expectedValue), ('Unexpected ' + valueTypeText + ': ' + repr( actualValue ) + ' (actual) ' + repr( expectedValue ) + ' (expected)') ) PK&N5~!registerMap/tests/testExporter.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import io import unittest.mock import yaml from ..exporter import \ acquireRegisterMap, \ main from ..registerMap import RegisterMap from ..export.arguments import parseArguments from ..export.cpp.registerMap import Output class ParseArgumentsSideEffect : def __init__( self ) : self.mock_generator = None self.options = None def __call__( self, commandLineArguments ) : self.options = parseArguments( commandLineArguments ) self.mock_generator = unittest.mock.create_autospec( Output ) self.options.languageOptions.generator = self.mock_generator return self.options class TestAcquireRegisterMap( unittest.TestCase ) : def testEmptyRegisterMap( self ) : mock_yamlContent = io.StringIO( '' ) with unittest.mock.patch( 'registerMap.exporter.open', return_value = mock_yamlContent ) : actualValue = acquireRegisterMap( 'some/path' ) self.assertIsNone( actualValue ) class TestExporter( unittest.TestCase ) : def setUp( self ) : self.parserSideEffect = ParseArgumentsSideEffect() self.registerMap = RegisterMap() m1 = self.registerMap.addModule( 'm1' ) r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 10) ) r2 = m1.addRegister( 'r2' ) r2.addField( 'f1', (0, 2) ) r2.addField( 'f2', (5, 7) ) def testExporterSequence( self ) : inputValue = [ 'registerMap/path', '--license-file', 'licenseFile/text', 'c++', 'output/path' ] expectedLicenseLines = [ 'a small\n', 'license text\n', ] inputLicenseText = ''.join( expectedLicenseLines ) with unittest.mock.patch( 'registerMap.exporter.parseArguments', side_effect = self.parserSideEffect ), \ unittest.mock.patch( 'registerMap.exporter.open', return_value = io.StringIO( inputLicenseText ) ), \ unittest.mock.patch( 'registerMap.exporter.acquireRegisterMap', return_value = self.registerMap ) as mock_acquireRegisterMap : main( inputValue ) mock_acquireRegisterMap.assert_called_once_with( self.parserSideEffect.options.registerMapFile ) # Check that the generator was instantiated correctly. self.parserSideEffect.mock_generator.assert_called_once_with( self.parserSideEffect.options.languageOptions, licenseTextLines = expectedLicenseLines ) # Check that the generate method was called correctly. generatorInstance = self.parserSideEffect.mock_generator.return_value generatorInstance.generate.assert_called_once_with( self.registerMap, self.parserSideEffect.options.registerMapName ) def testLicenseFileNone( self ) : inputValue = [ 'registerMap/path', 'c++', 'output/path' ] with unittest.mock.patch( 'registerMap.exporter.parseArguments', side_effect = self.parserSideEffect ), \ unittest.mock.patch( 'registerMap.exporter.acquireRegisterMap', return_value = self.registerMap ) as mock_acquireRegisterMap : main( inputValue ) mock_acquireRegisterMap.assert_called_once_with( self.parserSideEffect.options.registerMapFile ) mock_generatorInstance = self.parserSideEffect.mock_generator.return_value mock_generatorInstance.generate.assert_called_once_with( self.registerMap, self.parserSideEffect.options.registerMapName ) # Check for the default register map name since no license file specified. self.assertEqual( 'registerMap', self.parserSideEffect.options.registerMapName ) if __name__ == '__main__' : unittest.main() PK&N%*registerMap/tests/testModuleConstraints.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..registerMap import RegisterMap from ..exceptions import ConstraintError class TestModuleFixedAddressConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.moduleUnderTest = self.registerMap.addModule( 'm1' ) def testFixedAddressOk( self ) : self.assertEqual( 0x0, self.registerMap.memory.baseAddress ) self.assertEqual( self.registerMap.memory.baseAddress, self.moduleUnderTest.baseAddress ) expectedValue = 0x20f0 self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = expectedValue # The register map base address is unchanged. self.assertEqual( 0x0, self.registerMap.memory.baseAddress ) # The module has the specified base address. self.assertEqual( expectedValue, self.moduleUnderTest.baseAddress ) class TestModuleFixedSizeConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.moduleUnderTest = self.registerMap.addModule( 'm1' ) def testFixedSizeOk( self ) : self.assertEqual( 0, self.moduleUnderTest.spanMemoryUnits ) expectedValue = 10 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = expectedValue self.assertEqual( expectedValue, self.moduleUnderTest.spanMemoryUnits ) def testExceededSizeRegisterAddRaises( self ) : moduleSize = 3 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = moduleSize for i in range( 0, moduleSize ) : self.moduleUnderTest.addRegister( 'r{0}'.format( i ) ) # Attempting to add a fourth register to a module constrained to size 3 raises an exception. with self.assertRaisesRegex( ConstraintError, '^Fixed size exceeded' ) : self.moduleUnderTest.addRegister( 'r3' ) def testExceededSizeConstraintTooSmallRaises( self ) : moduleSize = 3 for i in range( 0, moduleSize ) : self.moduleUnderTest.addRegister( 'r{0}'.format( i ) ) self.assertEqual( moduleSize, self.moduleUnderTest.spanMemoryUnits ) # Attempting to constrain the size smaller than the allocated registers raises with self.assertRaisesRegex( ConstraintError, '^Fixed size exceeded' ) : self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = moduleSize - 1 class TestModuleMemoryAlignmentConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() # Assign an unaligned base address to the map. self.registerMap.memory.baseAddress = 0x1 self.moduleUnderTest = self.registerMap.addModule( 'm1' ) def testWordAlignedAddress( self ) : self.assertEqual( 8, self.registerMap.memory.memoryUnitBits ) self.assertEqual( self.registerMap.memory.baseAddress, self.moduleUnderTest.baseAddress ) # Align the module start address to 32 bit (8 bits * 4 memory units). self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 self.assertEqual( 0x4, self.moduleUnderTest.baseAddress ) class TestModuleConstraintCombinations( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.moduleUnderTest = self.registerMap.addModule( 'm1' ) def testFixedAddressAndAlignmentOk( self ) : # Applying memory alignment to a fixed address that is memory aligned is fine (implicitly, if in future # the fixed address is changed to an unaligned address then an exception will be raised) self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 def testFixedAddressAndAlignmentRaises( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x1 with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 def testFixedAddressAndAlignmentWithAddressChangeRaises( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x5 def testFixedAddressAndSizeOk( self ) : self.moduleUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 4 def testAlignmentAndSizeOk( self ) : self.moduleUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 self.moduleUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 4 if __name__ == '__main__' : unittest.main() PK&NZN,,,registerMap/tests/testRegisterConstraints.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..registerMap import RegisterMap from ..exceptions import ConstraintError class TestRegisterFixedAddressConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module = self.registerMap.addModule( 'm1' ) self.r1 = self.module.addRegister( 'r1' ) def testFixedAddressOk( self ) : """ Applying a fixed address constraint changes the address. """ self.assertEqual( 0x0, self.registerMap.memory.baseAddress ) self.assertEqual( self.registerMap.memory.baseAddress, self.module.baseAddress ) self.assertEqual( self.module.baseAddress, self.r1.startAddress ) expectedValue = 0x2000 self.r1[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.r1.startAddress ) def testFixedAddressAdjustsOtherRegisters( self ) : """ Applying a fixed address shuffles other registers appropriately. """ r2 = self.module.addRegister( 'r2' ) self.assertEqual( 0x0, self.registerMap.memory.baseAddress ) self.assertEqual( self.registerMap.memory.baseAddress, self.module.baseAddress ) self.assertEqual( self.module.baseAddress, self.r1.startAddress ) self.assertEqual( 1, self.r1.sizeMemoryUnits ) self.assertEqual( 1, r2.startAddress ) expectedValue = 0x2000 self.r1[ 'constraints' ][ 'fixedAddress' ] = expectedValue self.assertEqual( expectedValue, self.r1.startAddress ) self.assertEqual( (expectedValue + 1), r2.startAddress ) class TestRegisterFixedSizeConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module = self.registerMap.addModule( 'm1' ) self.register1 = self.module.addRegister( 'r1' ) self.registerUnderTest = self.module.addRegister( 'r2' ) def testFixedSizeOk( self ) : """ Show that when a fixed size constraint is applied, that the next register address is shifted appropriately. """ self.assertEqual( self.module.baseAddress, self.register1.startAddress ) self.assertEqual( (self.register1.startAddress + 1), self.registerUnderTest.startAddress ) expectedSize = 5 self.register1[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = expectedSize expectedAddress = self.register1.startAddress + expectedSize self.assertEqual( expectedAddress, self.registerUnderTest.startAddress ) class TestRegisterMemoryAlignmentConstraint( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.registerMap.memory.baseAddress = 0x1 self.module = self.registerMap.addModule( 'm1' ) self.registerUnderTest = self.module.addRegister( 'r1' ) def testMemoryAlignmentOk( self ) : """ Show that address alignment shuffles a register address appropriately. """ self.assertEqual( 0x1, self.registerMap.memory.baseAddress ) self.assertEqual( self.registerMap.memory.baseAddress, self.module.baseAddress ) self.assertEqual( self.registerMap.memory.baseAddress, self.registerUnderTest.startAddress ) self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 expectedValue = 0x4 self.assertEqual( expectedValue, self.registerUnderTest.startAddress ) class TestRegisterConstraintCombinations( unittest.TestCase ) : def setUp( self ) : self.registerMap = RegisterMap() self.module = self.registerMap.addModule( 'm1' ) self.registerUnderTest = self.module.addRegister( 'r1' ) def testFixedAddressAndAlignmentOk( self ) : """ Applying memory alignment to a fixed address that is memory aligned is fine (implicitly, if in future the fixed address is changed to an unaligned address then an exception will be raised) """ self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 def testFixedAddressAndAlignmentRaises( self ) : """ Show that an exception is raised when alignment conflicts with a fixed address. """ self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x1 with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 def testFixedAddressAndAlignmentWithAddressChangeRaises( self ) : """ Show that an exception is raised when a fixed address is changed that conflicts with existing constraints. """ self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 with self.assertRaisesRegex( ConstraintError, '^Address constraints conflict' ) : self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x5 def testFixedAddressAndSizeOk( self ) : """ Show that non conflicting fixed address and fixed size constraints are okay. """ self.registerUnderTest[ 'constraints' ][ 'fixedAddress' ] = 0x4 self.registerUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 4 def testAlignmentAndSizeOk( self ) : """ Show that non conflicting alignment and fixed size constraints are okay. """ self.registerUnderTest[ 'constraints' ][ 'alignmentMemoryUnits' ] = 4 self.registerUnderTest[ 'constraints' ][ 'fixedSizeMemoryUnits' ] = 4 if __name__ == '__main__' : unittest.main() PK&NU%%$registerMap/tests/testRegisterMap.py""" Unit tests for RegisterMap """ # # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging import unittest from registerMap.registerMap import \ ConfigurationError, \ Module, \ RegisterMap log = logging.getLogger( __name__ ) class TestDefaultModuleInstantiation( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultValues( self ) : self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( self.thisMap.assignedMemoryUnits, 0 ) class TestBaseAddress( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultBaseAddress( self ) : expectedBaseAddress = 0 actualBaseAddress = self.thisMap.memory.baseAddress self.assertTrue( isinstance( actualBaseAddress, int ) ) self.assertEqual( actualBaseAddress, expectedBaseAddress ) def testSetBaseAddressGoodValue( self ) : expectedBaseAddress = 25 # Don't test with the default value self.assertNotEqual( expectedBaseAddress, self.thisMap.memory.baseAddress ) self.thisMap.memory.baseAddress = expectedBaseAddress actualBaseAddress = self.thisMap.memory.baseAddress self.assertEqual( actualBaseAddress, expectedBaseAddress ) class TestMemoryAddress( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultMemoryAddressBits( self ) : expectedMemoryAddressBits = 32 actualMemoryAddressBits = self.thisMap.memory.addressBits self.assertTrue( isinstance( actualMemoryAddressBits, int ) ) self.assertEqual( actualMemoryAddressBits, expectedMemoryAddressBits ) def testSetGoodValue( self ) : expectedMemoryAddressBits = 20 self.assertNotEqual( expectedMemoryAddressBits, self.thisMap.memory.addressBits ) self.thisMap.memory.addressBits = expectedMemoryAddressBits actualMemoryAddressBits = self.thisMap.memory.addressBits self.assertEqual( actualMemoryAddressBits, expectedMemoryAddressBits ) class TestMemoryUnit( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultMemoryUnitBits( self ) : expectedMemoryUnitBits = 8 actualMemoryUnitBits = self.thisMap.memory.memoryUnitBits self.assertTrue( isinstance( actualMemoryUnitBits, int ) ) self.assertEqual( actualMemoryUnitBits, expectedMemoryUnitBits ) class TestPageSize( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultPageSize( self ) : actualPageSize = self.thisMap.memory.pageSize self.assertIsNone( actualPageSize ) def testPageSizeAssignment( self ) : expectedPageSize = 128 self.assertNotEqual( expectedPageSize, self.thisMap.memory.pageSize ) self.thisMap.memory.pageSize = expectedPageSize actualPageSize = self.thisMap.memory.pageSize self.assertEqual( actualPageSize, expectedPageSize ) class TestRegisterMapModules( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testDefaultModules( self ) : self.assertTrue( isinstance( self.thisMap[ 'modules' ], dict ) ) self.assertEqual( len( self.thisMap[ 'modules' ] ), 0 ) class TestAddModule( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testAddSingleModule( self ) : self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 0, len( self.thisMap[ 'modules' ] ) ) newModule = self.thisMap.addModule( 'm1' ) self.assertEqual( 0, self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 1, len( self.thisMap[ 'modules' ] ) ) self.assertTrue( isinstance( newModule, Module ) ) self.assertEqual( newModule.baseAddress, self.thisMap.memory.baseAddress ) def testAddDuplicateModuleNameRaises( self ) : self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 0, len( self.thisMap[ 'modules' ] ) ) self.thisMap.addModule( 'm1' ) with self.assertRaisesRegex( ConfigurationError, '^Created module names must be unique within a register map' ) : self.thisMap.addModule( 'm1' ) class TestModuleAddresses( unittest.TestCase ) : def setUp( self ) : self.thisMap = RegisterMap() def testBaseAddressUpdate( self ) : self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 0, len( self.thisMap[ 'modules' ] ) ) m1 = self.thisMap.addModule( 'm1' ) self.assertEqual( 0, self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 1, len( self.thisMap[ 'modules' ] ) ) self.assertEqual( self.thisMap.memory.baseAddress, m1.baseAddress ) r1 = m1.addRegister( 'r1' ) self.assertEqual( 1, self.thisMap.spanMemoryUnits ) self.assertEqual( 1, self.thisMap.assignedMemoryUnits ) self.assertEqual( 1, len( self.thisMap[ 'modules' ] ) ) self.assertEqual( self.thisMap.memory.baseAddress, r1.startAddress ) self.thisMap.memory.baseAddress = 0x10 # Existing register and module must reflect the base address change. self.assertEqual( self.thisMap.memory.baseAddress, m1.baseAddress ) self.assertEqual( self.thisMap.memory.baseAddress, r1.startAddress ) def testModuleSequentialAddresses( self ) : self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 0, len( self.thisMap[ 'modules' ] ) ) m1 = self.thisMap.addModule( 'm1' ) self.assertEqual( 0, self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 1, len( self.thisMap[ 'modules' ] ) ) self.assertEqual( self.thisMap.memory.baseAddress, m1.baseAddress ) r1 = m1.addRegister( 'r1' ) self.assertEqual( 1, self.thisMap.spanMemoryUnits ) self.assertEqual( 1, self.thisMap.assignedMemoryUnits ) self.assertEqual( 1, len( self.thisMap[ 'modules' ] ) ) self.assertEqual( self.thisMap.memory.baseAddress, r1.startAddress ) m2 = self.thisMap.addModule( 'm2' ) r2 = m2.addRegister( 'r2' ) self.thisMap.memory.baseAddress = 0x10 # Existing registers and modules must reflect the base address change. self.assertEqual( self.thisMap.memory.baseAddress, m1.baseAddress ) self.assertEqual( self.thisMap.memory.baseAddress, r1.startAddress ) self.assertEqual( (self.thisMap.memory.baseAddress + 1), m2.baseAddress ) self.assertEqual( (self.thisMap.memory.baseAddress + 1), r2.startAddress ) def testAssignedCount( self ) : self.assertEqual( 8, self.thisMap.memory.memoryUnitBits ) self.assertIsNone( self.thisMap.spanMemoryUnits ) self.assertEqual( 0, self.thisMap.assignedMemoryUnits ) self.assertEqual( 0, len( self.thisMap[ 'modules' ] ) ) m1 = self.thisMap.addModule( 'm1' ) r1 = m1.addRegister( 'r1' ) m2 = self.thisMap.addModule( 'm2' ) r2 = m2.addRegister( 'r2' ) r2.addField( 'f2', [ 3, 10 ], (3, 10) ) r2[ 'constraints' ][ 'fixedAddress' ] = 0x15 log.debug( 'm1 address before base assigment: ' + hex( m1.baseAddress ) ) log.debug( 'm2 address before base assigment: ' + hex( m2.baseAddress ) ) log.debug( 'r1 address before base assigment: ' + hex( r1.startAddress ) ) log.debug( 'r2 address before base assigment: ' + hex( r2.startAddress ) ) self.assertEqual( 3, self.thisMap.assignedMemoryUnits ) self.assertEqual( 23, self.thisMap.spanMemoryUnits ) log.debug( 'register map base address assignment' ) self.thisMap.memory.baseAddress = 0x10 log.debug( 'm1 address after base assigment: ' + hex( m1.baseAddress ) ) log.debug( 'm2 address after base assigment: ' + hex( m2.baseAddress ) ) log.debug( 'r1 address after base assigment: ' + hex( r1.startAddress ) ) log.debug( 'r2 address after base assigment: ' + hex( r2.startAddress ) ) self.assertEqual( 1, m1.spanMemoryUnits ) self.assertEqual( 6, m2.spanMemoryUnits ) expectedRegisterMapSpan = m1.spanMemoryUnits + m2.spanMemoryUnits self.assertEqual( 3, self.thisMap.assignedMemoryUnits ) self.assertEqual( expectedRegisterMapSpan, self.thisMap.spanMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&N.\- - *registerMap/tests/testRegisterMapLength.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..registerMap import RegisterMap class TestRegisterMapLen( unittest.TestCase ) : def setUp( self ) : self.mapUnderTest = RegisterMap() self.assertEqual( len( self.mapUnderTest ), 0 ) def testModuleLen1( self ) : self.mapUnderTest.addModule( 'myModule' ) self.assertEqual( len( self.mapUnderTest ), 1 ) def testRegisterLen2( self ) : myModule = self.mapUnderTest.addModule( 'myModule' ) myModule.addRegister( 'myRegister' ) self.assertEqual( len( self.mapUnderTest ), 2 ) def testFieldLen3( self ) : myModule = self.mapUnderTest.addModule( 'myModule' ) myRegister = myModule.addRegister( 'myRegister' ) myRegister.addField( 'myField', [ 0, 3 ] ) self.assertEqual( len( self.mapUnderTest ), 3 ) def testSecondLocalFieldLen4( self ) : myModule = self.mapUnderTest.addModule( 'myModule' ) myRegister = myModule.addRegister( 'myRegister' ) myRegister.addField( 'myField', [ 0, 3 ] ) myRegister.addField( 'myOtherField', [ 0, 3 ] ) self.assertEqual( len( self.mapUnderTest ), 4 ) def testGlobalFieldLen3( self ) : myModule = self.mapUnderTest.addModule( 'myModule' ) myRegister = myModule.addRegister( 'myRegister' ) myRegister.addField( 'myField', [ 0, 3 ], (0, 3), isGlobal = True ) myRegister.addField( 'myField', [ 4, 6 ], (4, 6), isGlobal = True ) self.assertEqual( len( self.mapUnderTest ), 3 ) if __name__ == '__main__' : unittest.main() PK&N u>>(registerMap/tests/testRegisterMapSpan.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import unittest from ..registerMap import RegisterMap class TestRegisterMapSpan( unittest.TestCase ) : def setUp( self ) : self.mapUnderTest = RegisterMap() def testContiguousRegisterSpan( self ) : m1 = self.mapUnderTest.addModule( 'm1' ) # Two byte register r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) self.assertEqual( 2, r1.sizeMemoryUnits ) expectedModuleSize = r1.sizeMemoryUnits self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) # Single byte register r2 = m1.addRegister( 'r2' ) r2.addField( 'f1', (0, 3) ) r2.addField( 'f2', (4, 6) ) self.assertEqual( 1, r2.sizeMemoryUnits ) expectedModuleSize = r1.sizeMemoryUnits + r2.sizeMemoryUnits self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) self.assertEqual( expectedModuleSize, self.mapUnderTest.spanMemoryUnits ) def testContiguousRegisterSpanMultipleModules( self ) : m1 = self.mapUnderTest.addModule( 'm1' ) # Two byte register r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) self.assertEqual( 2, r1.sizeMemoryUnits ) expectedModuleSize = r1.sizeMemoryUnits self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) m2 = self.mapUnderTest.addModule( 'm2' ) # Single byte register r2 = m2.addRegister( 'r2' ) r2.addField( 'f1', (0, 3) ) r2.addField( 'f2', (4, 6) ) self.assertEqual( 1, r2.sizeMemoryUnits ) expectedM1Size = r1.sizeMemoryUnits self.assertEqual( expectedM1Size, m1.spanMemoryUnits ) expectedM2Size = r2.sizeMemoryUnits self.assertEqual( expectedM2Size, m2.spanMemoryUnits ) expectedMapSize = expectedM1Size + expectedM2Size self.assertEqual( expectedMapSize, self.mapUnderTest.spanMemoryUnits ) def testDiscontiguousRegisterSpan( self ) : m1 = self.mapUnderTest.addModule( 'm1' ) # Two byte register r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) self.assertEqual( 2, r1.sizeMemoryUnits ) expectedModuleSize = r1.sizeMemoryUnits self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) # Three byte register r2 = m1.addRegister( 'r2' ) r2.addField( 'f1', (0, 3) ) r2.addField( 'f2', (4, 17) ) self.assertEqual( 3, r2.sizeMemoryUnits ) r2[ 'constraints' ][ 'fixedAddress' ] = 0x15 expectedModuleSize = r2.sizeMemoryUnits + r2.offset self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) self.assertEqual( expectedModuleSize, self.mapUnderTest.spanMemoryUnits ) def testDiscontiguousRegisterSpanMultipleModules( self ) : expectedM2AddressOffset = 0x15 self.assertEqual( 0, self.mapUnderTest.memory.baseAddress ) m1 = self.mapUnderTest.addModule( 'm1' ) # Two byte register r1 = m1.addRegister( 'r1' ) r1.addField( 'f1', (0, 11) ) self.assertEqual( 2, r1.sizeMemoryUnits ) expectedModuleSize = r1.sizeMemoryUnits self.assertEqual( expectedModuleSize, m1.spanMemoryUnits ) m2 = self.mapUnderTest.addModule( 'm2' ) m2[ 'constraints' ][ 'fixedAddress' ] = expectedM2AddressOffset # Single byte register r2 = m2.addRegister( 'r2' ) r2.addField( 'f1', (0, 3) ) r2.addField( 'f2', (4, 6) ) self.assertEqual( 1, r2.sizeMemoryUnits ) expectedM1Size = r1.sizeMemoryUnits self.assertEqual( expectedM1Size, m1.spanMemoryUnits ) expectedM2Size = r2.sizeMemoryUnits self.assertEqual( expectedM2Size, m2.spanMemoryUnits ) expectedMapSize = expectedM2AddressOffset + expectedM2Size self.assertEqual( expectedMapSize, self.mapUnderTest.spanMemoryUnits ) if __name__ == '__main__' : unittest.main() PK&NGGregisterMap/tests/testYamlIo.py# # Copyright 2017 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # import logging import unittest from registerMap.registerMap import \ ParseError, \ RegisterMap log = logging.getLogger( __name__ ) class TestYamlLoadSave( unittest.TestCase ) : def testEncodeDecode( self ) : m = RegisterMap() m.memory.addressBits = 48 m.memory.baseAddress = 0x1000 m.memory.memoryUnitBits = 16 m.memory.pageSize = 128 m[ 'description' ] = 'some description' m[ 'summary' ] = 'a summary' self.createSampleModule( m, 'm1' ) encodedYamlData = m.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedMap = RegisterMap.from_yamlData( encodedYamlData ) self.assertEqual( decodedMap.memory.addressBits, m.memory.addressBits ) self.assertEqual( decodedMap.memory.baseAddress, m.memory.baseAddress ) self.assertEqual( decodedMap.memory.memoryUnitBits, m.memory.memoryUnitBits ) self.assertEqual( decodedMap.memory.pageSize, m.memory.pageSize ) self.assertEqual( decodedMap[ 'description' ], m[ 'description' ] ) self.assertEqual( decodedMap[ 'summary' ], m[ 'summary' ] ) self.assertEqual( len( decodedMap[ 'modules' ] ), len( m[ 'modules' ] ) ) self.assertEqual( decodedMap[ 'modules' ][ 'm1' ][ 'name' ], 'm1' ) def createSampleModule( self, thisMap, moduleName ) : sampleModule = thisMap.addModule( moduleName ) registerName = 'r1' sampleModule.addRegister( registerName ) sampleModule[ 'registers' ][ registerName ][ 'constraints' ][ 'fixedAddress' ] = 0x1010 sampleModule[ 'registers' ][ registerName ][ 'description' ] = 'some description' sampleModule[ 'registers' ][ registerName ][ 'mode' ] = 'ro' sampleModule[ 'registers' ][ registerName ][ 'public' ] = False sampleModule[ 'registers' ][ registerName ][ 'summary' ] = 'a summary' sampleModule[ 'registers' ][ registerName ].addField( 'f1', [ 3, 5 ], (3, 5) ) sampleModule[ 'registers' ][ registerName ].addField( 'f2', [ 7, 7 ], (7, 7) ) def testFromBadYamlDataRaises( self ) : yamlData = { 'mode' : 'ro' } with self.assertRaisesRegex( ParseError, '^RegisterMap is not defined in yaml data' ) : RegisterMap.from_yamlData( yamlData, optional = False ) def testOptionalYamlData( self ) : yamlData = { 'mode' : 'ro' } m = RegisterMap.from_yamlData( yamlData, optional = True ) self.assertEqual( m.memory.addressBits, 32 ) self.assertEqual( m.memory.baseAddress, 0 ) self.assertEqual( m.memory.memoryUnitBits, 8 ) self.assertIsNone( m.memory.pageSize ) self.assertEqual( len( m[ 'modules' ] ), 0 ) def testSynchronization( self ) : thisMap = RegisterMap() thisMap.memory.addressBits = 48 thisMap.memory.baseAddress = 0 thisMap.memory.memoryUnitBits = 8 thisMap.memory.pageSize = None m1 = thisMap.addModule( 'm1' ) r1 = m1.addRegister( 'r1' ) m2 = thisMap.addModule( 'm2' ) r2 = m2.addRegister( 'r2' ) r2.addField( 'f2', [ 3, 10 ], (3, 10) ) r2[ 'constraints' ][ 'fixedAddress' ] = 0x15 encodedYamlData = thisMap.to_yamlData() log.debug( 'Encoded yaml data: ' + repr( encodedYamlData ) ) decodedMap = RegisterMap.from_yamlData( encodedYamlData ) # Changing the base address for each map must mean that elements end up with the same addresses. thisMap.memory.baseAddress = 0x10 decodedMap.memory.baseAddress = 0x10 # Existing registers and modules must reflect the base address change. self.assertEqual( decodedMap[ 'modules' ][ 'm1' ].baseAddress, m1.baseAddress ) self.assertEqual( decodedMap[ 'modules' ][ 'm1' ][ 'registers' ][ 'r1' ].startAddress, r1.startAddress ) self.assertEqual( decodedMap[ 'modules' ][ 'm2' ].baseAddress, m2.baseAddress ) self.assertEqual( decodedMap[ 'modules' ][ 'm2' ][ 'registers' ][ 'r2' ].startAddress, r2.startAddress ) if __name__ == '__main__' : unittest.main() PK&N`registerMap/utility/__init__.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # PK&N9"66(registerMap/utility/observer/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .address import AddressChangeObserver from .observable import Observable from .size import SizeChangeObserver PK&N2T.'registerMap/utility/observer/address.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .interface import Observer class AddressChangeObserver( Observer ) : """ Narrow the generic Observer to a specific type of event relating to element address. """ def __init__( self, owner ) : self.__owner = owner def update( self, observable, arguments ) : self.__owner.reviewAddressChange() PK&Nmړ)registerMap/utility/observer/interface.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import abc class Observer( metaclass = abc.ABCMeta ) : """ Abstract interface of a class that wants to observe events from other classes. """ @abc.abstractmethod def update( self, observable, arguments ) : pass PK&N̈ *registerMap/utility/observer/observable.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # class Observable( object ) : """ Parent interface of a class that wants other classes to observe its generated events. """ # http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Observer.html def __init__( self ) : self.observers = list() self.changed = False def addObserver( self, thisObserver ) : if thisObserver not in self.observers : self.observers.append( thisObserver ) def notifyObservers( self, arguments = None ) : for thisObserver in self.observers : thisObserver.update( self, arguments ) def removeObserver( self, thisObserver ) : self.observers.remove( thisObserver ) def removeObservers( self ) : self.observers = list() PK&N;*E  $registerMap/utility/observer/size.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # from .interface import Observer class SizeChangeObserver( Observer ) : """ Narrow the generic Observer to a specific type of event relating to element size. """ def __init__( self, owner ) : self.__owner = owner def update( self, observable, arguments ) : self.__owner.reviewSizeChange() PK&N5ֵ.registerMap/utility/observer/tests/__init__.py# # Copyright 2018 Russell Smiley # # This file is part of registerMap. # # registerMap is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # registerMap is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with registerMap. If not, see . # PK&Nh? 4registerMap/utility/observer/tests/testObservable.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import unittest from ..observable import Observable from ..interface import Observer class TestObservable( unittest.TestCase ) : def testConstruct( self ) : thisObservable = Observable() self.assertEqual( thisObservable.observers, [ ] ) class TestAddRemoveObservers( unittest.TestCase ) : class MockObserver( Observer ) : def update( self, observable, arguments ) : pass def setUp( self ) : self.testObservable = Observable() def testAddObserver( self ) : expectedObserver = TestAddRemoveObservers.MockObserver() self.testObservable.addObserver( expectedObserver ) self.assertEqual( len( self.testObservable.observers ), 1 ) self.assertEqual( self.testObservable.observers[ 0 ], expectedObserver ) def testRemoveObserver( self ) : expectedObserver = TestAddRemoveObservers.MockObserver() self.testObservable.addObserver( expectedObserver ) self.assertEqual( len( self.testObservable.observers ), 1 ) self.assertEqual( self.testObservable.observers[ 0 ], expectedObserver ) self.testObservable.removeObserver( expectedObserver ) self.assertEqual( len( self.testObservable.observers ), 0 ) def testRemoveObservers( self ) : expectedNumberObservers = 4 for i in range( 0, expectedNumberObservers ) : self.testObservable.addObserver( TestAddRemoveObservers.MockObserver() ) self.assertEqual( len( self.testObservable.observers ), expectedNumberObservers ) self.testObservable.removeObservers() self.assertEqual( len( self.testObservable.observers ), 0 ) class TestNotifyObservers( unittest.TestCase ) : class MockObserver( Observer ) : def __init__( self ) : self.updateCount = 0 def update( self, source, arguments ) : self.updateCount += 1 @property def updated( self ) : returnValue = False if self.updateCount != 0 : returnValue = True return returnValue def setUp( self ) : self.testObservable = Observable() def testSingleNotification( self ) : expectedObserver = TestNotifyObservers.MockObserver() self.testObservable.addObserver( expectedObserver ) self.assertEqual( len( self.testObservable.observers ), 1 ) self.assertEqual( self.testObservable.observers[ 0 ], expectedObserver ) self.testObservable.notifyObservers() self.assertTrue( expectedObserver.updated ) if __name__ == '__main__' : unittest.main() PK&N`%registerMap/utility/tests/__init__.py# # Copyright 2016 Russell Smiley # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # PK!Ha79,registerMap-0.5.0.dist-info/entry_points.txtN+I/N.,()J(/*M,-JM,.I-M,ЃYUrqPK&N:~~#registerMap-0.5.0.dist-info/LICENSE GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS PK!H>*RQ!registerMap-0.5.0.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,rzd&Y)r$[)T&UrPK!HB{ $registerMap-0.5.0.dist-info/METADATAVmo6_q觼L#;A!vK6/hcMKg$j$TKKys:Cn*-dAsc S 3^푿U\em1yHRAQr. Cޡb)abJHPp0I0aoe^Sb0Qd|2zd콈D2ȚU"gFBXSV 츢U*1*v} ˚}*P{v4Ա!Ž }KW|6uƵsD.N,\~r N@EI]V꬗c 3n:|n)!A"57W˺yZH1TEx\䙬LY/cI :_﬒)cz?V(1`EH>&2rҜX1гa0I:ȹ]:(_/S*E$D˅  ]:~{_pﰩKL}xw)Jkj\I!xlfؑ-xM# `4~+GqU+KO$JG?Z=l3 +U[&eWxiI*cl@ j#;&qvN@rL /YФMةГk34mWF)YV2Ahd5M*J~7 GNCܜMtf Wec.U UAgLPTZiTuiMv5l*+ӯh6OD$ƗR$@2n3u $PD9Fn6,[nxmy. N{2Pi}::vE7#f_Qg\/m*2waO fYvYم[Qe]Gbliv{V]]~=ca:g=g=yԺ":ƛ2bh%أOp(|p׫7IpGG)|.ÃpZMR٤×ɓI5nR"uR<| %tEK(sQp襫pYvR/,޼|)- wrɦ&u!,<1oֹf#V†ph4`Gk )#ɂ}YEhEVrȥqG)WsUQ;I5o_5e+@#JI\͊L'`<귮MhUb ilcK7ߨ  ȼ]Č7|߁&{@Ba4[|YX1^m1QEY9V\mۉD<"SN)T%/H<ҡX Z J軼sk)Cg[+,q8M Ct^d`m倿Ɏ0??>g@!Í&0L& Z zܰQU"Kbe-G,9A~\5Lm-6r[~e7&6=HKa;aFtკc-{qFݖX~ŷd O|+w7@;uؒ'YU HO߻@{+ں{eEd^3te3UNIJUgDK\RYA2=3onJ/y87ݧ%S )HҚ 0^r/LaOhfHt-,t@d]qa2J0j 9n|4gZT'W.cf-˶pF;|`x>2j$f@x#6&U+d6kΣ YA)ӭAkPnqg{ZNC=uܘZ02{tgϧN:FJr'iJ?9s@F!m2TPܡu֚p=}2i1w* ^GU[O= [:kfu Vb(m wN|%1{zT8c-넩 rUEX-_D@90o u.$ޞG|M<G2g *6Yo*&.J^ƃ:::1 n gJ`(]x1}ֶ0+["4gÇ./xa΂NQsY Ak?q(KȗA'VҺ){M~<uPRM%^($?N {I,Ky;vWkIN#̶.T|m>jloc]ܞM=iy'VtUd%S ?D'y_?'h6EK 24<ɴ [y2+:}z[!=^ 1 +")kwv`;veVHʳ-־dO$j\HoL 7A[B|3(BԔl5HYBNfyʸj7]1BDpÒYO]^+]U/tg<:Isw BtA]i{&R"fm "f;BŸ>Uē477^#uF}p1kwdx*qބԿ?;5G(USS3'yPGAQI;NVeIQ]Kk ?=uLd}A$?t WPbcxjͿsR^U`U2֮7XHשӝ >;Wߴ-_Smڎ u 'ࢦ$k]W ` WG {ʧ+6i6o?8gcDj5Ľ媍0`H r5iD }ހ "kyؑ@T 5cy.X%Gnng=T~sI)H2P_l}Б<7aa+}J'/2O2HfnKWtTb 4TЛ {ܮO2Vr!R^a^#ޛ89v(4"p|Jqo _/V%j:cIS;\4HÇ@9;*5/ZWïp-ҏۼ1~Mrw,-G?>}uܸF\KY8V׊/ľZ86u+3rJ }oҾJ>5/ B0h ˒N)Y5"i6k/L-}8틟O ub30t̘#ʹߜ 4?  y7\ cNNf,e+On480G,ە+R] L)مcu/ZC0nMAaGr'h#չ5LAv_Qۦe!~_p$!HH-G:]_ ΨpPh۾o?he,A#_杲 n RAyuKyI'x"$ʏlsvT=d1|4 Sfޖ \m@Τ룑\~ B&.SDZoE~?5Hcm\O.P1Sx]nT~,3Ojۇ@#^ +)t `P{~bkJ ݎ}m NPm{瘡<73߹Mmf9.k::0fujMPf䢷%nGe.0;WBg1Qmݪ*Q LAu<R }hɺ 8eC0*D57p?;뮇 mCE]!Q~vqrToO·)}N9 ϣ2*f}EfNBnbfo g_?@M Dz4m6kn6֥x^TX(8OW䯤M-1Y2{8bl{Mͤl~HVɰKߢH1K@AZꊞxX-/Cxެcf\G$IjE)FvyIeso?\x ˠ:p~ZQnbD%IlCwe/=N}GK"[! kQ&5擌L'iɭY`5~Gdz5 ^D}0ң1RrD|ZR0sFI)B JEsf])~NYa_x rZ{k(CV;L/z1V/Y`oLҮƂCnAXHN M|6D^ox1b#6InaqazVM+(pȓ뾽7ǟ5_4yⰻd32h;B.S!D.h呟-@Cv|dMHr4K6B~-:ƝGNZS+؉brUN,*_7(G6'X:qasRqQd2n#:W{! M4':i?֫%aMzB(}58;Q&6Yז~?pt-K]~HJ^]{bCLa7[ﮎa[6AhY1S dp˗^u |BeSe*ZKQ汮fػ鐦dK<%/Q.xfqj}Ui)ϣG ZsAEd?+qr'kajb[g`7EʓQޡO2^sK8{ Z\X[_Og?AkPk`mRSӥ ;9 .Ga wh'Fv+67jz?S; (3k6]O2m#O}><|_ovHJvR>VP@'n1KKjYE!+`wR 8܍36N^#X"Wi b6n H-%((-h^$b h.A"I549X ".GEz[>pcq<r _C^}9,x:QOMPZ6[O:Q0-_gSm|GOZ}IIzVSUPvOe*OEOMo$}oBG_ RզYʖSGZ%`ed_;nL-6|_T[vl֪.Œ+u_Ss;{nºPවpxxvX1~U7ʵ:rn Lqg\/Շ.ދ6f=M: 'ZpViːY/dpY' /+50:xH\9Wƕ1ckPD]B8%'P` Ŧwhr%4 VMz\ $pPoyˋWMн)؝Dh_$d(x#BA˨ Ѿ*?:F]&t&i 8%q9 $ A4r MơLc(볏fNǚ]( |Oxj&W3U/|8ak\2c v]Ḧ́%ќ.!C/qsx )u>x v&֬t&*+_bKf()P@i&n.-Ϙ^JSo7єpuc Ib[) },r`*仞 AɎAȦ\+ѲC|ozA/Nrk1 uKR[z董qR7Lњ?/k5lsܓqOE>!#[frvHk"(= B,_fC-JV;ҙgWc k[_OFxR؞ _ Jҹ>|벽`%qXl r/_{}] %ڋd=YndҕFg $//@Iٴ^R>Q8i> ]jqGߝҫn0A;v1 8T'ZowR5v4Ƣ7s1aH;ovct=ͺ`U$n *ne Dn]ceJ:gמz$5M0|GY2oP'b}J= /<֚L/ p&//F).B箃8͖/9@ &f[`ܰkE*`ЂgQwlWf)X*S "rQ*RϯV3%zmoo iE nlřz1[uqty?G3KC1^D.n\%n$ Sixv5s8q^<E=*MVo rw5TlGst ]#_qҔk+(>BÌUcriK&9uUK@_QI__ L-V[ĝmFbɡúY=_AHrߊ~؀Unk&Y\ +^̶L]8 jIUVr}|NnQ WAMzH,F Q*o75giV0H~pOpOjaLZI:f,25]GNqׂ&^8,N[LQ! \%7Z~1NXݮZSdy>j:2!}ǯ@1Rt]KKMLbЁF1IN~Qܣ瑤@BJ{cT*ԧD*A۝$E~fk9ǩ6EvxԄ:嶂<B EChzb `?Xs]ST.N#aݒ w戲,ѩh7Ѱп~|0vKICZ5v qґ2*en]+|1pS!D,>]ffћ;0B0aM ԕؿ qRpmكZ.q8t$ { ϰ?bmԸJjЃQtDT&$Vh[O]|܉'oO"+R90z7\3 JV=}x\.^ m ơ!Q5T ]nRs5nV uOuI^u(uQL {y:y*,Ĵ?uϧ k3xd}vWj2o-(p;; dmΕ8~-ӵuzu\he Ud΀r:*?_a׃7|:No3|FMCq.ũRi{!w2.lIJ|*ݜكYfA{"o{xu2PFL9MN _^^o."h@XouH+ON=H)Kg5f aS¿> =if/K[Rⴺ "t'}+}.[QkJ&4g&Y uSb,R~ÿ?_FZ *նs?_e9 0揇(q"XaKm%+ߘSt%uFkNIfm@d>"YvwegbXn>$&ipw@dha̛&u:39*KT"/:0XH;E[9U~M۪j f)kĆ !^*{Ȝ2Y*& ! fbBw KR_>ӕ G) ?6.&3Ya|~gj&zm1$VEpݽ SGІ |q{ybJ#mo{_:<@R7rXk>kw갱Y e/wVgM3u Ni,RrQn2BRN=ᾣ ]I'MV'o#Vg^jJC.~LjAi OM?4 t!3ݴ9¼Öe@Փ@+zQ#RG 0Bi;עh]FtΪWU0HO7ˊ~O?PK&NregisterMap/VERSIONPK&N}ʑ7registerMap/__init__.pyPK&Nn,,registerMap/exceptions.pyPK&Nh5`registerMap/exporter.pyPK&N^_JregisterMap/registerMap.pyPK&NS.registerMap/base/__init__.pyPK&NF~KO1registerMap/base/parameters.pyPK&N"AregisterMap/base/tests/__init__.pyPK&N+q q /DregisterMap/base/tests/testElementsParameter.pyPK&N7͘ .MPregisterMap/base/tests/testModulesParameter.pyPK&Nrr#\registerMap/constraints/__init__.pyPK&Neo`k*X`registerMap/constraints/constraintTable.pyPK&N2'eD)D)&s}registerMap/constraints/constraints.pyPK&N)registerMap/constraints/tests/__init__.pyPK&NH8registerMap/constraints/tests/testAlignmentConstraint.pyPK&N@O884 registerMap/constraints/tests/testConstraintTable.pyPK&N ;registerMap/constraints/tests/testFixedAddressConstraint.pyPK&N'2A87registerMap/constraints/tests/testFixedSizeConstraint.pyPK&N#)registerMap/export/__init__.pyPK&Nμ H,registerMap/export/arguments.pyPK&NAOO,9registerMap/export/exporters.pyPK&N<registerMap/export/options.pyPK&N`#@registerMap/export/base/__init__.pyPK&NIx DregisterMap/export/base/field.pyPK&N??$JregisterMap/export/base/interface.pyPK&NB0tt!~QregisterMap/export/base/memory.pyPK&N c!1XregisterMap/export/base/module.pyPK&Nw/!`registerMap/export/base/output.pyPK&N--#gregisterMap/export/base/register.pyPK&N&T{registerMap/export/base/registerMap.pyPK&N] ] #$registerMap/export/base/template.pyPK&N5ֵ)registerMap/export/base/tests/__init__.pyPK&Nא&ːregisterMap/export/base/tests/mocks.pyPK&NK4 registerMap/export/base/tests/testExportFieldBase.pyPK&NI5registerMap/export/base/tests/testExportMemoryBase.pyPK&N%<<] ] 5<registerMap/export/base/tests/testExportModuleBase.pyPK&NB  5registerMap/export/base/tests/testExportOutputBase.pyPK&Nq}tt7CregisterMap/export/base/tests/testExportRegisterBase.pyPK&N9C registerMap/export/base/tests/testExportRegisterContiguousFields.pyPK&N̘s:kregisterMap/export/base/tests/testExportRegisterMapBase.pyPK&Nf hh7fregisterMap/export/base/tests/testExportTemplateBase.pyPK&Ni   #registerMap/export/c/__init__.pyPK&NQ!kregisterMap/export/c/arguments.pyPK&N$mmregisterMap/export/c/options.pyPK&Nt;RNN#2registerMap/export/c/registerMap.pyPK&NaVV)registerMap/export/c/elements/__init__.pyPK&N1m&^registerMap/export/c/elements/field.pyPK&N(EE'registerMap/export/c/elements/memory.pyPK&NL cc';"registerMap/export/c/elements/module.pyPK&Nl;)'registerMap/export/c/elements/register.pyPK&Nrps,>+registerMap/export/c/elements/registerMap.pyPK&N5ֵ/0registerMap/export/c/elements/tests/__init__.pyPK&NՃR1*3registerMap/export/c/elements/tests/testCField.pyPK&Ngg2;registerMap/export/c/elements/tests/testCMemory.pyPK&NjK[['AregisterMap/export/c/output/__init__.pyPK&NdH#OEregisterMap/export/c/output/base.pyPK&Ns$HregisterMap/export/c/output/macro.pyPK&N-%NregisterMap/export/c/output/memory.pyPK&N6V%TregisterMap/export/c/output/module.pyPK&Nd2kk*ZregisterMap/export/c/output/registerMap.pyPK&N:#AaregisterMap/export/c/output/templates/idiomatic/memory_template.hPK&NGAdregisterMap/export/c/output/templates/idiomatic/module_template.hPK&Nc0LLFkregisterMap/export/c/output/templates/idiomatic/registerMap_template.cPK&No]llForegisterMap/export/c/output/templates/idiomatic/registerMap_template.hPK&NpS|CC=tregisterMap/export/c/output/templates/macro/assert_template.hPK&N@=4wregisterMap/export/c/output/templates/macro/extern_template.hPK&N5ֵ-yregisterMap/export/c/output/tests/__init__.pyPK&Ni7|registerMap/export/c/output/tests/testCMacroTemplate.pyPK&NOA8zregisterMap/export/c/output/tests/testCMemoryTemplate.pyPK&N{q,,8registerMap/export/c/output/tests/testCModuleTemplate.pyPK&Nn=registerMap/export/c/output/tests/testCRegisterMapTemplate.pyPK&N5ֵ&>registerMap/export/c/tests/__init__.pyPK&NdW>ж 1DregisterMap/export/c/tests/testCArgumentParser.pyPK&NsYi i 4IregisterMap/export/c/tests/testCRegisterMapOutput.pyPK&N5ֵ)registerMap/export/commonCppC/__init__.pyPK&NEjj0 registerMap/export/commonCppC/output/__init__.pyPK&N߿__-registerMap/export/commonCppC/output/macro.pyPK&No5\ .oregisterMap/export/commonCppC/output/memory.pyPK&N6 ^ .s+registerMap/export/commonCppC/output/module.pyPK&Ns滦 3y7registerMap/export/commonCppC/output/registerMap.pyPK&N5ֵ6CregisterMap/export/commonCppC/output/tests/__init__.pyPK&N(a`""4FregisterMap/export/commonCppC/output/tests/common.pyPK&N3"  "OregisterMap/export/cpp/__init__.pyPK&NnK#jRregisterMap/export/cpp/arguments.pyPK&Nt=oo![registerMap/export/cpp/options.pyPK&N‚RR%?_registerMap/export/cpp/registerMap.pyPK&NaVV+mregisterMap/export/cpp/elements/__init__.pyPK&N5##(sqregisterMap/export/cpp/elements/field.pyPK&N=Iqq)vregisterMap/export/cpp/elements/memory.pyPK&Nigg)|registerMap/export/cpp/elements/module.pyPK&N{+BregisterMap/export/cpp/elements/register.pyPK&Nc.registerMap/export/cpp/elements/registerMap.pyPK&N5ֵ1registerMap/export/cpp/elements/tests/__init__.pyPK&Nk5registerMap/export/cpp/elements/tests/testCppField.pyPK&Nvv6registerMap/export/cpp/elements/tests/testCppMemory.pyPK&NjK[[)[registerMap/export/cpp/output/__init__.pyPK&N[u*%registerMap/export/cpp/output/base.pyPK&N3$tt&:registerMap/export/cpp/output/macro.pyPK&N""'registerMap/export/cpp/output/memory.pyPK&N$/'YregisterMap/export/cpp/output/module.pyPK&NQ;ww,registerMap/export/cpp/output/registerMap.pyPK&NtEMregisterMap/export/cpp/output/templates/idiomatic/memory_template.cppPK&N E{registerMap/export/cpp/output/templates/idiomatic/memory_template.hppPK&NEregisterMap/export/cpp/output/templates/idiomatic/module_template.hppPK&N>!!JregisterMap/export/cpp/output/templates/idiomatic/registerMap_template.cppPK&N{M+JPregisterMap/export/cpp/output/templates/idiomatic/registerMap_template.hppPK&N4bFFAregisterMap/export/cpp/output/templates/macro/assert_template.hppPK&N5ֵ/LregisterMap/export/cpp/output/tests/__init__.pyPK&N\_ OKK;[registerMap/export/cpp/output/tests/testCppMacroTemplate.pyPK&N(5O<registerMap/export/cpp/output/tests/testCppMemoryTemplate.pyPK&N,,< registerMap/export/cpp/output/tests/testCppModuleTemplate.pyPK&NN7R00A5registerMap/export/cpp/output/tests/testCppRegisterMapTemplate.pyPK&N5ֵ(NregisterMap/export/cpp/tests/__init__.pyPK&Nc5 5QregisterMap/export/cpp/tests/testCppArgumentParser.pyPK&N; 8-\registerMap/export/cpp/tests/testCppRegisterMapOutput.pyPK&N!djregisterMap/export/io/__init__.pyPK&Nu&emregisterMap/export/io/yaml/__init__.pyPK&Nqi&mpregisterMap/export/io/yaml/abstract.pyPK&NN=$uregisterMap/export/io/yaml/stream.pyPK&N1yregisterMap/export/io/yaml/parameters/__init__.pyPK&N</|registerMap/export/io/yaml/parameters/encode.pyPK&N.registerMap/export/io/yaml/parameters/parse.pyPK&N7registerMap/export/io/yaml/parameters/tests/__init__.pyPK&N dd9registerMap/export/io/yaml/parameters/tests/testEncode.pyPK&N"  8ԛregisterMap/export/io/yaml/parameters/tests/testParse.pyPK&N77registerMap/export/io/yaml/parameters/tests/data/.emptyPK&N۟,registerMap/export/io/yaml/tests/__init__.pyPK&NӠ,uregisterMap/export/io/yaml/tests/data/.emptyPK&N5ֵ$_registerMap/export/tests/__init__.pyPK&NF  )cregisterMap/export/tests/testArguments.pyPK&N!registerMap/structure/__init__.pyPK&N(registerMap/structure/bitmap/__init__.pyPK&Nd/8*1*1&registerMap/structure/bitmap/bitmap.pyPK&N.UregisterMap/structure/bitmap/tests/__init__.pyPK&NZ+cregisterMap/structure/bitmap/tests/mocks.pyPK&N 0registerMap/structure/bitmap/tests/testBitMap.pyPK&NcyB registerMap/structure/bitmap/tests/testBitMapMapDestinationBits.pyPK&N4[=$registerMap/structure/bitmap/tests/testBitMapMapSourceBits.pyPK&NP508registerMap/structure/bitmap/tests/testBitMapQuery.pyPK&Nܺ''67GregisterMap/structure/bitmap/tests/testBitMapRanges.pyPK&NUܫu u :VregisterMap/structure/bitmap/tests/testBitMapYamlEncode.pyPK&NXX3cregisterMap/structure/bitmap/tests/testRemoveMap.pyPK&N ¤ *(}registerMap/structure/bitrange/__init__.pyPK&N0 registerMap/structure/bitrange/tests/__init__.pyPK&NȊ ff4registerMap/structure/bitrange/tests/testBitRange.pyPK&NED  :ѡregisterMap/structure/bitrange/tests/testBitRangeYamlIo.pyPK&N*5registerMap/structure/elements/__init__.pyPK&N!GV/registerMap/structure/elements/base/__init__.pyPK&NvE/eregisterMap/structure/elements/base/bitStore.pyPK&N).registerMap/structure/elements/base/element.pyPK&N}/registerMap/structure/elements/base/identity.pyPK&N1#registerMap/structure/elements/base/observable.pyPK&N7- 0OregisterMap/structure/elements/base/parameter.pyPK&N5registerMap/structure/elements/base/tests/__init__.pyPK&N>(3registerMap/structure/elements/base/tests/testId.pyPK&N:registerMap/structure/elements/base/tests/testParameter.pyPK&N̫m0PregisterMap/structure/elements/field/__init__.pyPK&NS`//-zregisterMap/structure/elements/field/field.pyPK&Nɀp##2registerMap/structure/elements/field/parameters.pyPK&N6*registerMap/structure/elements/field/tests/__init__.pyPK&Nz =-registerMap/structure/elements/field/tests/testCanonicalId.pyPK&NqZMEFF77registerMap/structure/elements/field/tests/testField.pyPK&NccLTregisterMap/structure/elements/field/tests/testFieldLocalGlobalConversion.pyPK&N-@ @ ;ncregisterMap/structure/elements/field/tests/testFieldSize.pyPK&N5SKnregisterMap/structure/elements/field/tests/testFieldUserDefinedParameter.pyPK&N2""8@tregisterMap/structure/elements/field/tests/testYamlIo.pyPK&NABregisterMap/structure/elements/field/tests/parameters/__init__.pyPK&NvOregisterMap/structure/elements/module/tests/testCanonicalId.pyPK&ND B B9vUregisterMap/structure/elements/module/tests/testModule.pyPK&NQAחregisterMap/structure/elements/module/tests/testModuleInstance.pyPK&NЦJ registerMap/structure/elements/module/tests/testModuleMultipleInstances.pyPK&NgWC&registerMap/structure/elements/module/tests/testModuleParameters.pyPK&NjjJ registerMap/structure/elements/module/tests/testModuleRegisterAddresses.pyPK&NiMregisterMap/structure/elements/module/tests/testModuleUserDefinedParameter.pyPK&Ncϓ}"}"9'registerMap/structure/elements/module/tests/testYamlIo.pyPK&N  3registerMap/structure/elements/register/__init__.pyPK&N3wJ3U!registerMap/structure/elements/register/instance.pyPK&NyO4UAregisterMap/structure/elements/register/interface.pyPK&No5jGregisterMap/structure/elements/register/parameters.pyPK&NwiXiX3YregisterMap/structure/elements/register/register.pyPK&N9tregisterMap/structure/elements/register/tests/__init__.pyPK&NEv v 6registerMap/structure/elements/register/tests/mocks.pyPK&NƎF F =WregisterMap/structure/elements/register/tests/testRegister.pyPK&NΞHregisterMap/structure/elements/register/tests/testRegisterCanonicalId.pyPK&NsEregisterMap/structure/elements/register/tests/testRegisterInstance.pyPK&NڐS55L registerMap/structure/elements/register/tests/testRegisterInstanceAddress.pyPK&N<,Pm registerMap/structure/elements/register/tests/testRegisterInstanceYamlAddress.pyPK&N9D7K registerMap/structure/elements/register/tests/testRegisterParameterTypes.pyPK&Noލ E5 registerMap/structure/elements/register/tests/commonTests/__init__.pyPK&N|KKHA registerMap/structure/elements/register/tests/commonTests/description.pyPK&N  JI registerMap/structure/elements/register/tests/commonTests/fieldInterval.pyPK&N&(>%%C"S registerMap/structure/elements/register/tests/commonTests/fields.pyPK&N\HCk registerMap/structure/elements/register/tests/commonTests/memory.pyPK&NAq registerMap/structure/elements/register/tests/commonTests/mode.pyPK&NzA{ registerMap/structure/elements/register/tests/commonTests/name.pyPK&NZC. registerMap/structure/elements/register/tests/commonTests/public.pyPK&NP**Ee registerMap/structure/elements/register/tests/commonTests/sizeBits.pyPK&N&  D registerMap/structure/elements/register/tests/commonTests/summary.pyPK&NpR` registerMap/structure/elements/register/tests/commonTests/userDefinedParameters.pyPK&N R-55C registerMap/structure/elements/register/tests/commonTests/yamlIo.pyPK&N`0 registerMap/structure/elements/tests/__init__.pyPK&Novaa4 registerMap/structure/elements/tests/mockObserver.pyPK&Ngc^^5Z registerMap/structure/elements/tests/testParameter.pyPK&NX ⊢*  registerMap/structure/interval/__init__.pyPK&NnW, registerMap/structure/interval/contiguous.pyPK&N))  registerMap/structure/interval/element.pyPK&N8uZ)Y* registerMap/structure/interval/overlap.pyPK&N%{&{3 registerMap/structure/interval/sort.pyPK&N08 registerMap/structure/interval/tests/__init__.pyPK&Nڌ##4; registerMap/structure/interval/tests/testInterval.pyPK&N*! >Z registerMap/structure/interval/tests/testIntervalContiguous.pyPK&NL; f registerMap/structure/interval/tests/testIntervalOverlap.pyPK&N@4 8fv registerMap/structure/interval/tests/testIntervalSort.pyPK&NFogg(B registerMap/structure/memory/__init__.pyPK&N5' registerMap/structure/memory/address.pyPK&N⊃$$-5 registerMap/structure/memory/configuration.pyPK&Nˁ--' registerMap/structure/memory/element.pyPK&N  ) registerMap/structure/memory/interface.pyPK&N. registerMap/structure/memory/tests/__init__.pyPK&N"\,<( registerMap/structure/memory/tests/testAddressQueryResult.pyPK&N <-<-Bk registerMap/structure/memory/tests/testAddressableMemoryElement.pyPK&Nٮ ; registerMap/structure/memory/tests/testBitsMemoryElement.pyPK&N$w@w@= registerMap/structure/memory/tests/testMemoryConfiguration.pyPK&NZoo7` registerMap/structure/memory/tests/testMemoryElement.pyPK&NaT%i registerMap/structure/set/__init__.pyPK&Nգ>(|H registerMap/tests/testRegisterMapSpan.pyPK&NGG[ registerMap/tests/testYamlIo.pyPK&N`n registerMap/utility/__init__.pyPK&N9"66(`q registerMap/utility/observer/__init__.pyPK&N2T.'t registerMap/utility/observer/address.pyPK&Nmړ)7y registerMap/utility/observer/interface.pyPK&N̈ *} registerMap/utility/observer/observable.pyPK&N;*E  $ registerMap/utility/observer/size.pyPK&N5ֵ.i registerMap/utility/observer/tests/__init__.pyPK&Nh? 4w registerMap/utility/observer/tests/testObservable.pyPK&N`% registerMap/utility/tests/__init__.pyPK!Ha79, registerMap-0.5.0.dist-info/entry_points.txtPK&N:~~# registerMap-0.5.0.dist-info/LICENSEPK!H>*RQ!- registerMap-0.5.0.dist-info/WHEELPK!HB{ $ registerMap-0.5.0.dist-info/METADATAPK!H뗖*=o"{ registerMap-0.5.0.dist-info/RECORDPK  ,dJ