# # 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)