russdill / pybis

Python based IBIS parser
GNU Lesser General Public License v2.1
21 stars 10 forks source link

================================= PyBIS -- Python based IBIS parser

Introduction

This module contains a python based IBIS parser. The latest IBIS specification can be found here:

http://eda.org/pub/ibis/ver5.0/ver5_0.txt

Parsing an IBIS file can be accomplished as follows:

import pybis
results = pybis.IBSParser().parse('test.ibs')
print results.header.file_rev

The additional parsers 'PKGParser' and 'EBDParser' are available for parsing '.pkg' and '.ebd' files respectively.

Handling Parse Results

Parse results are return as a tree of 'IBISNode' objects. An 'IBISNode' object is a python dict. Each key/value pair represents a section, keyword, or param. Each value can be a:

- IBISNode
- Range
- list
- dict
- numpy matrix
- string
- float
- int
- None

In the case of a dict or list, the children can be any of the above except dict and list.

Children of an IBISNode can be accessed through the standard dict accessors as well as with the python attribute accessors. Additionally, any accesses are case insensitive and allow the use of a '_' in place of ' ' or '/', 'p' in place of '+', and 'n' in place of '-':

results.model["SSTL18"].model_spec.vinlp
results.MODEL["SSTL18"].Model_Spec["Vinl+"]
results["Model"]["SSTL18"]["Model Spec"].Vinlp

Objects represented by dict values, such as the set of components, do not have this property.

If the specification indicates that a certain keyword is required in certain circumstances or defaults to a certain value, the parser will ensure that condition is met. For optional keywords, and if block or try/except block can be used:

if 'Copyright' in results.header:
    print results.header.copyright
else:
    print 'Not specified'

try:
    print results.header["Copyright"]
except:
    print 'Not specified'

print result.header.get('Copyright', 'Not specified')

A 'Range' type represents a typ/min/max set. It can be accessed through the following methods:

[0-2] -                  Return raw values (0 = typ, 1 = min, 2 = max).
(0-2) -                  Return typ for min or max if they are 'None'.
(0-2, invert=False) -    Ensure max > min.
(0-2, invert=True) -     Ensure mix > max.
.typ, .min, .max -       Easy accessors for (0-2).
.norm -                  Return version of object where max > min.
.inv -                   return version of object where min > max.

A keyword such as 'Pin', 'Pin Mapping', or 'Pin EMI' that names columns, is stored as a dict of IBISNode's indexed by the key in the first column. The column names are the keys of the IBISNode's. This is also true of sections that implicitly name columns such as 'Driver Schedule'.

Keywords that represent waveforms or I-V curves such as 'Pulldown', 'GND Clamp', and 'Rising Waveform' are stored as a 'Range' object. Each item in the Range object is an x, y tuple who's members are a list of floats.

'NA' and 'NC' entries are stored as None.

'[End...]' keywords are not stored.

Parse Results - Section 4 - File Header Information

Keywords within the file header are stored in a "fake" section called "header". Multiple occurrences of multi-line sections, such as 'Source' and 'Copyright' are merged together. The 'Comment Char' keyword does not appear in parse output.

print results.header["File Name"]

Parse Results - Section 5 - Component Description

Components are stored as a dict within the 'Component' keyword with each key representing a component name, and each value representing a component.

Items in the 'Series Pin Mapping' keyword are indexed by the tuple (pin_1, pin_2).

'Series Switch Groups' are just stored as a list of lists, which each list starting with the keyword 'on' or 'off'.

Parse Results - Section 6 - Model Statement

Models are stored as a dict within the 'Model' keyword with each key representing a model name, and each value representing a model.

Drain model types are deprecated and replaced by the parser with the associated sink type.

The 'Rising Waveform' and 'Falling Waveform' sections are stored as a list of sections. Because the section contains multiple keywords along with waveform data, the waveform data is stored under the keyword 'waveform'. Additionally, the keywords 'V_fixture_min' and 'V_fixture_max' are combined with the 'V_fixture' keyword to create a Range.

'Series MOSFET' I-V tables are indexed by their 'Vds' value.

'Test Data' and 'Test Load' are handled the same way as 'Model' and 'Component' keywords.

Parse Results - Section 6a - Add Submodel Description

'Submodel' keywords are handling in a similar way to 'Model' keywords.

Parse Results - Section 6b - Multi-lingual Model Extensions

Multi-lingual extensions are supported as additional keywords under the 'Component' and 'Model' keywords as well as the additional top level 'External Circuit' keyword.

The data under the 'Corner' keyword is reorganized so that the 'file_name' keyword and 'circuit_name' keyword under 'Corner' each contain a Range object.

The 'D_to_A' and 'A_to_D' keywords are stored as dict's indexed by 'd_port'. Additionally, each parameter is stored as a Range object.

'Portmap' keywords are stored as dict's indexed by 'port'.

Parse Results - Section 6c - Algorithmic Modeling Interface (AMI)

The 'Algorithmic Model' keyword is supported under the 'Model' keyword. Although parsing of the keyword supported, pybis does not at this time parse AMI files.

Parse Results - Section 7 - Package Modeling

The matrices in 'Model Data' are stored as as a numpy matrix. A keyword, 'Pin Mapping', is added to 'Model Data' that provides a mapping from pin name to numpy matrix index.

The parser insures that a 'Package Model' contains either 'Model Data' or section data associated with pins, but not both. In either case, 'Pin Numbers' is stored as a dict indexed by pin name. In the 'Model Data' case, the value for each pin is 'None'. In the sections case, the value for each pin is a list of stubs. A stub can either be a 'Len', 'R', 'L', 'C' IBISNode, or it can be a list of stubs in the case of a fork.

Parse Results - Section 8 - Electrical Board Description

The 'Path Description' section under a 'Begin Board Description' keyword is stored as a list. Each element in the list can be an IBISNode containing 'Pin', 'Node', or 'Len'. If the IBISNode contains 'Len' it is a stub and may also contain 'L', 'R', and/or 'C'. An element in the list can also be a list, which indicates a fork.

Parse Results - Section 11 - EMI Parameters

Extra EMI keywords are supported under the 'Component' and 'Model' keywords.

Parse Errors

Parse errors throw an Exception along with a parse tree backtrace, which due to the immaturity of the parser, often does not return helpful data:

In 'body ' , 'Model BPS2P10F_PU50K' :
Parsing failed on line 2144: 'Ref                    = 1Mohms'
Traceback (most recent call last):
  File "pybis.py", line 2148, in <module>
    root = parser.parse(open(sys.argv[1], 'rb'))
  File "pybis.py", line 2019, in parse
    self.parseLine(line)
  File "pybis.py", line 2090, in parseLine
    self.current.parser.fin(self.current)
  File "pybis.py", line 1366, in fin
    .format(model_type, keyword))
Exception: Type 'i/o' missing required keyword 'Ramp'

In the above backtrace, the error listed is:

Type 'i/o' missing required keyword 'Ramp'

However, the cause of the error is a misspelling of the 'Rref' keyword. This is because upon encountering and unknown keyword in a section, the parser assumes the keyword is contained in a higher level section and so closes the section. The close function of the section notices that the 'Ramp' keyword is missing and throws an exception.

Most parse errors will occur when sections are closed. The line number given in this case will be the line number that cause the section to be closed:

In 'body ' , 'Model BPS2P10F_PU50K' :
Parsing failed on line 2785: '[Model]             BPS2P4F_PD50K'
Traceback (most recent call last):
  File "pybis.py", line 2148, in <module>
    root = parser.parse(open(sys.argv[1], 'rb'))
  File "pybis.py", line 2019, in parse
    self.parseLine(line)
  File "pybis.py", line 2090, in parseLine
    self.current.parser.fin(self.current)
  File "pybis.py", line 1366, in fin
    .format(model_type, keyword))
Exception: Type 'i/o' missing required keyword 'C_comp'

In this case the Exception is correct, but the line number is misleading. In both cases, the first line of the backtrace (starting with 'In') can be used to locate the error.

Performance

Performance of PyBIS is slower than the golden parser (ibischk5) by a factor of

  1. Although this is unfortunate, the performance should still be acceptable for many workloads.

of lines | ibischk5 | pybis | factor

79178 0m0.394s 0m3.438s 8.7 9624 0m0.056s 0m0.539s 9.6

Compatibility

Because the IBIS specification is somewhat vague, the definition of what is or is not a valid IBIS file is typically defined by what can pass though the golden parser (ibischk5).

Because of this, the highest priority of PyBIS is to accept any files accepted without errors by ibischk5. A secondary goal is to emit any valid errors or warnings that the golden parser emits.

Example Code

Example code is included in examples/.

models.py - Given an IBIS file as an argument, list the models contained in the IBIS file:

./models.py sample1.ibs
BIP00F input
BIPIN15F input
BPIN15F_PU50K input
BPIST02F input
BPIST02F_PU50K input
BPOZ2F 3-state
BPOZ4F 3-state
BPS2P10F_PU50K i/o
BPS2P4F_PD50K i/o
BPS2P4F_PU50K i/o
BT2Z50CX i/o
BT2Z50CX_PU50K i/o
BUSB6AU_HIGH_SPEED i/o
BUSB6AU_LOW_SPEED i/o

Selecting a model then displays the Time based and I-V curves of that model:

./models.py sample1.ibs BPOZ2F
(scipy plots are displayed)

ibs2symdef.py - Convert the components in an IBIS file to a djboxsym symdef file:

http://www.gedasymbols.org/user/dj_delorie/tools/djboxsym.html

This uses model information to intelligently place pins.

Sample Data

Some sample IBIS files have been collected and are present in samples/.

Installation

Do the usual:

python setup.py install

Future Changes

In the long term, it is desired that PyBIS will expand into a suite of python based IBIS tools. In the short term, the parser requires incremental changes. Some of the areas that need improvement are:

- Improved error messages.
- Warning messages.
- Improved compatibility.
- Performance improvements.
- Line numbers in parse results.
- Cleaned up code base.
- Additional IBIS samples including code test cases.

Some possible future feature ideas include:

- AMI parsing.
- IBIS version handling.
- Folding together of newer and older IBIS fields and features in parse
  output. For example, Vinl appears in 3 different keywords.
- A GUI based IBIS file viewer/browser.