[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/Narrat/python3-eispice/master/module/ibis_parser.py [Back]  [Original]

#
# Copyright (C) 2005-2007 Cooper Street Innovations Inc.
# Charles Eidsness    
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#

"""
This module contains the IBIS file parser.

Classes:
IbisPinData -- IBIS Pin Data
IbisModel_Selector -- IBIS Model Selector Data
IbisVICurve -- IBIS VI Curve Data
IbisPin -- IBIS Pin Data
IbisPackage -- IBIS Package Data
IbisWaveform -- IBIS Waveform Data
IbisRamp -- IBIS Ramp Data
IbisModel_Spec -- IBIS Spec Data
IbisModel -- IBIS Model Data
IbisComponent -- IBIS Component Data
Ibis -- Top Level IBIS Data

"""

import re, os, sys
import units
import collections
from numpy import array

from ibis_driver import *
from ibis_device import *

# -------------------------------------------------------------------------- #

Done = 'done'

_reNamed = r"""(?x)(?i)\s*
    (?P%s)\s*
    (?P.*?)
    [|\r\n]"""
_reValue = r"""(?x)(?i)\s*
    (?P%s)[\s=]*(?P\S*?)\s*
    [|\r\n]"""
_reLabeled = r"""(?x)(?i)
    \[(?P%s)\]\s*
    (?P.*?)
    [|\r\n]"""
_reLabel = '(?i)\[(?P%s)\]\s*'
_reRange = r"""(?x)(?i)\s*
    (?P%s)\s*
    (?P\S*)\s*
    (?P\S*)\s*
    (?P\S*)\s*
    [|\r\n]"""
_reLabeledRange = r"""(?x)(?i)
    \[(?P%s)\]\s*
    (?P\S*)\s*
    (?P\S*)\s*
    (?P\S*)\s*
    [|\r\n]"""
_reComment = '\s*[|\r\n\f]'
_reAny = '(?P.*)'

class _Builder:
    """A customized awk-like parser"""

    def __init__(self):
        self.patterns = []
        self.fdin = None
        #  Some useful re's
        self.addRE(_reComment)

    def addRE(self, pattern, handler=None):
        self.patterns.append((re.compile(pattern), handler))

    def _process(self, line):
        for pattern, handler in self.patterns:
            match = pattern.match(line.lower())
            if match:
                if isinstance(handler, collections.Callable):
                    return handler(**match.groupdict())
                else:
                    return handler
        raise RuntimeError(line)

    def process(self):
        for line in iter(self.fdin.readline, ''):
            if self._process(line) is Done:
                pos = int(self.fdin.tell()) - len(line)
                self.fdin.seek(pos,0)
                break

    def handleName(self, key, name):
        key = key.replace(" ","_").lower()
        setattr(self, key, name.strip())

    def handleBlock(self, key, name):
        name = name.strip()
        for line in iter(self.fdin.readline, ''):
            if (line[0] != '['):
                name = name + '\n'
                name = name + line.strip()
            else:
                pos = int(self.fdin.tell()) - len(line)
                self.fdin.seek(pos,0)
                break
        key = key.replace(" ","_").lower()
        setattr(self, key, name)

    def handleValue(self, key, name):
        key = key.replace(" ","_").lower()
        setattr(self, key, units.float(name))

    def handleMulti(self, key, name):
        key = key.replace(" ","_").lower()
        if not hasattr(self, key):
            setattr(self, key, {})
        dic = getattr(self, key)
        dic[name.strip()] = globals()['Ibis' + key.title()](self.fdin)

    def handleSingle(self, key):
        key = key.replace(" ","_").lower()
        setattr(self, key, globals()['Ibis' + key.title()](self.fdin))

    def handleSingleDict(self, key):
        key = key.replace(" ","_").lower()
        setattr(self, key, vars(globals()['Ibis' + key.title()](self.fdin)))

    def handleRange(self, key, typ, min, max):
        key = key.replace(" ","_").lower()
        if not hasattr(self, key):
            setattr(self, key, {})
        dic = getattr(self, key)
        dic['typ'] = units.float(typ)
        dic['min'] = units.float(min)
        dic['max'] = units.float(max)
        if dic['min'] == None:
            dic['min'] = dic['typ']
        if dic['max'] == None:
            dic['max'] = dic['typ']

    def handleVICurve(self, key):
        key = key.replace(" ","_").lower()
        setattr(self, key, vars(IbisVICurve(self.fdin)))

    def handleWaveform(self, key):
        key = key.replace(" ","_").lower()
        if not hasattr(self, key):
            setattr(self, key, [])
        lst = getattr(self, key)
        lst.append(IbisWaveform(self.fdin))

    def handleCommentChar(self, key, name):
        if name != '':
            raise RuntimeError("Don't support comment characters other than |. ")

    def handleUnkown(self, line):
        raise RuntimeError('Unsupported Line\n%s' % line)

# -------------------------------------------------------------------------- #

class IbisPinData(_Builder):
    """IBIS Pin Data"""
    def __init__(self, signal, model, R, L, C):
        self.signal = signal
        self.model = model
        self.R = units.float(R)
        self.L = units.float(L)
        self.C = units.float(C)

class IbisModel_Selector(_Builder):
    """IBIS Model Selector Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.models = []

        self.addRE("\[", Done)
        self.addRE(_reNamed % "\S*", self.handle)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

    def handle(self, key, name):
        self.models.append((key, name))

class IbisVICurve(_Builder):
    """IBIS Model VI Curve Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.typ = []
        self.min = []
        self.max = []

        self.addRE("\[", Done)
        self.addRE(_reRange % "\S*", self.handle)

        self.process()

        self.typ = array(self.typ)
        self.min = array(self.min)
        self.max = array(self.max)

        del self.fdin
        del self.patterns

    def handle(self, key, typ, min, max):
        key = units.float(key)
        if key == None:
            return
        self.typ.append([key, units.float(typ)])
        if units.float(min) == None:
            self.min.append([key, units.float(typ)])
        else:
            self.min.append([key, units.float(min)])
        if units.float(max) == None:
            self.max.append([key, units.float(typ)])
        else:
            self.max.append([key, units.float(max)])


class IbisPin(_Builder):
    """IBIS Model Pin Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.addRE("\[", Done)
        self.addRE(r"""(?x)\s*?
            (?P\S*)\s*    # Pin name
            (?P\S*)\s*    # Signal Name
            (?P\S*)\s*?    # Model Name
            (?:                    # RLC's are optional
                (?P\S*?)\s*?  # Resistance
                (?P\S*?)\s*?  # Inductance
                (?P\S*?)\s*?  # Capacitance
            )?[|\r\n]""", self.handle)

        self.process()

        del self.fdin
        del self.patterns

    def handle(self, key, signal, model, R=None, L=None, C=None):
        setattr(self, key, IbisPinData(signal, model, R, L, C))

class IbisPackage(_Builder):
    """IBIS Model Package Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.addRE(_reRange % "r[ _]pkg", self.handleRange)
        self.addRE(_reRange % "l[ _]pkg", self.handleRange)
        self.addRE(_reRange % "c[ _]pkg", self.handleRange)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

class IbisWaveform(_Builder):
    """IBIS Model Waveform Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.data = {}
        self.data['typ'] = []
        self.data['min'] = []
        self.data['max'] = []

        self.addRE("\[", Done)
        self.addRE(_reValue % "r[ _]fixture", self.handleValue)
        self.addRE(_reValue % "c[ _]fixture", self.handleValue)
        self.addRE(_reValue % "l[ _]fixture", self.handleValue)
        self.addRE(_reValue % "v[ _]fixture_min", self.handleValue)
        self.addRE(_reValue % "v[ _]fixture_max", self.handleValue)
        self.addRE(_reValue % "v[ _]fixture", self.handleValue)
        self.addRE("\s*" + _reRange % "\S*", self.handle)
        self.addRE(_reAny, Done)

        self.process()

        self.data['typ'] = array(self.data['typ'])
        self.data['min'] = array(self.data['min'])
        self.data['max'] = array(self.data['max'])

        del self.fdin
        del self.patterns

    def handle(self, key, typ, min, max):
        self.data['typ'].append([units.float(key), units.float(typ)])
        if units.float(min) == None:
            self.data['min'].append([units.float(key), units.float(typ)])
        else:
            self.data['min'].append([units.float(key), units.float(min)])
        if units.float(max) == None:
            self.data['max'].append([units.float(key), units.float(typ)])
        else:
            self.data['max'].append([units.float(key), units.float(max)])


class IbisRamp(_Builder):
    """IBIS Model Ramp Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        # Default Load
        self.r_load = 50

        _reDvDtRange = r"""(?x)(?i)\s*
            (?P%s)\s*
            (?P\S*)\/(?P\S*)\s*
            (?P\S*)\/(?P\S*)\s*
            (?P\S*)\/(?P\S*)\s*
            [|\r\n]"""

        _reDvDtNARange = r"""(?x)(?i)\s*
            (?P%s)\s*
            (?P\S*)\/(?P\S*)\s*
            na\s*na\s*
            [|\r\n]"""

        self.addRE(_reDvDtRange % "dv/dt_r", self.handle)
        self.addRE(_reDvDtRange % "dv/dt_f", self.handle)
        self.addRE(_reDvDtNARange % "dv/dt_r", self.handleNA)
        self.addRE(_reDvDtNARange % "dv/dt_f", self.handleNA)
        self.addRE(_reValue % "r_load", self.handleValue)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

    def handle(self, key, typ_dv, typ_dt, min_dv, min_dt, max_dv, max_dt):

        key_dv = 'dv_' + key.lower()[-1]
        key_dt = 'dt_' + key.lower()[-1]
        if not hasattr(self, key_dv):
            setattr(self, key_dv, {})
        if not hasattr(self, key_dt):
            setattr(self, key_dt, {})
        dic_dv = getattr(self, key_dv)
        dic_dt = getattr(self, key_dt)
        dic_dv['typ'] = units.float(typ_dv)
        dic_dv['min'] = units.float(min_dv)
        dic_dv['max'] = units.float(max_dv)
        dic_dt['typ'] = units.float(typ_dt)
        dic_dt['min'] = units.float(min_dt)
        dic_dt['max'] = units.float(max_dt)

    def handleNA(self, key, typ_dv, typ_dt):

        key_dv = 'dv_' + key.lower()[-1]
        key_dt = 'dt_' + key.lower()[-1]
        if not hasattr(self, key_dv):
            setattr(self, key_dv, {})
        if not hasattr(self, key_dt):
            setattr(self, key_dt, {})
        dic_dv = getattr(self, key_dv)
        dic_dt = getattr(self, key_dt)
        dic_dv['typ'] = units.float(typ_dv)
        dic_dv['min'] = units.float(typ_dv)
        dic_dv['max'] = units.float(typ_dv)
        dic_dt['typ'] = units.float(typ_dt)
        dic_dt['min'] = units.float(typ_dt)
        dic_dt['max'] = units.float(typ_dt)


class IbisModel_Spec(_Builder):
    """IBIS Model Spec Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.addRE(_reRange % "vinl", self.handleRange)
        self.addRE(_reRange % "vinh", self.handleRange)
        self.addRE(_reRange % "vinh[+]", self.handleRange)
        self.addRE(_reRange % "vinh[-]", self.handleRange)
        self.addRE(_reRange % "vinl[+]", self.handleRange)
        self.addRE(_reRange % "vinl[-]", self.handleRange)
        self.addRE(_reRange % "s[ _]overshoot[ _]high", self.handleRange)
        self.addRE(_reRange % "s[ _]overshoot[ _]low", self.handleRange)
        self.addRE(_reRange % "d[ _]overshoot[ _]high", self.handleRange)
        self.addRE(_reRange % "d[ _]overshoot[ _]low", self.handleRange)
        self.addRE(_reRange % "d[ _]overshoot[ _]time", self.handleRange)
        self.addRE(_reRange % "pulse_high", self.handleRange)
        self.addRE(_reRange % "pulse[ _]low", self.handleRange)
        self.addRE(_reRange % "pulse[ _]time", self.handleRange)
        self.addRE(_reRange % "vmeas", self.handleRange)
        self.addRE(_reRange % "vref", self.handleRange)
        self.addRE(_reRange % "cref", self.handleRange)
        self.addRE(_reRange % "rref", self.handleRange)
        self.addRE(_reRange % "cref[ _]rising", self.handleRange)
        self.addRE(_reRange % "cref[ _]falling", self.handleRange)
        self.addRE(_reRange % "rref[ _]rising", self.handleRange)
        self.addRE(_reRange % "rref[ _]falling", self.handleRange)
        self.addRE(_reRange % "vref[ _]rising", self.handleRange)
        self.addRE(_reRange % "vref[ _]falling", self.handleRange)
        self.addRE(_reRange % "vmeas[ _]rising", self.handleRange)
        self.addRE(_reRange % "vmeas[ _]falling", self.handleRange)
        self.addRE(_reRange % "rref[ _]diff", self.handleRange)
        self.addRE(_reRange % "cref[ _]diff", self.handleRange)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

class IbisModel(_Builder):
    """IBIS Model Model Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.addRE(_reNamed % "model[ _]type", self.handleName)
        self.addRE(_reNamed % "polarity", self.handleName)
        self.addRE(_reNamed % "enable", self.handleName)
        self.addRE(_reValue % "vinl", self.handleValue)
        self.addRE(_reValue % "vinh", self.handleValue)
        self.addRE(_reValue % "vmeas", self.handleValue)
        self.addRE(_reValue % "cref", self.handleValue)
        self.addRE(_reValue % "rref", self.handleValue)
        self.addRE(_reValue % "vref", self.handleValue)
        self.addRE(_reRange % "c_comp", self.handleRange)
        self.addRE(_reLabeledRange % "temperature[ _]range", self.handleRange)
        self.addRE(_reLabeledRange % "voltage[ _]range", self.handleRange)
        self.addRE(_reLabeledRange % "gnd[ _]clamp[ _]reference", self.handleRange)
        self.addRE(_reLabeledRange % "power[ _]clamp[ _]reference", self.handleRange)
        self.addRE(_reLabeledRange % "pulldown[ _]reference", self.handleRange)
        self.addRE(_reLabeledRange % "pullup[ _]reference", self.handleRange)
        self.addRE(_reLabel % "gnd[ _]clamp", self.handleVICurve)
        self.addRE(_reLabel % "power[ _]clamp", self.handleVICurve)
        self.addRE(_reLabel % "pulldown", self.handleVICurve)
        self.addRE(_reLabel % "pullup", self.handleVICurve)
        self.addRE(_reLabel % "ramp", self.handleSingle)
        self.addRE(_reLabel % "model[ _]spec", self.handleSingle)
        self.addRE(_reLabel % "rising[ _]waveform", self.handleWaveform)
        self.addRE(_reLabel % "falling[ _]waveform", self.handleWaveform)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

        # --------- Calculate the Driver TA Table (if it is a driver) -------

        if ((self.model_type.lower() == "3-state")
                or (self.model_type.lower() == "output")
                or (self.model_type.lower() == "i/o")):

            self.pullup_k = {}
            self.pulldown_k = {}

            self.calcDriverK = {}
            # Determine which function to use to calculate ku and kd
            # For both falling an rising Waveforms
            try:
                waveform = self.rising_waveform[1]
                self.calcDriverK[Rising] = calcDriverKDoubleWave
            except IndexError:
                self.calcDriverK[Rising] = calcDriverKSingleWave
            except AttributeError:
                self.calcDriverK[Rising] = calcDriverKRamp

            try:
                waveform = self.falling_waveform[1]
                self.calcDriverK[Falling] = calcDriverKDoubleWave
            except IndexError:
                self.calcDriverK[Falling] = calcDriverKSingleWave
            except AttributeError:
                self.calcDriverK[Falling] = calcDriverKRamp


            for direction in [Rising, Falling]:

                self.pullup_k[direction] = {}
                self.pulldown_k[direction] = {}

                # Calculate ku and kd at Typ, Min, and Max
                for speed in [Typical, Minimum, Maximum]:
                    (ku, kd) = self.calcDriverK[direction](self,
                            direction, speed)
                    self.pullup_k[direction][speed] = ku
                    self.pulldown_k[direction][speed] = kd

class IbisComponent(_Builder):
    """IBIS Model Component Data"""
    def __init__(self, fdin):
        _Builder.__init__(self)
        self.fdin = fdin

        self.addRE(_reNamed % "si[ _]location", self.handleName)
        self.addRE(_reNamed % "timing[ _]location", self.handleName)
        self.addRE(_reLabeled % "manufacturer", self.handleName)
        self.addRE(_reLabel % "package", self.handleSingle)
        self.addRE(_reLabel % "pin", self.handleSingleDict)
        self.addRE(_reAny, Done)

        self.process()

        del self.fdin
        del self.patterns

class Ibis_Parser(_Builder):
    """IBIS Model"""
    def __init__(self, filename, device=None):
        """
        Arguments:
        filename -- IBIS Model to import
        device -- (optional) name of default device, default = first device
        """

        _Builder.__init__(self)
        if filename == 'test':
            import ibis_test
            import io
            self.fdin = io.StringIO(ibis_test.ibis_test)
        else:
            filename = os.path.join(sys.path[0], filename)
            self.fdin = open(filename, 'r')

        self.addRE(_reLabeled % "ibis[ _]ver", self.handleName)
        # Todo: Make this comment char thing work
        self.addRE(_reLabeled % "comment[ _]char", self.handleCommentChar)
        self.addRE(_reLabeled % "file[ _]name", self.handleName)
        self.addRE(_reLabeled % "file[ _]rev", self.handleName)
        self.addRE(_reLabeled % "date", self.handleName)
        self.addRE(_reLabeled % "source", self.handleBlock)
        self.addRE(_reLabeled % "notes", self.handleBlock)
        self.addRE(_reLabeled % "disclaimer", self.handleBlock)
        self.addRE(_reLabeled % "copyright", self.handleBlock)
        self.addRE(_reLabeled % "component", self.handleMulti)
        self.addRE(_reLabeled % "model[ _]selector", self.handleMulti)
        self.addRE(_reLabeled % "model", self.handleMulti)
        self.addRE(_reLabel % "end", Done)
        self.addRE(_reAny, self.handleUnkown)

        self.process()

        self.fdin.close()

        del self.fdin
        del self.patterns

        # Set the default component (called device)
        if device == None:
            self.device = list(self.component.keys())[0]
        else:
            if device in self.component:
                self.device = device
            else:
                raise RuntimeError("Can not find %s in the IBIS File" % device)

Web Proxy Viewer  |  New URL  |  Original Page