blob: c86cde256b73a945a9f795fa1b9fdd9c9d165178 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright 2020 The SkyWater PDK Authors.
#
# Use of this source code is governed by the Apache 2.0
# license that can be found in the LICENSE file or at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
import os
from dataclasses import dataclass
from enum import Enum
from typing import Optional
def parse_filename(pathname):
"""Extract library and module name from pathname.
>>> t = list(parse_filename('sky130_fd_io-top_ground_padonlyv2-tt_1p80V_3p30V_3p30V_25C.wrap.lib'))
>>> t.pop(0)
Cell(name='top_ground_padonlyv2', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.io, name=None))
>>> t.pop(0)
'tt_1p80V_3p30V_3p30V_25C'
>>> t.pop(0)
'wrap.lib'
"""
dirname, filename = os.path.split(pathname)
if '.' in filename:
basename, extension = filename.split('.', 1)
else:
basename = filename
extension = ''
basename = basename.replace('-', SEPERATOR)
library, cell, extra = basename.split(SEPERATOR, 3)
return (Cell.parse(library+SEPERATOR+cell), extra, extension)
SEPERATOR = "__"
class LibraryNode(Enum):
SKY130 = "SkyWater 130nm"
@classmethod
def parse(cls, s):
s = s.upper()
if not hasattr(cls, s):
raise ValueError("Unknown node: {}".format(s))
return getattr(cls, s)
def __repr__(self):
return "LibraryNode."+self.name
class LibrarySource(str):
"""Where a library was created."""
Known = []
@classmethod
def parse(cls, s):
try:
return cls.Known[cls.Known.index(s)]
except ValueError:
return cls(s)
@property
def fullname(self):
if self in self.Known:
return self.__doc__
else:
return 'Unknown source: '+str.__repr__(self)
def __repr__(self):
return 'LibrarySource({})'.format(str.__repr__(self))
Foundary = LibrarySource("fd")
Foundary.__doc__ = "The SkyWater Foundary"
LibrarySource.Known.append(Foundary)
Efabless = LibrarySource("ef")
Efabless.__doc__ = "Efabless"
LibrarySource.Known.append(Efabless)
OSU = LibrarySource("osu")
OSU.__doc__ = "Oklahoma State University"
LibrarySource.Known.append(OSU)
class LibraryType(Enum):
pr = "Primitives"
sc = "Standard Cells"
sp = "Build Space (Flash, SRAM, etc)"
io = "IO and Periphery"
xx = "Miscellaneous"
@classmethod
def parse(cls, s):
if not hasattr(cls, s):
raise ValueError("Unknown library type: {}".format(s))
return getattr(cls, s)
def __repr__(self):
return "LibraryType."+self.name
def __str__(self):
return self.value
@dataclass
class Library:
"""
>>> l = Library.parse("sky130_fd_sc_hd")
>>> l
Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd')
>>> l.fullname
'sky130_fd_sc_hd'
>>> l.source.fullname
'The SkyWater Foundary'
>>> print(l.type)
Standard Cells
>>> l = Library.parse("sky130_rrr_sc_hd")
>>> l
Library(node=LibraryNode.SKY130, source=LibrarySource('rrr'), type=LibraryType.sc, name='hd')
>>> l.fullname
'sky130_rrr_sc_hd'
>>> l.source.fullname
"Unknown source: 'rrr'"
"""
node: LibraryNode
source: LibrarySource
type: LibraryType
name: Optional[str] = None
@property
def fullname(self):
output = []
output.append(self.node.name.lower())
output.append(self.source.lower())
output.append(self.type.name)
if self.name:
output.append(self.name)
return "_".join(output)
@classmethod
def parse(cls, s):
if SEPERATOR in s:
raise ValueError(
"Found separator '__' in library name: {!r}".format(s))
bits = s.split("_")
if len(bits) < 3:
raise ValueError(
"Did not find enough parts in library name: {}".format(bits))
kw = {}
kw['node'] = LibraryNode.parse(bits.pop(0))
kw['source'] = LibrarySource.parse(bits.pop(0))
kw['type'] = LibraryType.parse(bits.pop(0))
if bits:
kw['name'] = bits.pop(0)
return cls(**kw)
@dataclass
class Cell:
"""
>>> c = Cell.parse("sky130_fd_sc_hd__abc")
>>> c
Cell(name='abc', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd'))
>>> c.fullname
'sky130_fd_sc_hd__abc'
>>> c = Cell.parse("abc")
>>> c
Cell(name='abc', library=None)
>>> c.fullname
Traceback (most recent call last):
...
ValueError: Can't get fullname for cell without a library! Cell(name='abc', library=None)
"""
name: str
library: Optional[Library] = None
@property
def fullname(self):
if not self.library:
raise ValueError(
"Can't get fullname for cell without a library! {}".format(
self))
return "{}__{}".format(self.library.fullname, self.name)
@classmethod
def parse(cls, s):
kw = {}
if SEPERATOR in s:
library, s = s.split(SEPERATOR, 1)
kw['library'] = Library.parse(library)
kw['name'] = s
return cls(**kw)
if __name__ == "__main__":
import doctest
doctest.testmod()