PK TL#ԗ$ registerMap/VERSION0.3.0
PK TL}ʑ 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 TLn, , 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 TLh5 registerMap/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 TL
z 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 .elements.base.parameter import Parameter
from .elements.module import Module
from .exceptions import \
ConfigurationError, \
ParseError
from .set import SetCollection
from .structure.memory.element import AddressableMemoryElement
from .structure.memory.space import MemorySpace
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 = MemorySpace()
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
endAddress = startAddress
registersCreated = False
for thisModule in self.__data[ 'modules' ].value.values() :
if thisModule.endAddress > endAddress :
endAddress = thisModule.endAddress
if len( thisModule[ 'registers' ] ) > 0 :
registersCreated = True
if (endAddress == startAddress) and (not registersCreated) :
self.__element.sizeMemoryUnits = 0
elif (endAddress == startAddress) and registersCreated :
self.__element.sizeMemoryUnits = 1
else :
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 = MemorySpace.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 TL registerMap/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 TL`C registerMap/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 ..elements.base import ElementList
from ..elements.module import Module
from ..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 TL " 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 TL:joE E / 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.elements.module import Module
from registerMap.set import SetCollection
from registerMap.structure.memory.space import MemorySpace
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 = MemorySpace()
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 TL