Added support for JSON pinmux reading from LibreSOC.

* New: In cumulus/plugins.blocks.iospecs.IoSpecs, new class to manage
    I/O pads placement. Support for reading the JSON pinmux format
    (courtesy of LKCL & StackOverflow).
This commit is contained in:
Jean-Paul Chaput 2020-11-27 18:46:58 +01:00
parent 13726d648b
commit 85d943a3e4
2 changed files with 164 additions and 1 deletions

View File

@ -533,7 +533,7 @@ class IoPadConf ( object ):
def __init__ ( self, datas ):
if not isinstance(datas,tuple):
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is not a list.'
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is not a tuple.'
, str(datas) ] )
if len(datas) < 5 and len(datas) > 8:
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" list must have between 5 to 7 elements.'
@ -886,6 +886,20 @@ class IoPin ( object ):
A_END = 0x0020
A_MASK = A_BEGIN|A_END
@staticmethod
def toStr ( value ):
s = ''
for constant, name in ( (IoPin.SOUTH , 'SOUTH' )
, (IoPin.NORTH , 'NORTH' )
, (IoPin.EAST , 'EAST' )
, (IoPin.WEST , 'WEST' )
, (IoPin.A_BEGIN, 'A_BEGIN')
, (IoPin.A_END , 'A_END' ) ):
if value & constant:
if len(s): s += '|'
s += 'IoPin.'+name
return s
def __init__ ( self, flags, stem, upos, ustep=0, count=1 ):
"""
Create an I/O Pin(s) on the abutment box of a block. Could be for one

View File

@ -0,0 +1,149 @@
#
# This file is part of the Coriolis Software.
# Copyright (c) SU 2020-2020, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/block/iospecs.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
import sys
import re
import os.path
import json
from operator import itemgetter
import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation
import CRL
from helpers import trace, l, u, n
from helpers.utils import classdecorator
from helpers.io import ErrorMessage, WarningMessage, catch
from helpers.overlay import CfgCache
from plugins.alpha.block.configuration import IoPin
__all__ = [ 'IoSpecs' ]
# ----------------------------------------------------------------------------
# Function : "iospecs.utf8toStr".
def utf8toStr ( data, ignoreDicts=False ):
"""
Translate UTF-8 strings into basic str ones in dict & list datas.
Based on _byteify() by Mirec Miskuf on Stackoverflow.
reference: https://stackoverflow.com/questions/956867/
how-to-get-string-objects-instead-of-unicode-from-json/
33571117#33571117
"""
if isinstance(data,unicode):
return data.encode('utf-8')
if isinstance(data,list):
return [ utf8toStr( item, ignoreDicts=True ) for item in data ]
if isinstance(data,dict) and not ignoreDicts:
return dict( ( utf8toStr(key , ignoreDicts=True )
, utf8toStr(value, ignoreDicts=True ))
for key, value in data.iteritems() )
return data
# ----------------------------------------------------------------------------
# Class : "iospecs.IoPadSpec".
class IoPadSpec ( object ):
id = 0
def __init__ ( self, instance, side, position=None, nets=[] ):
self.instance = instance
self.side = side
self.position = position
self.nets = list(nets)
self._id = IoPadSpec.id
IoPadSpec.id += 1
def addNets ( self, nets ):
self.nets += nets
def asList ( self ):
return tuple( [ self.side, self.position, self.instance ] + self.nets )
def __str__ ( self ):
s = '({:<11}'.format( IoPin.toStr(self.side) )
s += ', {}'.format( self.position )
s += ', "{}"'.format( self.instance )
for net in self.nets:
s += ', "{}"'.format(net)
s += ')'
return s
# ----------------------------------------------------------------------------
# Class : "iospecs.IoSpecs".
class IoSpecs ( object ):
"""
Load and generate IoPadsSpec from a variety of sources.
"""
def __init__ ( self ):
self._ioPadsLUT = {}
self._ioPadsSpec = []
def addIoPadSpec ( self, instance, side ):
if self._ioPadsLUT.has_key(instance):
print( ErrorMessage( 2, 'IoSpecs.addIoPadSpec(): Duplicate pad specification for "{}" (ignored).' \
.format(instance) ) )
return self._ioPadsLUT[ instance ]
spec = IoPadSpec( instance, side )
self._ioPadsLUT[ instance ] = spec
self._ioPadsSpec.append( spec )
return spec
def loadFromPinmux ( self, fileName ):
"""
Load ioPadsSpec from a LibreSOC generated pinmux file in JSON format.
"""
if not os.path.isfile(fileName):
raise ErrorMessage( 2, [ 'IoSpecs.loadFromPinmux(): JSON pinmux file not found.'
, '("{}")'.format(fileName) ] )
with open(fileName) as fd:
datas = utf8toStr( json.loads( fd.read(), object_hook=utf8toStr )
, ignoreDicts=True )
for padName in datas['pads.east' ]: self.addIoPadSpec( padName, IoPin.EAST )
for padName in datas['pads.west' ]: self.addIoPadSpec( padName, IoPin.WEST )
for padName in datas['pads.north']: self.addIoPadSpec( padName, IoPin.NORTH )
for padName in datas['pads.south']: self.addIoPadSpec( padName, IoPin.SOUTH )
for padDatas in datas['pads.instances']:
padName = padDatas[0]
if not self._ioPadsLUT.has_key(padName):
print( WarningMessage('IoSpecs.loadFromPinmux(): Pad "{}" is not on any side, ignored.' \
.format(padName) ))
continue
end = None
if padDatas[-1] in '+-*': end = -1
self._ioPadsLUT[padName].addNets( padDatas[1:end] )
@property
def ioPadsSpec ( self ):
specs = []
for spec in self._ioPadsSpec:
specs.append( spec.asList() )
return specs
def __str__ ( self ):
if len(self._ioPadsSpec):
s = 'ioPadsSpec = [ '
for spec in self._ioPadsSpec:
if len(s) > 15: s += '\n , '
s += '{}'.format( spec )
s += ')'
s += ' ]'
return s