skywater_pdk package

Submodules

skywater_pdk.base module

class skywater_pdk.base.Cell(name: str, library: Library | None = None)

Bases: object

Cell in a library.

Examples

>>> 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', version=None))
>>> 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)
classmethod from_dict(kvs: dict | list | str | int | float | bool | None, *, infer_missing=False) A
classmethod from_json(s: str | bytes | bytearray, *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) A
property fullname
library: Library | None = None
name: str
classmethod parse(s)
classmethod schema(*, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) SchemaF[A]
to_dict(encode_json=False) Dict[str, dict | list | str | int | float | bool | None]
to_json(*, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: int | str | None = None, separators: Tuple[str, str] | None = None, default: Callable | None = None, sort_keys: bool = False, **kw) str
class skywater_pdk.base.Library(node: LibraryNode, source: LibrarySource, type: LibraryType, name: str = '', version: LibraryVersion | None = None)

Bases: Library

Library of cells.

Examples

>>> l = Library.parse("sky130_fd_sc_hd")
>>> l
Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=None)
>>> 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', version=None)
>>> l.fullname
'sky130_rrr_sc_hd'
>>> l.source.fullname
"Unknown source: 'rrr'"
>>> l1 = Library.parse("sky130_fd_sc_hd")
>>> l2 = Library.parse("sky130_fd_sc_hdll")
>>> l = [l2, None, l1]
>>> l.sort()
node: LibraryNode
source: LibrarySource
type: LibraryType
class skywater_pdk.base.LibraryNode(value)

Bases: Enum

Process node for a library.

SKY130 = 'SkyWater 130nm'
classmethod parse(s)
to_json()
class skywater_pdk.base.LibrarySource

Bases: str

Where a library was created.

Known = [LibrarySource('fd'), LibrarySource('ef'), LibrarySource('osu')]
property fullname
classmethod parse(s)
to_json()
class skywater_pdk.base.LibraryType(value)

Bases: Enum

Type of library contents.

io = 'IO and Periphery'
classmethod parse(s)
pr = 'Primitives'
sc = 'Standard Cells'
sp = 'Build Space (Flash, SRAM, etc)'
to_json()
xx = 'Miscellaneous'
class skywater_pdk.base.LibraryVersion(milestone: int = 0, major: int = 0, minor: int = 0, commits: int = 0, hash: str = '')

Bases: LibraryVersion

Version number for a library.

Examples

>>> v0 = LibraryVersion.parse("v0.0.0")
>>> v0
LibraryVersion(milestone=0, major=0, minor=0, commits=0, hash='')
>>> v1a = LibraryVersion.parse("v0.0.0-10-g123abc")
>>> v1a
LibraryVersion(milestone=0, major=0, minor=0, commits=10, hash='123abc')
>>> v1b = LibraryVersion.parse("v0.0.0-4-g123abc")
>>> v1b
LibraryVersion(milestone=0, major=0, minor=0, commits=4, hash='123abc')
>>> v2 = LibraryVersion.parse("v0.0.2")
>>> v2
LibraryVersion(milestone=0, major=0, minor=2, commits=0, hash='')
>>> v3 = LibraryVersion.parse("v0.2.0")
>>> v3
LibraryVersion(milestone=0, major=2, minor=0, commits=0, hash='')
>>> v4 = LibraryVersion.parse("v0.0.10")
>>> v4
LibraryVersion(milestone=0, major=0, minor=10, commits=0, hash='')
>>> v0 < v1a
True
>>> v1a < v2
True
>>> v0 < v2
True
>>> l = [v1a, v2, v3, None, v1b, v0, v2]
>>> l.sort()
>>> [i.fullname for i in l]
['0.0.0', '0.0.0-4-g123abc', '0.0.0-10-g123abc', '0.0.2', '0.0.2', '0.2.0']
skywater_pdk.base.parse_filename(pathname) Tuple[Library | Cell, str | None, str | None]

Extract library and module name from filename.

Returns:

  • obj (Library or Cell) – Library or Cell information parsed from filename

  • extra (str, optional) – String containing any extra unparsed data (like corner information)

  • ext (str, optional) – String containing the file extension

Examples

>>> 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='', version=None))
>>> t.pop(0)
'tt_1p80V_3p30V_3p30V_25C'
>>> t.pop(0)
'wrap.lib'
>>> t = list(parse_filename('v0.10.0/sky130_fd_sc_hdll__a211o__tt_1p80V_3p30V_3p30V_25C.wrap.json'))
>>> t.pop(0)
Cell(name='a211o', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hdll', version=LibraryVersion(milestone=0, major=10, minor=0, commits=0, hash='')))
>>> t.pop(0)
'tt_1p80V_3p30V_3p30V_25C'
>>> t.pop(0)
'wrap.json'
>>> t = list(parse_filename('sky130_fd_io/v0.1.0/sky130_fd_io__top_powerhv_hvc_wpad__tt_1p80V_3p30V_100C.wrap.json'))
>>> t.pop(0)
Cell(name='top_powerhv_hvc_wpad', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.io, name='', version=LibraryVersion(milestone=0, major=1, minor=0, commits=0, hash='')))
>>> from skywater_pdk.corners import parse_filename as pf_corners
>>> pf_corners(t.pop(0))
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3), temps=(100,), flags=None), [])
>>> t.pop(0)
'wrap.json'
>>> parse_filename('libraries/sky130_fd_io/v0.2.1/cells/analog_pad/sky130_fd_io-analog_pad.blackbox.v')[0]
Cell(name='analog_pad', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.io, name='', version=LibraryVersion(milestone=0, major=2, minor=1, commits=0, hash='')))
>>> t = list(parse_filename('skywater-pdk/libraries/sky130_fd_sc_hd/v0.0.1/cells/a2111o/sky130_fd_sc_hd__a2111o.blackbox.v'))
>>> t.pop(0)
Cell(name='a2111o', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')))
>>> assert t.pop(0) is None
>>> t.pop(0)
'blackbox.v'
skywater_pdk.base.parse_pathname(pathname)

Extract library and module name for pathname.

Returns:

  • obj (Library or Cell) – Library or Cell information parsed from filename

  • filename (str, optional) – String containing any filename extracted. String containing the file extension

Examples

>>> parse_pathname('skywater-pdk/libraries/sky130_fd_sc_hd/v0.0.1/cells/a2111o')
(Cell(name='a2111o', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash=''))), None)
>>> parse_pathname('skywater-pdk/libraries/sky130_fd_sc_hd/v0.0.1/cells/a2111o/README.rst')
(Cell(name='a2111o', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash=''))), 'README.rst')
>>> parse_pathname('skywater-pdk/libraries/sky130_fd_sc_hd/v0.0.1')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), None)
>>> parse_pathname('skywater-pdk/libraries/sky130_fd_sc_hd/v0.0.1/README.rst')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), 'README.rst')
>>> parse_pathname('libraries/sky130_fd_sc_hd/v0.0.1')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), None)
>>> parse_pathname('libraries/sky130_fd_sc_hd/v0.0.1/README.rst')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), 'README.rst')
>>> parse_pathname('sky130_fd_sc_hd/v0.0.1')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), None)
>>> parse_pathname('sky130_fd_sc_hd/v0.0.1/README.rst')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), 'README.rst')
>>> parse_pathname('sky130_fd_sc_hd/v0.0.1/RANDOM')
(Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.sc, name='hd', version=LibraryVersion(milestone=0, major=0, minor=1, commits=0, hash='')), 'RANDOM')
>>> parse_pathname('RANDOM') 
Traceback (most recent call last):
    ...
ValueError: ...
>>> parse_pathname('libraries/RANDOM/v0.0.1') 
Traceback (most recent call last):
    ...
ValueError: ...
>>> parse_pathname('libraries/skywater_fd_sc_hd/vA.B.C') 
Traceback (most recent call last):
    ...
ValueError: ...

skywater_pdk.corners module

class skywater_pdk.corners.Corner(corner: Tuple[CornerType, CornerType], volts: Tuple[float, ...], temps: Tuple[int, ...], flags: Tuple[CornerFlag, ...] | None = None)

Bases: Corner

corner: Tuple[CornerType, CornerType]
temps: Tuple[int, ...]
volts: Tuple[float, ...]
class skywater_pdk.corners.CornerFlag(value)

Bases: OrderedFlag

ccsnoise = 'Composite Current Source Noise'
hv = 'High voltage'
lowhv = 'Low High Voltage'
lv = 'Low voltage'
nointpr = 'No internal power'
classmethod parse(s)
pwr = 'Power'
to_json()
w = 'w'
xx = 'xx'
class skywater_pdk.corners.CornerType(value)

Bases: OrderedFlag

Examples

>>> CornerType.parse('t')
CornerType.t
>>> CornerType.parse('tt')
[CornerType.t, CornerType.t]
>>> CornerType.parse('wp')
[CornerType.f, CornerType.f]
f = 'Fast'
classmethod parse(s)
s = 'Slow'
t = 'Typical'
to_json()
class skywater_pdk.corners.OptionalTuple(iterable=(), /)

Bases: OptionalTuple

skywater_pdk.corners.parse_filename(pathname)

Extract corner information from a filename.

See also

skywater_pdk.base.parse_pathname, skywater_pdk.base.parse_filehname

Examples

>>> parse_filename('tt_1p80V_3p30V_3p30V_25C')
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
>>> parse_filename('sky130_fd_io__top_ground_padonlyv2__tt_1p80V_3p30V_3p30V_25C.wrap.lib')
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.json')
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.lib')
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_25C_ccsnoise.wrap.json')
(Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(25,), flags=(CornerFlag.ccsnoise,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p65V_n40C.wrap.json')
(Corner(corner=(CornerType.f, CornerType.f), volts=(1.65,), temps=(-40,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_85C_pwr.wrap.lib')
(Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(85,), flags=(CornerFlag.pwr,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_ccsnoise.wrap.json')
(Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.ccsnoise,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_pwr.wrap.lib')
(Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.pwr,)), [])
>>> parse_filename('sky130_fd_sc_hd__a2111o_4__ss_1p76V_n40C.cell.json')
(Corner(corner=(CornerType.s, CornerType.s), volts=(1.76,), temps=(-40,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ls__lpflow_lsbuf_lh_1__lpflow_wc_lh_level_shifters_ss_1p95V_n40C.cell.json')
(Corner(corner=(CornerType.s, CornerType.s), volts=(1.95,), temps=(-40,), flags=None), ['wc', 'lh', 'level', 'shifters'])
>>> parse_filename('sky130_fd_sc_hvl__lsbufhv2hv_hl_1__ff_5p50V_lowhv_1p65V_lv_ss_1p60V_100C.cell.json')
(Corner(corner=(CornerType.f, CornerType.s), volts=(5.5, 1.65, 1.6), temps=(100,), flags=(CornerFlag.lowhv, CornerFlag.lv)), [])

skywater_pdk.sizes module

class skywater_pdk.sizes.CellSize

Bases: ABC

Drive strength variants of a given cell.

Examples

>>> d1 = CellSize.from_suffix("_1")
>>> d2 = CellSize.from_suffix("_lp")
>>> d3 = CellSize.from_suffix("_m")
>>> d4 = CellSize.from_suffix("_2")
>>> CellSize.from_suffix("_abc")
Traceback (most recent call last):
    ...
InvalidSuffixError: Invalid suffix: _abc
>>> l = [d1, d2, d3, d4]
>>> l
[CellSizeNumeric(units=1), CellSizeLowPower(lp_variant=0), CellSizeMinimum(), CellSizeNumeric(units=2)]
>>> l.sort()
>>> l
[CellSizeNumeric(units=1), CellSizeNumeric(units=2), CellSizeLowPower(lp_variant=0), CellSizeMinimum()]
abstract describe()
classmethod from_suffix(s)
abstract property suffix
class skywater_pdk.sizes.CellSizeLowPower(lp_variant: int = 0)

Bases: CellSize

Examples

>>> lp = CellSizeLowPower.from_suffix("_lp")
>>> lp2 = CellSizeLowPower.from_suffix("_lp2")
>>> lp3 = CellSizeLowPower.from_suffix("_lp3")
>>> CellSizeLowPower.from_suffix("_ld")
Traceback (most recent call last):
    ...
InvalidSuffixError: Invalid suffix: _ld
>>> lp
CellSizeLowPower(lp_variant=0)
>>> lp2
CellSizeLowPower(lp_variant=1)
>>> lp3
CellSizeLowPower(lp_variant=2)
>>> str(lp)
'with size for low power'
>>> str(lp2)
'with size for low power (alternative)'
>>> str(lp3)
'with size for low power (extra alternative 0)'
>>> lp.describe()
'for low power'
>>> lp2.describe()
'for low power (alternative)'
>>> lp3.describe()
'for low power (extra alternative 0)'
>>> lp.suffix
'_lp'
>>> lp2.suffix
'_lp2'
>>> lp3.suffix
'_lp3'
describe()
classmethod from_dict(kvs: dict | list | str | int | float | bool | None, *, infer_missing=False) A
classmethod from_json(s: str | bytes | bytearray, *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) A
classmethod from_suffix(s)
lp_variant: int = 0
classmethod schema(*, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) SchemaF[A]
property suffix
to_dict(encode_json=False) Dict[str, dict | list | str | int | float | bool | None]
to_json(*, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: int | str | None = None, separators: Tuple[str, str] | None = None, default: Callable | None = None, sort_keys: bool = False, **kw) str
class skywater_pdk.sizes.CellSizeMinimum

Bases: CellSize

Examples

>>> m = CellSizeMinimum.from_suffix("_m")
>>> CellSizeMinimum.from_suffix("_m2")
Traceback (most recent call last):
    ...
InvalidSuffixError: Invalid suffix: _m2
>>> m
CellSizeMinimum()
>>> str(m)
'with size minimum'
>>> m.describe()
'minimum'
>>> m.suffix
'_m'
>>> m1 = CellSizeMinimum()
>>> m2 = CellSizeMinimum()
>>> assert m1 is m2
describe()
classmethod from_suffix(s)
property suffix
to_dict()
class skywater_pdk.sizes.CellSizeNumeric(units: int)

Bases: CellSize

Examples

>>> s1 = CellSizeNumeric.from_suffix("_1")
>>> s2 = CellSizeNumeric.from_suffix("_2")
>>> s3 = CellSizeNumeric.from_suffix("_3")
>>> CellSizeNumeric.from_suffix("_-1")
Traceback (most recent call last):
    ...
InvalidSuffixError: Invalid suffix: _-1
>>> s1
CellSizeNumeric(units=1)
>>> s2
CellSizeNumeric(units=2)
>>> s3
CellSizeNumeric(units=3)
>>> str(s1)
'with size of 1 units'
>>> str(s2)
'with size of 2 units'
>>> str(s3)
'with size of 3 units (invalid?)'
>>> s1.describe()
'of 1 units'
>>> s2.describe()
'of 2 units'
>>> s3.describe()
'of 3 units (invalid?)'
>>> s1.suffix
'_1'
>>> s2.suffix
'_2'
>>> s3.suffix
'_3'
VALID_UNIT_VALUES = (0, 1, 2, 4, 8, 6, 12, 14, 16, 20, 32)
describe()
classmethod from_dict(kvs: dict | list | str | int | float | bool | None, *, infer_missing=False) A
classmethod from_json(s: str | bytes | bytearray, *, parse_float=None, parse_int=None, parse_constant=None, infer_missing=False, **kw) A
classmethod from_suffix(s)
classmethod schema(*, infer_missing: bool = False, only=None, exclude=(), many: bool = False, context=None, load_only=(), dump_only=(), partial: bool = False, unknown=None) SchemaF[A]
property suffix
to_dict(encode_json=False) Dict[str, dict | list | str | int | float | bool | None]
to_json(*, skipkeys: bool = False, ensure_ascii: bool = True, check_circular: bool = True, allow_nan: bool = True, indent: int | str | None = None, separators: Tuple[str, str] | None = None, default: Callable | None = None, sort_keys: bool = False, **kw) str
units: int
exception skywater_pdk.sizes.InvalidSuffixError(s)

Bases: ValueError

skywater_pdk.sizes.parse_size(s)
>>> parse_size('_1')
CellSizeNumeric(units=1)
>>> parse_size('a2111o_1')
CellSizeNumeric(units=1)
>>> parse_size('sky130_fd_sc_ms__sdfrtp_1.v')
CellSizeNumeric(units=1)
>>> parse_size('libraries/sky130_fd_sc_ms/v0.0.1/cells/sdfrtp/sky130_fd_sc_ms__sdfrtp_1.v')
CellSizeNumeric(units=1)
>>> parse_size('libraries/sky130_fd_sc_ms/v0.0.1/cells/sdfrtp/sky130_fd_sc_ms__sdfrtp_1.bb.blackbox.v')
CellSizeNumeric(units=1)
>>> parse_size('libraries/sky130_fd_sc_ms/v0.0.1/cells/sdfrtp/sky130_fd_sc_ms__sdfrtp.v')
>>> parse_size('sky130_fd_sc_ms__sdfrtp.v')
>>> parse_size('_blah')

skywater_pdk.utils module

class skywater_pdk.utils.OrderedFlag(value)

Bases: Flag

An enumeration.

skywater_pdk.utils.comparable_to_none(cls)

Examples

>>> @comparable_to_none
... @dataclass(order=True)
... class A:
...     a: int = 0
>>> @comparable_to_none
... @dataclass(order=True)
... class B:
...     b: Optional[A] = None
>>> b0 = B()
>>> repr(b0)
'B(b=None)'
>>> str(b0)
'B(b=None)'
>>> b1 = B(A())
>>> repr(b1)
'B(b=A(a=0))'
>>> str(b1)
'B(b=A(a=0))'
>>> b2 = B(A(2))
>>> repr(b2)
'B(b=A(a=2))'
>>> str(b2)
'B(b=A(a=2))'
>>> l = [b0, b1, b2, None]
>>> for i in range(0, 3):
...     random.shuffle(l)
...     l.sort()
...     print(l)
[None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
[None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
[None, B(b=None), B(b=A(a=0)), B(b=A(a=2))]
skywater_pdk.utils.dataclass_json_passthru_config(*args, **kw)
skywater_pdk.utils.dataclass_json_passthru_sequence_config(*args, **kw)
skywater_pdk.utils.extract_numbers(s)

Create tuple with sequences of numbers converted to ints.

>>> extract_numbers("pwr_template13x10")
('pwr_template', 13, 'x', 10)
>>> extract_numbers("vio_10_10_1")
('vio_', 10, '_', 10, '_', 1)
skywater_pdk.utils.sortable_extracted_numbers(s)

Create output which is sortable by numeric values in string.

>>> sortable_extracted_numbers("pwr_template13x10")
('pwr_template', '0000000013', 'x', '0000000010')
>>> sortable_extracted_numbers("vio_10_10_1")
('vio_', '0000000010', '_', '0000000010', '_', '0000000001')
>>> l = ['a1', 'a2b2', 'a10b10', 'b2', 'a8b50', 'a10b1']
>>> l.sort()
>>> print('\n'.join(l))
a1
a10b1
a10b10
a2b2
a8b50
b2
>>> l.sort(key=sortable_extracted_numbers)
>>> print('\n'.join(l))
a1
a2b2
a8b50
a10b1
a10b10
b2

Module contents