Showing preview only (1,488K chars total). Download the full file or copy to clipboard to get everything.
Repository: ucb-art/BAG_framework
Branch: master
Commit: daf4b0aaa72f
Files: 162
Total size: 1.4 MB
Directory structure:
gitextract_e9aig5le/
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── bag/
│ ├── LICENSE
│ ├── __init__.py
│ ├── concurrent/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── core.py
│ ├── core.py
│ ├── data/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ ├── dc.py
│ │ ├── digital.py
│ │ ├── lti.py
│ │ ├── ltv.py
│ │ ├── mos.py
│ │ └── plot.py
│ ├── design/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── module.py
│ ├── interface/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── database.py
│ │ ├── ocean.py
│ │ ├── server.py
│ │ ├── simulator.py
│ │ ├── skill.py
│ │ ├── templates/
│ │ │ ├── LICENSE
│ │ │ ├── Module.pyi
│ │ │ ├── PrimModule.pyi
│ │ │ ├── calibreview_setup.txt
│ │ │ ├── load_results.ocn
│ │ │ └── run_simulation.ocn
│ │ └── zmqwrapper.py
│ ├── io/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── file.py
│ │ ├── gui.py
│ │ ├── process.py
│ │ ├── sim_data.py
│ │ └── template.py
│ ├── layout/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ ├── digital.py
│ │ ├── objects.py
│ │ ├── routing/
│ │ │ ├── LICENSE
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── fill.py
│ │ │ └── grid.py
│ │ ├── tech.py
│ │ ├── template.py
│ │ └── util.py
│ ├── math/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── dfun.py
│ │ └── interpolate.py
│ ├── mdao/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── components.py
│ │ └── core.py
│ ├── simulation/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ └── core_v2.py
│ ├── tech/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ └── mos.py
│ ├── util/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── cache.py
│ │ ├── immutable.py
│ │ ├── interval.py
│ │ ├── parse.py
│ │ └── search.py
│ ├── verification/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── calibre.py
│ │ ├── icv.py
│ │ ├── pvs.py
│ │ ├── templates/
│ │ │ ├── LICENSE
│ │ │ ├── layout_export_config.txt
│ │ │ └── si_env.txt
│ │ └── virtuoso.py
│ └── virtuoso.py
├── docs/
│ ├── .gitignore
│ ├── LICENSE
│ ├── Makefile
│ ├── README
│ ├── refresh_api.sh
│ └── source/
│ ├── LICENSE
│ ├── api/
│ │ ├── LICENSE
│ │ ├── bag.data.rst
│ │ ├── bag.design.rst
│ │ ├── bag.interface.rst
│ │ ├── bag.io.rst
│ │ ├── bag.layout.routing.rst
│ │ ├── bag.layout.rst
│ │ ├── bag.math.rst
│ │ ├── bag.mdao.rst
│ │ ├── bag.rst
│ │ ├── bag.tech.rst
│ │ ├── bag.util.rst
│ │ ├── bag.verification.rst
│ │ └── modules.rst
│ ├── conf.py
│ ├── developer/
│ │ ├── LICENSE
│ │ └── developer.rst
│ ├── index.rst
│ ├── overview/
│ │ ├── LICENSE
│ │ ├── design.rst
│ │ ├── overview.rst
│ │ ├── schematic.rst
│ │ └── testbench.rst
│ ├── setup/
│ │ ├── LICENSE
│ │ ├── bag_config/
│ │ │ ├── LICENSE
│ │ │ ├── bag_config.rst
│ │ │ ├── database/
│ │ │ │ └── database.rst
│ │ │ ├── misc.rst
│ │ │ ├── simulation/
│ │ │ │ └── simulation.rst
│ │ │ └── socket/
│ │ │ └── socket.rst
│ │ ├── config_summary.rst
│ │ ├── install_python.rst
│ │ ├── new_pdk.rst
│ │ ├── pyoptsparse.rst
│ │ ├── setup.rst
│ │ └── tech_config/
│ │ ├── LICENSE
│ │ ├── layout/
│ │ │ └── layout.rst
│ │ ├── misc.rst
│ │ ├── mos/
│ │ │ └── mos.rst
│ │ └── tech_config.rst
│ └── tutorial/
│ ├── LICENSE
│ ├── figures/
│ │ └── LICENSE
│ └── tutorial.rst
├── run_scripts/
│ ├── LICENSE
│ ├── clean_cds_lib.py
│ ├── compile_verilog.il
│ ├── gen_cell.py
│ ├── generate_verilog.py
│ ├── meas_cell.py
│ ├── run_bag.sh
│ ├── setup_submodules.py
│ ├── sim_cell.py
│ ├── start_bag.il
│ ├── start_bag.sh
│ ├── start_bag_ICADV12d3.il
│ └── virt_server.sh
├── setup.py
└── tests/
├── LICENSE
├── __init__.py
└── layout/
├── LICENSE
├── __init__.py
└── routing/
├── LICENSE
├── __init__.py
└── test_fill.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*~
*.pyc
.idea
build
dist
bag.egg-info
__pycache__
*.swp
================================================
FILE: .gitmodules
================================================
[submodule "cybag_oa"]
path = cybag_oa
url = https://github.com/ucb-art/cybag_oa.git
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
Berkeley Analog Generator (BAG) version 2.0 and later.
BAG 2.0 is a complete rewrite of BAG 1.x (which is in pre-alpha stage and
never released publicly).
(Very outdated) Documentation and install instructions can be found at <http://bag-framework.readthedocs.io/en/latest/>
A tutorial setup is available at <https://github.com/ucb-art/BAG2_cds_ff_mpt.git/>
================================================
FILE: bag/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: bag/__init__.py
================================================
# -*- coding: utf-8 -*-
"""This is the bag root package.
"""
import signal
from . import math
from .math import float_to_si_string, si_string_to_float
from . import interface
from . import design
from . import data
from . import tech
from . import layout
from .core import BagProject, create_tech_info
__all__ = ['interface', 'design', 'data', 'math', 'tech', 'layout', 'BagProject',
'float_to_si_string', 'si_string_to_float', 'create_tech_info']
# make sure that SIGINT will always be catched by python.
signal.signal(signal.SIGINT, signal.default_int_handler)
================================================
FILE: bag/concurrent/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: bag/concurrent/__init__.py
================================================
# -*- coding: utf-8 -*-
"""This package define helper classes used to perform concurrent operations.
"""
================================================
FILE: bag/concurrent/core.py
================================================
# -*- coding: utf-8 -*-
"""This module define utility classes for performing concurrent operations.
"""
from typing import Optional, Sequence, Dict, Union, Tuple, Callable, Any
import os
import asyncio
# noinspection PyProtectedMember
from asyncio.subprocess import Process
import subprocess
import multiprocessing
from concurrent.futures import CancelledError
def batch_async_task(coro_list):
"""Execute a list of coroutines or futures concurrently.
User may press Ctrl-C to cancel all given tasks.
Parameters
----------
coro_list :
a list of coroutines or futures to run concurrently.
Returns
-------
results :
a list of return values or raised exceptions of given tasks.
"""
top_future = asyncio.gather(*coro_list, return_exceptions=True)
loop = asyncio.get_event_loop()
try:
print('Running tasks, Press Ctrl-C to cancel.')
results = loop.run_until_complete(top_future)
except KeyboardInterrupt:
print('Ctrl-C detected, Cancelling tasks.')
top_future.cancel()
loop.run_forever()
results = None
return results
ProcInfo = Tuple[Union[str, Sequence[str]], str, Optional[Dict[str, str]], Optional[str]]
FlowInfo = Tuple[Union[str, Sequence[str]], str, Optional[Dict[str, str]], Optional[str],
Callable[[Optional[int], str], Any]]
class SubProcessManager(object):
"""A class that provides convenient methods to run multiple subprocesses in parallel using asyncio.
Parameters
----------
max_workers : Optional[int]
number of maximum allowed subprocesses. If None, defaults to system
CPU count.
cancel_timeout : Optional[float]
Number of seconds to wait for a process to terminate once SIGTERM or
SIGKILL is issued. Defaults to 10 seconds.
"""
def __init__(self, max_workers=None, cancel_timeout=10.0):
# type: (Optional[int], Optional[float]) -> None
if max_workers is None:
max_workers = multiprocessing.cpu_count()
if cancel_timeout is None:
cancel_timeout = 10.0
self._cancel_timeout = cancel_timeout
self._semaphore = asyncio.Semaphore(max_workers)
async def _kill_subprocess(self, proc: Optional[Process]) -> None:
"""Helper method; send SIGTERM/SIGKILL to a subprocess.
This method first sends SIGTERM to the subprocess. If the process hasn't terminated
after a given timeout, it sends SIGKILL.
Parameter
---------
proc : Optional[Process]
the process to attempt to terminate. If None, this method does nothing.
"""
if proc is not None:
if proc.returncode is None:
try:
proc.terminate()
try:
await asyncio.shield(asyncio.wait_for(proc.wait(), self._cancel_timeout))
except CancelledError:
pass
if proc.returncode is None:
proc.kill()
try:
await asyncio.shield(
asyncio.wait_for(proc.wait(), self._cancel_timeout))
except CancelledError:
pass
except ProcessLookupError:
pass
async def async_new_subprocess(self,
args: Union[str, Sequence[str]],
log: str,
env: Optional[Dict[str, str]] = None,
cwd: Optional[str] = None) -> Optional[int]:
"""A coroutine which starts a subprocess.
If this coroutine is cancelled, it will shut down the subprocess gracefully using
SIGTERM/SIGKILL, then raise CancelledError.
Parameters
----------
args : Union[str, Sequence[str]]
command to run, as string or sequence of strings.
log : str
the log file name.
env : Optional[Dict[str, str]]
an optional dictionary of environment variables. None to inherit from parent.
cwd : Optional[str]
the working directory. None to inherit from parent.
Returns
-------
retcode : Optional[int]
the return code of the subprocess.
"""
if isinstance(args, str):
args = [args]
# get log file name, make directory if necessary
log = os.path.abspath(log)
if os.path.isdir(log):
raise ValueError('log file %s is a directory.' % log)
os.makedirs(os.path.dirname(log), exist_ok=True)
async with self._semaphore:
proc = None
with open(log, 'w') as logf:
logf.write('command: %s\n' % (' '.join(args)))
logf.flush()
try:
proc = await asyncio.create_subprocess_exec(*args, stdout=logf,
stderr=subprocess.STDOUT,
env=env, cwd=cwd)
retcode = await proc.wait()
return retcode
except CancelledError as err:
await self._kill_subprocess(proc)
raise err
async def async_new_subprocess_flow(self,
proc_info_list: Sequence[FlowInfo]) -> Any:
"""A coroutine which runs a series of subprocesses.
If this coroutine is cancelled, it will shut down the current subprocess gracefully using
SIGTERM/SIGKILL, then raise CancelledError.
Parameters
----------
proc_info_list : Sequence[FlowInfo]
a list of processes to execute in series. Each element is a tuple of:
args : Union[str, Sequence[str]]
command to run, as string or list of string arguments.
log : str
log file name.
env : Optional[Dict[str, str]]
environment variable dictionary. None to inherit from parent.
cwd : Optional[str]
working directory path. None to inherit from parent.
vfun : Sequence[Callable[[Optional[int], str], Any]]
a function to validate if it is ok to execute the next process. The output of the
last function is returned. The first argument is the return code, the second
argument is the log file name.
Returns
-------
result : Any
the return value of the last validate function. None if validate function
returns False.
"""
num_proc = len(proc_info_list)
if num_proc == 0:
return None
async with self._semaphore:
for idx, (args, log, env, cwd, vfun) in enumerate(proc_info_list):
if isinstance(args, str):
args = [args]
# get log file name, make directory if necessary
log = os.path.abspath(log)
if os.path.isdir(log):
raise ValueError('log file %s is a directory.' % log)
os.makedirs(os.path.dirname(log), exist_ok=True)
proc, retcode = None, None
with open(log, 'w') as logf:
logf.write('command: %s\n' % (' '.join(args)))
logf.flush()
try:
proc = await asyncio.create_subprocess_exec(*args, stdout=logf,
stderr=subprocess.STDOUT,
env=env, cwd=cwd)
retcode = await proc.wait()
except CancelledError as err:
await self._kill_subprocess(proc)
raise err
fun_output = vfun(retcode, log)
if idx == num_proc - 1:
return fun_output
elif not fun_output:
return None
def batch_subprocess(self, proc_info_list):
# type: (Sequence[ProcInfo]) -> Optional[Sequence[Union[int, Exception]]]
"""Run all given subprocesses in parallel.
Parameters
----------
proc_info_list : Sequence[ProcInfo]
a list of process information. Each element is a tuple of:
args : Union[str, Sequence[str]]
command to run, as string or list of string arguments.
log : str
log file name.
env : Optional[Dict[str, str]]
environment variable dictionary. None to inherit from parent.
cwd : Optional[str]
working directory path. None to inherit from parent.
Returns
-------
results : Optional[Sequence[Union[int, Exception]]]
if user cancelled the subprocesses, None is returned. Otherwise, a list of
subprocess return codes or exceptions are returned.
"""
num_proc = len(proc_info_list)
if num_proc == 0:
return []
coro_list = [self.async_new_subprocess(args, log, env, cwd) for args, log, env, cwd in
proc_info_list]
return batch_async_task(coro_list)
def batch_subprocess_flow(self, proc_info_list):
# type: (Sequence[Sequence[FlowInfo]]) -> Optional[Sequence[Union[int, Exception]]]
"""Run all given subprocesses flow in parallel.
Parameters
----------
proc_info_list : Sequence[Sequence[FlowInfo]
a list of process flow information. Each element is a sequence of tuples of:
args : Union[str, Sequence[str]]
command to run, as string or list of string arguments.
log : str
log file name.
env : Optional[Dict[str, str]]
environment variable dictionary. None to inherit from parent.
cwd : Optional[str]
working directory path. None to inherit from parent.
vfun : Sequence[Callable[[Optional[int], str], Any]]
a function to validate if it is ok to execute the next process. The output of the
last function is returned. The first argument is the return code, the second
argument is the log file name.
Returns
-------
results : Optional[Sequence[Any]]
if user cancelled the subprocess flows, None is returned. Otherwise, a list of
flow return values or exceptions are returned.
"""
num_proc = len(proc_info_list)
if num_proc == 0:
return []
coro_list = [self.async_new_subprocess_flow(flow_info) for flow_info in proc_info_list]
return batch_async_task(coro_list)
================================================
FILE: bag/core.py
================================================
# -*- coding: utf-8 -*-
"""This is the core bag module.
"""
from typing import TYPE_CHECKING, Dict, Any, Tuple, Optional, Union, Type, Sequence, TypeVar
import os
import importlib
import cProfile
import pstats
from pathlib import Path
# noinspection PyPackageRequirements
from .interface import ZMQDealer
from .interface.database import DbAccess
from .design import ModuleDB, SchInstance
from .layout.routing import RoutingGrid
from .layout.template import TemplateDB
from .layout.core import DummyTechInfo
from .io import read_file, sim_data, read_yaml_env
from .concurrent.core import batch_async_task
if TYPE_CHECKING:
from .interface.simulator import SimAccess
from .layout.template import TemplateBase
from .layout.core import TechInfo
from .design.module import Module
from .simulation.core_v2 import TestbenchManager, MeasurementManager
ModuleType = TypeVar('ModuleType', bound=Module)
TemplateType = TypeVar('TemplateType', bound=TemplateBase)
def _get_config_file_abspath(fname):
"""Get absolute path of configuration file using BAG_WORK_DIR environment variable."""
fname = os.path.basename(fname)
if 'BAG_WORK_DIR' not in os.environ:
raise ValueError('Environment variable BAG_WORK_DIR not defined')
work_dir = os.environ['BAG_WORK_DIR']
if not os.path.isdir(work_dir):
raise ValueError('$BAG_WORK_DIR = %s is not a directory' % work_dir)
# read port number
fname = os.path.join(work_dir, fname)
if not os.path.isfile(fname):
raise ValueError('Cannot find file: %s' % fname)
return fname
def _get_port_number(port_file):
# type: (str) -> Tuple[Optional[int], str]
"""Read the port number from the given port file.
Parameters
----------
port_file : str
a file containing the communication port number.
Returns
-------
port : Optional[int]
the port number if reading is successful.
msg : str
Empty string on success, the error message on failure.
"""
try:
port_file = _get_config_file_abspath(port_file)
except ValueError as err:
return None, str(err)
port = int(read_file(port_file))
return port, ''
def _import_class_from_str(class_str):
# type: (str) -> Type
"""Given a Python class string, convert it to the Python class.
Parameters
----------
class_str : str
a Python class string/
Returns
-------
py_class : class
a Python class.
"""
sections = class_str.split('.')
module_str = '.'.join(sections[:-1])
class_str = sections[-1]
modul = importlib.import_module(module_str)
return getattr(modul, class_str)
class Testbench(object):
"""A class that represents a testbench instance.
Parameters
----------
sim : :class:`bag.interface.simulator.SimAccess`
The SimAccess instance used to issue simulation commands.
db : :class:`bag.interface.database.DbAccess`
The DbAccess instance used to update testbench schematic.
lib : str
testbench library.
cell : str
testbench cell.
parameters : Dict[str, str]
the simulation parameter dictionary. The values are string representation
of actual parameter values.
env_list : Sequence[str]
list of defined simulation environments.
default_envs : Sequence[str]
the selected simulation environments.
outputs : Dict[str, str]
default output expressions
Attributes
----------
lib : str
testbench library.
cell : str
testbench cell.
save_dir : str
directory containing the last simulation data.
"""
def __init__(self, # type: Testbench
sim, # type: SimAccess
db, # type: DbAccess
lib, # type: str
cell, # type: str
parameters, # type: Dict[str, str]
env_list, # type: Sequence[str]
default_envs, # type: Sequence[str]
outputs, # type: Dict[str, str]
):
# type: (...) -> None
"""Create a new testbench instance.
"""
self.sim = sim
self.db = db
self.lib = lib
self.cell = cell
self.parameters = parameters
self.env_parameters = {}
self.env_list = env_list
self.sim_envs = default_envs
self.config_rules = {}
self.outputs = outputs
self.save_dir = None
def get_defined_simulation_environments(self):
# type: () -> Sequence[str]
"""Return a list of defined simulation environments"""
return self.env_list
def get_current_simulation_environments(self):
# type: () -> Sequence[str]
"""Returns a list of simulation environments this testbench will simulate."""
return self.sim_envs
def add_output(self, var, expr):
# type: (str, str) -> None
"""Add an output expression to be recorded and exported back to python.
Parameters
----------
var : str
output variable name.
expr : str
the output expression.
"""
if var in sim_data.illegal_var_name:
raise ValueError('Variable name %s is illegal.' % var)
self.outputs[var] = expr
def set_parameter(self, name, val, precision=6):
# type: (str, Union[int, float], int) -> None
"""Sets the value of the given simulation parameter.
Parameters
----------
name : str
parameter name.
val : Union[int, float]
parameter value
precision : int
the parameter value will be rounded to this precision.
"""
param_config = dict(type='single', value=val)
if isinstance(val, str):
self.parameters[name] = val
else:
self.parameters[name] = self.sim.format_parameter_value(param_config, precision)
def set_env_parameter(self, name, val_list, precision=6):
# type: (str, Sequence[float], int) -> None
"""Configure the given parameter to have different value across simulation environments.
Parameters
----------
name : str
the parameter name.
val_list : Sequence[float]
the parameter values for each simulation environment. the order of the simulation
environments can be found in self.sim_envs
precision : int
the parameter value will be rounded to this precision.
"""
if len(self.sim_envs) != len(val_list):
raise ValueError('env parameter must have %d values.' % len(self.sim_envs))
default_val = None
for env, val in zip(self.sim_envs, val_list):
if env not in self.env_parameters:
cur_dict = {}
self.env_parameters[env] = cur_dict
else:
cur_dict = self.env_parameters[env]
param_config = dict(type='single', value=val)
cur_val = self.sim.format_parameter_value(param_config, precision)
if default_val is None:
default_val = cur_val
cur_dict[name] = self.sim.format_parameter_value(param_config, precision)
self.parameters[name] = default_val
def set_sweep_parameter(self, name, precision=6, **kwargs):
# type: (str, int, **Any) -> None
"""Set to sweep the given parameter.
To set the sweep values directly:
tb.set_sweep_parameter('var', values=[1.0, 5.0, 10.0])
To set a linear sweep with start/stop/step (inclusive start and stop):
tb.set_sweep_parameter('var', start=1.0, stop=9.0, step=4.0)
To set a logarithmic sweep with points per decade (inclusive start and stop):
tb.set_sweep_parameter('var', start=1.0, stop=10.0, num_decade=3)
Parameters
----------
name : str
parameter name.
precision : int
the parameter value will be rounded to this precision.
**kwargs : Any
the sweep parameters. Refer to the above for example calls.
"""
if 'values' in kwargs:
param_config = dict(type='list', values=kwargs['values'])
elif 'start' in kwargs and 'stop' in kwargs:
start = kwargs['start']
stop = kwargs['stop']
if 'step' in kwargs:
step = kwargs['step']
param_config = dict(type='linstep', start=start, stop=stop, step=step)
elif 'num_decade' in kwargs:
num = kwargs['num_decade']
param_config = dict(type='decade', start=start, stop=stop, num=num)
else:
raise Exception('Unsupported sweep arguments: %s' % kwargs)
else:
raise Exception('Unsupported sweep arguments: %s' % kwargs)
self.parameters[name] = self.sim.format_parameter_value(param_config, precision)
def set_simulation_environments(self, env_list):
# type: (Sequence[str]) -> None
"""Enable the given list of simulation environments.
If more than one simulation environment is specified, then a sweep
will be performed.
Parameters
----------
env_list : Sequence[str]
"""
self.sim_envs = env_list
def set_simulation_view(self, lib_name, cell_name, sim_view):
# type: (str, str, str) -> None
"""Set the simulation view of the given design.
For simulation, each design may have multiple views, such as schematic,
veriloga, extracted, etc. This method lets you choose which view to
use for netlisting. the given design can be the top level design or
an intermediate instance.
Parameters
----------
lib_name : str
design library name.
cell_name : str
design cell name.
sim_view : str
the view to simulate with.
"""
key = '%s__%s' % (lib_name, cell_name)
self.config_rules[key] = sim_view
def update_testbench(self):
# type: () -> None
"""Commit the testbench changes to the CAD database.
"""
config_list = []
for key, view in self.config_rules.items():
lib, cell = key.split('__')
config_list.append([lib, cell, view])
env_params = []
for env in self.sim_envs:
if env in self.env_parameters:
val_table = self.env_parameters[env]
env_params.append(list(val_table.items()))
self.db.update_testbench(self.lib, self.cell, self.parameters, self.sim_envs, config_list,
env_params)
def run_simulation(self, precision=6, sim_tag=None):
# type: (int, Optional[str]) -> Optional[str]
"""Run simulation.
Parameters
----------
precision : int
the floating point number precision.
sim_tag : Optional[str]
optional description for this simulation run.
Returns
-------
value : Optional[str]
the save directory path. If simulation is cancelled, return None.
"""
coro = self.async_run_simulation(precision=precision, sim_tag=sim_tag)
batch_async_task([coro])
return self.save_dir
def load_sim_results(self, hist_name, precision=6):
# type: (str, int) -> Optional[str]
"""Load previous simulation data.
Parameters
----------
hist_name : str
the simulation history name.
precision : int
the floating point number precision.
Returns
-------
value : Optional[str]
the save directory path. If result loading is cancelled, return None.
"""
coro = self.async_load_results(hist_name, precision=precision)
batch_async_task([coro])
return self.save_dir
async def async_run_simulation(self,
precision: int = 6,
sim_tag: Optional[str] = None) -> str:
"""A coroutine that runs the simulation.
Parameters
----------
precision : int
the floating point number precision.
sim_tag : Optional[str]
optional description for this simulation run.
Returns
-------
value : str
the save directory path.
"""
self.save_dir = None
self.save_dir = await self.sim.async_run_simulation(self.lib, self.cell, self.outputs,
precision=precision, sim_tag=sim_tag)
return self.save_dir
async def async_load_results(self, hist_name: str, precision: int = 6) -> str:
"""A coroutine that loads previous simulation data.
Parameters
----------
hist_name : str
the simulation history name.
precision : int
the floating point number precision.
Returns
-------
value : str
the save directory path.
"""
self.save_dir = None
self.save_dir = await self.sim.async_load_results(self.lib, self.cell, hist_name,
self.outputs, precision=precision)
return self.save_dir
def create_tech_info(bag_config_path=None):
# type: (Optional[str]) -> TechInfo
"""Create TechInfo object."""
if bag_config_path is None:
if 'BAG_CONFIG_PATH' not in os.environ:
raise Exception('BAG_CONFIG_PATH not defined.')
bag_config_path = os.environ['BAG_CONFIG_PATH']
bag_config = read_yaml_env(bag_config_path)
tech_params = read_yaml_env(bag_config['tech_config_path'])
if 'class' in tech_params:
tech_cls = _import_class_from_str(tech_params['class'])
tech_info = tech_cls(tech_params)
else:
# just make a default tech_info object as place holder.
print('*WARNING*: No TechInfo class defined. Using a dummy version.')
tech_info = DummyTechInfo(tech_params)
return tech_info
class BagProject(object):
"""The main bag controller class.
This class mainly stores all the user configurations, and issue
high level bag commands.
Parameters
----------
bag_config_path : Optional[str]
the bag configuration file path. If None, will attempt to read from
environment variable BAG_CONFIG_PATH.
port : Optional[int]
the BAG server process port number. If not given, will read from port file.
Attributes
----------
bag_config : Dict[str, Any]
the BAG configuration parameters dictionary.
tech_info : bag.layout.core.TechInfo
the BAG process technology class.
"""
def __init__(self, bag_config_path=None, port=None):
# type: (Optional[str], Optional[int]) -> None
if bag_config_path is None:
if 'BAG_CONFIG_PATH' not in os.environ:
raise Exception('BAG_CONFIG_PATH not defined.')
bag_config_path = os.environ['BAG_CONFIG_PATH']
self.bag_config = read_yaml_env(bag_config_path)
bag_tmp_dir = os.environ.get('BAG_TEMP_DIR', None)
# get port files
if port is None:
socket_config = self.bag_config['socket']
if 'port_file' in socket_config:
port, msg = _get_port_number(socket_config['port_file'])
if msg:
print('*WARNING* %s' % msg)
# create ZMQDealer object
dealer_kwargs = {}
dealer_kwargs.update(self.bag_config['socket'])
del dealer_kwargs['port_file']
# create TechInfo instance
self.tech_info = create_tech_info(bag_config_path=bag_config_path)
# create design module database.
try:
lib_defs_file = _get_config_file_abspath(self.bag_config['lib_defs'])
except ValueError:
lib_defs_file = ''
sch_exc_libs = self.bag_config['database']['schematic']['exclude_libraries']
self.dsn_db = ModuleDB(lib_defs_file, self.tech_info, sch_exc_libs, prj=self)
if port is not None:
# make DbAccess instance.
dealer = ZMQDealer(port, **dealer_kwargs)
db_cls = _import_class_from_str(self.bag_config['database']['class'])
self.impl_db = db_cls(dealer, bag_tmp_dir, self.bag_config['database'])
self._default_lib_path = self.impl_db.default_lib_path
else:
self.impl_db = None # type: Optional[DbAccess]
self._default_lib_path = DbAccess.get_default_lib_path(self.bag_config['database'])
# make SimAccess instance.
sim_cls = _import_class_from_str(self.bag_config['simulation']['class'])
self.sim = sim_cls(bag_tmp_dir, self.bag_config['simulation']) # type: SimAccess
@property
def default_lib_path(self):
# type: () -> str
return self._default_lib_path
def close_bag_server(self):
# type: () -> None
"""Close the BAG database server."""
if self.impl_db is not None:
self.impl_db.close()
self.impl_db = None
def close_sim_server(self):
# type: () -> None
"""Close the BAG simulation server."""
if self.sim is not None:
self.sim.close()
self.sim = None
def import_design_library(self, lib_name):
# type: (str) -> None
"""Import all design templates in the given library from CAD database.
Parameters
----------
lib_name : str
name of the library.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
new_lib_path = self.bag_config['new_lib_path']
self.impl_db.import_design_library(lib_name, self.dsn_db, new_lib_path)
def import_sch_cellview(self, lib_name: str, cell_name: str) -> None:
"""Import the given schematic and symbol template into Python.
This import process is done recursively.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell name.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
new_lib_path = self.bag_config['new_lib_path']
self.impl_db.import_sch_cellview(lib_name, cell_name, self.dsn_db, new_lib_path)
def get_cells_in_library(self, lib_name):
# type: (str) -> Sequence[str]
"""Get a list of cells in the given library.
Returns an empty list if the given library does not exist.
Parameters
----------
lib_name : str
the library name.
Returns
-------
cell_list : Sequence[str]
a list of cells in the library
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
return self.impl_db.get_cells_in_library(lib_name)
def make_template_db(self, impl_lib, grid_specs, use_cybagoa=True, gds_lay_file='',
cache_dir=''):
# type: (str, Dict[str, Any], bool, str, str) -> TemplateDB
"""Create and return a new TemplateDB instance.
Parameters
----------
impl_lib : str
the library name to put generated layouts in.
grid_specs : Dict[str, Any]
the routing grid specification dictionary.
use_cybagoa : bool
True to enable cybagoa acceleration if available.
gds_lay_file : str
the GDS layout information file.
cache_dir : str
the cache directory name.
"""
layers = grid_specs['layers']
widths = grid_specs['widths']
spaces = grid_specs['spaces']
bot_dir = grid_specs['bot_dir']
width_override = grid_specs.get('width_override', None)
routing_grid = RoutingGrid(self.tech_info, layers, spaces, widths, bot_dir,
width_override=width_override)
tdb = TemplateDB('template_libs.def', routing_grid, impl_lib, use_cybagoa=use_cybagoa,
gds_lay_file=gds_lay_file, cache_dir=cache_dir, prj=self)
return tdb
def generate_cell(self, # type: BagProject
specs, # type: Dict[str, Any]
temp_cls=None, # type: Optional[Type[TemplateType]]
gen_lay=True, # type: bool
gen_sch=False, # type: bool
run_lvs=False, # type: bool
run_rcx=False, # type: bool
use_cybagoa=True, # type: bool
debug=False, # type: bool
profile_fname='', # type: str
use_cache=False, # type: bool
save_cache=False, # type: bool
**kwargs,
):
# type: (...) -> Optional[Union[pstats.Stats, Dict[str, Any]]]
"""Generate layout/schematic of a given cell from specification file.
Parameters
----------
specs : Dict[str, Any]
the specification dictionary.
temp_cls : Optional[Type[TemplateType]]
the TemplateBase subclass to instantiate
if not provided, it will be imported from lay_class entry in specs dictionary.
gen_lay : bool
True to generate layout.
gen_sch : bool
True to generate schematics.
run_lvs : bool
True to run LVS.
run_rcx : bool
True to run RCX.
use_cybagoa : bool
True to enable cybagoa acceleration if available.
debug : bool
True to print debug messages.
profile_fname : str
If not empty, profile layout generation, and save statistics to this file.
use_cache : bool
True to use cached layouts.
save_cache : bool
True to save instances in this template to cache.
**kwargs :
Additional optional arguments.
Returns
-------
result: Optional[Union[pstats.Stats, Dict[str, Any]]]
If profiling is enabled, result will be the statistics object.
If the last thing done is layout or schematic, result will contain sch_params
If the last thing done is lvs, in case of failure result will
contain lvs log file in a dictionary, otherwise None
If the last thing done is rcx, in case of failure result will
contain rcx log file in a dictionary, otherwise None
"""
prefix = kwargs.get('prefix', '')
suffix = kwargs.get('suffix', '')
grid_specs = specs['routing_grid']
impl_lib = specs['impl_lib']
impl_cell = specs['impl_cell']
lay_str = specs.get('lay_class', '')
sch_lib = specs.get('sch_lib', '')
sch_cell = specs.get('sch_cell', '')
params = specs['params']
gds_lay_file = specs.get('gds_lay_file', '')
cache_dir = specs.get('cache_dir', '')
if temp_cls is None and lay_str:
temp_cls = _import_class_from_str(lay_str)
has_lay = temp_cls is not None
if gen_lay and not has_lay:
raise ValueError('layout_class is not specified')
if use_cache:
db_cache_dir = specs.get('cache_dir', '')
else:
db_cache_dir = ''
result_pstat = None
if has_lay:
temp_db = self.make_template_db(impl_lib, grid_specs, use_cybagoa=use_cybagoa,
gds_lay_file=gds_lay_file, cache_dir=db_cache_dir)
name_list = [impl_cell]
print('computing layout...')
if profile_fname:
profiler = cProfile.Profile()
profiler.runcall(temp_db.new_template, params=params, temp_cls=temp_cls,
debug=False)
profiler.dump_stats(profile_fname)
result_pstat = pstats.Stats(profile_fname).strip_dirs()
temp = temp_db.new_template(params=params, temp_cls=temp_cls, debug=debug)
print('computation done.')
temp_list = [temp]
if save_cache and cache_dir:
master_list = [inst.master for inst in temp.instance_iter()]
print('saving layouts to cache...')
temp_db.save_to_cache(master_list, cache_dir, debug=debug)
print('saving done.')
if gen_lay:
print('creating layout...')
temp_db.batch_layout(self, temp_list, name_list, debug=debug)
print('layout done.')
sch_params = temp.sch_params
else:
sch_params = params
if gen_sch:
dsn = self.create_design_module(lib_name=sch_lib, cell_name=sch_cell)
print('computing schematic...')
dsn.design(**sch_params)
print('creating schematic...')
dsn.implement_design(impl_lib, top_cell_name=impl_cell, prefix=prefix,
suffix=suffix)
print('schematic done.')
result = sch_params
lvs_passed = False
if run_lvs:
print('running lvs...')
lvs_passed, lvs_log = self.run_lvs(impl_lib, impl_cell, gds_lay_file=gds_lay_file)
if lvs_passed:
print('LVS passed!')
result = dict(log='')
else:
raise ValueError(f'LVS failed, lvs_log: {lvs_log}')
if run_rcx and ((run_lvs and lvs_passed) or not run_lvs):
print('running rcx...')
rcx_passed, rcx_log = self.run_rcx(impl_lib, impl_cell)
if rcx_passed:
print('RCX passed!')
result = dict(log='')
else:
raise ValueError(f'RCX failed, rcx_log: {rcx_log}')
if result_pstat:
return result_pstat
return result
def replace_dut_in_wrapper(self, params: Dict[str, Any], dut_lib: str,
dut_cell: str) -> None:
# helper function that replaces dut_lib and dut_cell in the wrapper recursively base on
# dut_params
dut_params = params.get('dut_params', None)
if dut_params is None:
params['dut_lib'] = dut_lib
params['dut_cell'] = dut_cell
return
return self.replace_dut_in_wrapper(dut_params, dut_lib, dut_cell)
def simulate_cell(self,
specs: Dict[str, Any],
gen_cell: bool = True,
gen_wrapper: bool = True,
gen_tb: bool = True,
load_results: bool = False,
extract: bool = False,
run_sim: bool = True) -> Optional[Dict[str, Any]]:
"""
Runs a minimum executable parts of the Testbench Manager flow selectively according to
a spec dictionary.
For example you can set the flags to generate a new cell, but since wrapper and test bench
exist, maybe you want to skip those, and run the simulation in the end. Maybe you
already created the cell all the way up to test bench level, and now you only need to
run simulation.
This function only works with Testbench Managers written in format of
simulation.core_v2.TestbenchManager
Parameters
----------
specs:
Dictionary of specifications
Some non-obvious conventions:
- if contains tbm_specs keyword, simulation is ran through testbench manager v2,
otherwise there should be a sim_params entry that specifies the simulation.
- Wrapper is assumed to be in the specs dictionary, if it is generated outside of
this function, gen_wrapper should be False.
gen_cell:
True to call generate_cell on specs
gen_wrapper:
True to generate Wrapper. Currently only one top-level wrapper is supported.
gen_tb:
True to generate test bench. If test bench is created, this flag can be set to False.
load_results:
True to skip simulation and load the results.
extract:
False to skip layout generation and only simulate schematic
run_sim:
True to run simulation. If the purpose of calling this function is just to generate
some part of simulation flow to debug, this flag can be set to False.
Returns
-------
results: Optional[Dict[str, Any]]
if run_sim/load_results = True, contains simulations results, otherwise it's None.
"""
impl_lib = specs['impl_lib']
impl_cell = specs['impl_cell']
root_dir = Path(specs['root_dir'])
if gen_cell and not load_results:
print('generating cell ...')
self.generate_cell(specs,
gen_lay=extract,
gen_sch=True,
run_lvs=extract,
run_rcx=extract,
use_cybagoa=True)
print('cell generated.')
# if testbench manager v2 found use that instead of interpreting simulation directly
tbm_specs = specs.get('tbm_specs', None)
if tbm_specs:
tbm_cls_str = tbm_specs['tbm_cls']
tbm_cls = _import_class_from_str(tbm_cls_str)
tbm: TestbenchManager = tbm_cls(root_dir)
sim_view_list = tbm_specs.get('sim_view_list', [])
if not sim_view_list:
view_name = 'netlist' if extract else 'schematic'
sim_view_list.append((impl_cell, view_name))
sim_envs = tbm_specs['sim_envs']
if load_results:
return tbm.load_results(impl_cell, tbm_specs)
results = tbm.simulate(bprj=self,
impl_lib=impl_lib,
impl_cell=impl_cell,
sim_view_list=sim_view_list,
env_list=sim_envs,
tb_dict=tbm_specs,
wrapper_dict=None,
gen_tb=gen_tb,
gen_wrapper=gen_wrapper,
run_sim=run_sim)
return results
sim_params = specs.get('sim_params', None)
wrapper = sim_params.get('wrapper', None)
has_wrapper = wrapper is not None
if gen_wrapper and not has_wrapper:
raise ValueError('must provide a wrapper in sim_params')
wrapper_lib = wrapper_cell = wrapped_cell = wrapper_params = None
if has_wrapper:
wrapper_lib = wrapper['wrapper_lib']
wrapper_cell = wrapper['wrapper_cell']
wrapper_params = wrapper.get('params', {})
wrapper_suffix = wrapper.get('wrapper_suffix', '')
if not wrapper_suffix:
wrapper_suffix = f'{wrapper_cell}'
wrapped_cell = f'{impl_cell}_{wrapper_suffix}'
if gen_wrapper and not gen_tb:
raise ValueError('generated a new wrapper, therefore gen_tb should also be true')
tb_lib = sim_params['tb_lib']
tb_cell = sim_params['tb_cell']
tb_params = sim_params.get('tb_params', {})
tb_suffix = sim_params.get('tb_suffix', '')
if not tb_suffix:
tb_suffix = f'{tb_cell}'
tb_name = f'{impl_cell}_{tb_suffix}'
tb_fname = root_dir / Path(tb_name, f'{tb_name}.hdf5')
if load_results:
print("loading results ...")
if tb_fname.exists():
return sim_data.load_sim_file(tb_fname)
raise ValueError(f'simulation results does not exist in {str(tb_fname)}')
if gen_wrapper and has_wrapper:
print('generating wrapper ...')
master = self.create_design_module(lib_name=wrapper_lib, cell_name=wrapper_cell)
self.replace_dut_in_wrapper(wrapper_params, impl_lib, impl_cell)
master.design(**wrapper_params)
master.implement_design(impl_lib, wrapped_cell)
print('wrapper generated.')
if gen_tb:
print('generating testbench ...')
tb_master = self.create_design_module(tb_lib, tb_cell)
dut_cell = wrapped_cell if has_wrapper else impl_cell
tb_master.design(dut_lib=impl_lib, dut_cell=dut_cell, **tb_params)
tb_master.implement_design(impl_lib, tb_name)
print('testbench generated.')
if run_sim:
print('setting up ADEXL ...')
sim_view_list = sim_params.get('sim_view_list', [])
if not sim_view_list:
view_name = 'netlist' if extract else 'schematic'
sim_view_list.append((impl_cell, view_name))
sim_envs = sim_params['sim_envs']
sim_swp_params = sim_params.get('sim_swp_params', {})
sim_vars = sim_params.get('sim_vars', {})
sim_outputs = sim_params.get('sim_outputs', {})
tb = self.configure_testbench(impl_lib, tb_name)
# set simulation variables
for key, val in sim_vars.items():
tb.set_parameter(key, val)
# set sweep parameters
for key, val in sim_swp_params.items():
tb.set_sweep_parameter(key, **val)
# set the simulation outputs
for key, val in sim_outputs.items():
tb.add_output(key, val)
# change the view_name (netlist or schematic)
for cell, view in sim_view_list:
tb.set_simulation_view(impl_lib, cell, view)
tb.set_simulation_environments(sim_envs)
tb.update_testbench()
print('setup completed.')
print('running simulation ...')
tb.run_simulation()
print('simulation done.')
print('loading results ...')
results = sim_data.load_sim_results(tb.save_dir)
if not results.get('sweep_params', {}):
raise ValueError(f'results are empty, either you forgot to specify outputs, or '
f'simulation failed. check sim_log: {tb.save_dir}/ocn_output.log')
print('results loaded.')
print('saving results into hdf5')
sim_data.save_sim_results(results, tb_fname)
print('results saved.')
return results
def measure_cell(self,
specs: Dict[str, Any],
gen_cell: bool = True,
gen_wrapper: bool = True,
gen_tb: bool = True,
load_results: bool = False,
extract: bool = False,
run_sims: bool = True) -> Optional[Dict[str, Any]]:
"""
Runs a minimum executable parts of the Measurement Manager flow selectively according to
a spec dictionary.
For example you can set the flags to generate a new cell, but since wrapper and test bench
exist, maybe you want to skip those, and run the measurement in the end. Maybe you
already created the cell all the way up to test bench level, and now you only need to
run simulation.
This function only works with Measurement Managers written in format of
simulation.core_v2.MeasurementManager
Parameters
----------
specs:
Dictionary of specifications
Some non-obvious conventions:
- if contains tbm_specs keyword, simulation is ran through testbench manager v2,
otherwise there should be a sim_params entry that specifies the simulation.
- Wrapper is assumed to be in the specs dictionary, if it is generated outside of
this function, gen_wrapper should be False.
gen_cell:
True to call generate_cell on specs
gen_wrapper:
True to generate Wrapper. Currently only one top-level wrapper is supported.
gen_tb:
True to generate test bench. If test bench is created, this flag can be set to False.
load_results:
True to skip simulation and load the results.
extract:
False to skip layout generation and only simulate schematic
run_sims:
True to run simulations. If the purpose of calling this function is just to generate
some part of simulation flow to debug, this flag can be set to False.
Returns
-------
results: Optional[Dict[str, Any]]
if run_sim/load_results = True, contains measurement results, otherwise it's None.
"""
impl_lib = specs['impl_lib']
impl_cell = specs['impl_cell']
root_dir = Path(specs['root_dir'])
if gen_cell and not load_results:
print('generating cell ...')
self.generate_cell(specs,
gen_lay=extract,
gen_sch=True,
run_lvs=extract,
run_rcx=extract,
use_cybagoa=True)
print('cell generated.')
mm_specs = specs['mm_specs']
mm_cls_str = mm_specs['mm_cls']
mm_cls = _import_class_from_str(mm_cls_str)
mm: MeasurementManager = mm_cls(root_dir, mm_specs)
return mm.measure(self, impl_lib, impl_cell, load_results=load_results,
gen_wrapper=gen_wrapper, gen_tb=gen_tb, run_sims=run_sims,
extract=extract)
def create_library(self, lib_name, lib_path=''):
# type: (str, str) -> None
"""Create a new library if one does not exist yet.
Parameters
----------
lib_name : str
the library name.
lib_path : str
directory to create the library in. If Empty, use default location.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
return self.impl_db.create_library(lib_name, lib_path=lib_path)
# noinspection PyUnusedLocal
def create_design_module(self, lib_name, cell_name, **kwargs):
# type: (str, str, **Any) -> SchInstance
"""Create a new top level design module for the given schematic template
Parameters
----------
lib_name : str
the library name.
cell_name : str
the cell name.
**kwargs : Any
optional parameters.
Returns
-------
dsn : SchInstance
a configurable schematic instance of the given schematic generator.
"""
return SchInstance(self.dsn_db, lib_name, cell_name, 'XTOP', static=False)
def new_schematic_instance(self, lib_name='', cell_name='', params=None, sch_cls=None,
debug=False, **kwargs):
# type: (str, str, Dict[str, Any], Type[ModuleType], bool, **Any) -> SchInstance
"""Create a new schematic instance
This method is the schematic equivalent of TemplateDB's new_template() method.
By default, we assume the design() function is used to set the schematic parameters.
If you use another function (such as design_specs()), then you should specify
an optional parameter design_fun equal to the name of that function.
Parameters
----------
lib_name : str
schematic library name.
cell_name : str
schematic name
params : Dict[str, Any]
the parameter dictionary.
sch_cls : Type[TemplateType]
the schematic generator class to instantiate.
debug : bool
True to print debug messages.
**kwargs : Any
optional parameters.
Returns
-------
dsn : SchInstance
a schematic instance of the given schematic generator.
"""
design_fun = kwargs.get('design_fun', 'design')
master = self.dsn_db.new_master(lib_name, cell_name, gen_cls=sch_cls, params=params,
debug=debug, design_args=None, design_fun=design_fun)
return SchInstance(self.dsn_db, lib_name, cell_name, 'XTOP', static=False,
master=master)
def clear_schematic_database(self):
# type: () -> None
"""Reset schematic database."""
self.dsn_db.clear()
def instantiate_schematic(self, lib_name, content_list, lib_path=''):
# type: (str, Sequence[Any], str) -> None
"""Create the given schematic contents in CAD database.
NOTE: this is BAG's internal method. TO create schematics, call batch_schematic() instead.
Parameters
----------
lib_name : str
name of the new library to put the schematic instances.
content_list : Sequence[Any]
list of schematics to create.
lib_path : str
the path to create the library in. If empty, use default location.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
self.impl_db.instantiate_schematic(lib_name, content_list, lib_path=lib_path)
def batch_schematic(self, # type: BagProject
lib_name, # type: str
sch_inst_list, # type: Sequence[SchInstance]
name_list=None, # type: Optional[Sequence[Optional[str]]]
prefix='', # type: str
suffix='', # type: str
debug=False, # type: bool
rename_dict=None, # type: Optional[Dict[str, str]]
):
# type: (...) -> None
"""create all the given schematics in CAD database.
Parameters
----------
lib_name : str
name of the new library to put the schematic instances.
sch_inst_list : Sequence[SchInstance]
list of SchInstance objects.
name_list : Optional[Sequence[Optional[str]]]
list of master cell names. If not given, default names will be used.
prefix : str
prefix to add to cell names.
suffix : str
suffix to add to cell names.
debug : bool
True to print debugging messages
rename_dict : Optional[Dict[str, str]]
optional master cell renaming dictionary.
"""
master_list = [inst.master for inst in sch_inst_list]
self.dsn_db.cell_prefix = prefix
self.dsn_db.cell_suffix = suffix
self.dsn_db.instantiate_masters(master_list, name_list=name_list, lib_name=lib_name,
debug=debug, rename_dict=rename_dict)
def configure_testbench(self, tb_lib, tb_cell):
# type: (str, str) -> Testbench
"""Update testbench state for the given testbench.
This method fill in process-specific information for the given testbench, then returns
a testbench object which you can use to control simulation.
Parameters
----------
tb_lib : str
testbench library name.
tb_cell : str
testbench cell name.
Returns
-------
tb : :class:`bag.core.Testbench`
the :class:`~bag.core.Testbench` instance.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
if self.sim is None:
raise Exception('SimAccess is not set up.')
c, clist, params, outputs = self.impl_db.configure_testbench(tb_lib, tb_cell)
return Testbench(self.sim, self.impl_db, tb_lib, tb_cell, params, clist, [c], outputs)
def load_testbench(self, tb_lib, tb_cell):
# type: (str, str) -> Testbench
"""Loads a testbench from the database.
Parameters
----------
tb_lib : str
testbench library name.
tb_cell : str
testbench cell name.
Returns
-------
tb : :class:`bag.core.Testbench`
the :class:`~bag.core.Testbench` instance.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
if self.sim is None:
raise Exception('SimAccess is not set up.')
cur_envs, all_envs, params, outputs = self.impl_db.get_testbench_info(tb_lib, tb_cell)
return Testbench(self.sim, self.impl_db, tb_lib, tb_cell, params, all_envs,
cur_envs, outputs)
def instantiate_layout_pcell(self, lib_name, cell_name, inst_lib, inst_cell, params,
pin_mapping=None, view_name='layout'):
# type: (str, str, str, str, Dict[str, Any], Optional[Dict[str, str]], str) -> None
"""Create a layout cell with a single pcell instance.
Parameters
----------
lib_name : str
layout library name.
cell_name : str
layout cell name.
inst_lib : str
pcell library name.
inst_cell : str
pcell cell name.
params : Dict[str, Any]
the parameter dictionary.
pin_mapping: Optional[Dict[str, str]]
the pin renaming dictionary.
view_name : str
layout view name, default is "layout".
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
pin_mapping = pin_mapping or {}
self.impl_db.instantiate_layout_pcell(lib_name, cell_name, view_name,
inst_lib, inst_cell, params, pin_mapping)
def instantiate_layout(self, lib_name, view_name, via_tech, layout_list):
# type: (str, str, str, Sequence[Any]) -> None
"""Create a batch of layouts.
Parameters
----------
lib_name : str
layout library name.
view_name : str
layout view name.
via_tech : str
via technology name.
layout_list : Sequence[Any]
a list of layouts to create
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
self.impl_db.instantiate_layout(lib_name, view_name, via_tech, layout_list)
def release_write_locks(self, lib_name, cell_view_list):
# type: (str, Sequence[Tuple[str, str]]) -> None
"""Release write locks from all the given cells.
Parameters
----------
lib_name : str
the library name.
cell_view_list : Sequence[Tuple[str, str]]
list of cell/view name tuples.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
self.impl_db.release_write_locks(lib_name, cell_view_list)
def run_lvs(self, # type: BagProject
lib_name, # type: str
cell_name, # type: str
**kwargs
):
# type: (...) -> Tuple[bool, str]
"""Run LVS on the given cell.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell_name
**kwargs :
optional keyword arguments. See DbAccess class for details.
Returns
-------
value : bool
True if LVS succeeds
log_fname : str
name of the LVS log file.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
coro = self.impl_db.async_run_lvs(lib_name, cell_name, **kwargs)
results = batch_async_task([coro])
if results is None or isinstance(results[0], Exception):
return False, ''
return results[0]
def run_rcx(self, # type: BagProject
lib_name, # type: str
cell_name, # type: str
**kwargs
):
# type: (...) -> Tuple[Union[bool, Optional[str]], str]
"""Run RCX on the given cell.
The behavior and the first return value of this method depends on the
input arguments. The second return argument will always be the RCX
log file name.
If create_schematic is True, this method will run RCX, then if it succeeds,
create a schematic of the extracted netlist in the database. It then returns
a boolean value which will be True if RCX succeeds.
If create_schematic is False, this method will run RCX, then return a string
which is the extracted netlist filename. If RCX failed, None will be returned
instead.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell_name
override RCX parameter values.
**kwargs :
optional keyword arguments. See DbAccess class for details.
Returns
-------
value : Union[bool, str]
The return value, as described.
log_fname : str
name of the RCX log file.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
create_schematic = kwargs.get('create_schematic', True)
coro = self.impl_db.async_run_rcx(lib_name, cell_name, **kwargs)
results = batch_async_task([coro])
if results is None or isinstance(results[0], Exception):
if create_schematic:
return False, ''
else:
return None, ''
return results[0]
def export_layout(self, lib_name, cell_name, out_file, **kwargs):
# type: (str, str, str, **Any) -> str
"""export layout.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell name.
out_file : str
output file name.
**kwargs : Any
optional keyword arguments. See Checker class for details.
Returns
-------
log_fname : str
log file name. Empty if task cancelled.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
coro = self.impl_db.async_export_layout(lib_name, cell_name, out_file, **kwargs)
results = batch_async_task([coro])
if results is None or isinstance(results[0], Exception):
return ''
return results[0]
def batch_export_layout(self, info_list):
# type: (Sequence[Tuple[Any, ...]]) -> Optional[Sequence[str]]
"""Export layout of all given cells
Parameters
----------
info_list:
list of cell information. Each element is a tuple of:
lib_name : str
library name.
cell_name : str
cell name.
out_file : str
layout output file name.
view_name : str
layout view name. Optional.
params : Optional[Dict[str, Any]]
optional export parameter values.
Returns
-------
results : Optional[Sequence[str]]
If task is cancelled, return None. Otherwise, this is a
list of log file names.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
coro_list = [self.impl_db.async_export_layout(*info) for info in info_list]
temp_results = batch_async_task(coro_list)
if temp_results is None:
return None
return ['' if isinstance(val, Exception) else val for val in temp_results]
async def async_run_lvs(self, lib_name: str, cell_name: str, **kwargs: Any) -> Tuple[bool, str]:
"""A coroutine for running LVS.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell_name
**kwargs : Any
optional keyword arguments. See Checker class for details.
LVS parameters should be specified as lvs_params.
Returns
-------
value : bool
True if LVS succeeds
log_fname : str
name of the LVS log file.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
return await self.impl_db.async_run_lvs(lib_name, cell_name, **kwargs)
async def async_run_rcx(self, # type: BagProject
lib_name: str,
cell_name: str,
**kwargs
) -> Tuple[Union[bool, Optional[str]], str]:
"""Run RCX on the given cell.
The behavior and the first return value of this method depends on the
input arguments. The second return argument will always be the RCX
log file name.
If create_schematic is True, this method will run RCX, then if it succeeds,
create a schematic of the extracted netlist in the database. It then returns
a boolean value which will be True if RCX succeeds.
If create_schematic is False, this method will run RCX, then return a string
which is the extracted netlist filename. If RCX failed, None will be returned
instead.
Parameters
----------
lib_name : str
library name.
cell_name : str
cell_name
override RCX parameter values.
**kwargs :
optional keyword arguments. See DbAccess class for details.
Returns
-------
value : Union[bool, str]
The return value, as described.
log_fname : str
name of the RCX log file.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
return await self.impl_db.async_run_rcx(lib_name, cell_name, **kwargs)
def create_schematic_from_netlist(self, netlist, lib_name, cell_name,
sch_view=None, **kwargs):
# type: (str, str, str, Optional[str], **Any) -> None
"""Create a schematic from a netlist.
This is mainly used to create extracted schematic from an extracted netlist.
Parameters
----------
netlist : str
the netlist file name.
lib_name : str
library name.
cell_name : str
cell_name
sch_view : Optional[str]
schematic view name. The default value is implemendation dependent.
**kwargs : Any
additional implementation-dependent arguments.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
return self.impl_db.create_schematic_from_netlist(netlist, lib_name, cell_name,
sch_view=sch_view, **kwargs)
def create_verilog_view(self, verilog_file, lib_name, cell_name, **kwargs):
# type: (str, str, str, **Any) -> None
"""Create a verilog view for mix-signal simulation.
Parameters
----------
verilog_file : str
the verilog file name.
lib_name : str
library name.
cell_name : str
cell name.
**kwargs : Any
additional implementation-dependent arguments.
"""
if self.impl_db is None:
raise Exception('BAG Server is not set up.')
verilog_file = os.path.abspath(verilog_file)
if not os.path.isfile(verilog_file):
raise ValueError('%s is not a file.' % verilog_file)
return self.impl_db.create_verilog_view(verilog_file, lib_name, cell_name, **kwargs)
================================================
FILE: bag/data/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: bag/data/__init__.py
================================================
# -*- coding: utf-8 -*-
"""This package defines methods and classes useful for data post-processing.
"""
# compatibility import.
from ..io import load_sim_results, save_sim_results, load_sim_file
from .core import Waveform
__all__ = ['load_sim_results', 'save_sim_results', 'load_sim_file',
'Waveform', ]
================================================
FILE: bag/data/core.py
================================================
# -*- coding: utf-8 -*-
"""This module defines core data post-processing classes.
"""
import numpy as np
import scipy.interpolate as interp
import scipy.cluster.vq as svq
import scipy.optimize as sciopt
class Waveform(object):
"""A (usually transient) waveform.
This class provides interpolation and other convenience functions.
Parameters
----------
xvec : np.multiarray.ndarray
the X vector.
yvec : np.multiarray.ndarray
the Y vector.
xtol : float
the X value tolerance.
order : int
the interpolation order. 1 for nearest, 2 for linear, 3 for spline.
ext : int or str
interpolation extension mode. See documentation for InterpolatedUnivariateSpline.
"""
def __init__(self, xvec, yvec, xtol, order=3, ext=3):
self._xvec = xvec
self._yvec = yvec
self._xtol = xtol
self._order = order
self._ext = ext
self._fun = interp.InterpolatedUnivariateSpline(xvec, yvec, k=order, ext=ext)
@property
def xvec(self):
"""the X vector"""
return self._xvec
@property
def yvec(self):
"""the Y vector"""
return self._yvec
@property
def order(self):
"""the interpolation order. 1 for nearest, 2 for linear, 3 for spline."""
return self._order
@property
def xtol(self):
"""the X value tolerance."""
return self._xtol
@property
def ext(self):
"""interpolation extension mode. See documentation for InterpolatedUnivariateSpline."""
return self._ext
def __call__(self, *arg, **kwargs):
"""Evaluate the waveform at the given points."""
return self._fun(*arg, **kwargs)
def get_xrange(self):
"""Returns the X vector range.
Returns
-------
xmin : float
minimum X value.
xmax : float
maximum X value.
"""
return self.xvec[0], self.xvec[-1]
def shift_by(self, xshift):
"""Returns a shifted version of this waveform.
Parameters
----------
xshift : float
the amount to shift by.
Returns
-------
wvfm : bag.data.core.Waveform
a reference to this instance, or a copy if copy is True.
"""
return Waveform(self.xvec + xshift, self.yvec, self.xtol, order=self.order, ext=self.ext)
def get_all_crossings(self, threshold, start=None, stop=None, edge='both'):
"""Returns all X values at which this waveform crosses the given threshold.
Parameters
----------
threshold : float
the threshold value.
start : float or None
if given, search for crossings starting at this X value.
stop : float or None
if given, search only for crossings before this X value.
edge : string
crossing type. Valid values are 'rising', 'falling', or 'both'.
Returns
-------
xval_list : list[float]
all X values at which crossing occurs.
"""
# determine start and stop indices
sidx = 0 if start is None else np.searchsorted(self.xvec, [start])[0]
if stop is None:
eidx = len(self.xvec)
else:
eidx = np.searchsorted(self.xvec, [stop])[0]
if eidx < len(self.xvec) and abs(self.xvec[eidx] - stop) < self.xtol:
eidx += 1
# quantize waveform values, then detect edge.
bool_vec = self.yvec[sidx:eidx] >= threshold # type: np.ndarray
qvec = bool_vec.astype(int)
dvec = np.diff(qvec)
# eliminate unwanted edge types.
if edge == 'rising':
dvec = np.maximum(dvec, 0)
elif edge == 'falling':
dvec = np.minimum(dvec, 0)
# get crossing indices
idx_list = dvec.nonzero()[0]
# convert indices to X value using brentq interpolation.
def crossing_fun(x):
return self._fun(x) - threshold
xval_list = []
for idx in idx_list:
t0, t1 = self.xvec[sidx + idx], self.xvec[sidx + idx + 1]
try:
tcross = sciopt.brentq(crossing_fun, t0, t1, xtol=self.xtol)
except ValueError:
# no solution, this happens only if we have numerical error
# around the threshold. In this case just pick the endpoint
# closest to threshold.
va = crossing_fun(t0)
vb = crossing_fun(t1)
tcross = t0 if abs(va) < abs(vb) else t1
xval_list.append(tcross)
return xval_list
def get_crossing(self, threshold, start=None, stop=None, n=1, edge='both'):
"""Returns the X value at which this waveform crosses the given threshold.
Parameters
----------
threshold : float
the threshold value.
start : float or None
if given, search for the crossing starting at this X value.'
stop : float or None
if given, search only for crossings before this X value.
n : int
returns the nth crossing.
edge : str
crossing type. Valid values are 'rising', 'falling', or 'both'.
Returns
-------
xval : float or None
the X value at which the crossing occurs. None if no crossings are detected.
"""
xval_list = self.get_all_crossings(threshold, start=start, stop=stop, edge=edge)
if len(xval_list) < n:
return None
return xval_list[n-1]
def to_arrays(self, xmin=None, xmax=None):
"""Returns the X and Y arrays representing this waveform.
Parameters
----------
xmin : float or None
If given, will start from this value.
xmax : float or None
If given, will end at this value.
Returns
-------
xvec : np.multiarray.ndarray
the X array
yvec : np.multiarray.ndarray
the Y array
"""
sidx = 0 if xmin is None else np.searchsorted(self.xvec, [xmin])[0]
eidx = len(self.xvec) if xmax is None else np.searchsorted(self.xvec, [xmax])[0]
if eidx < len(self.xvec) and self.xvec[eidx] == xmax:
eidx += 1
xtemp = self.xvec[sidx:eidx]
if xmin is not None and (len(xtemp) == 0 or xtemp[0] != xmin):
np.insert(xtemp, 0, [xmin])
if xmax is not None and (len(xtemp) == 0 or xtemp[-1] != xmax):
np.append(xtemp, [xmax])
return xtemp, self(xtemp)
def get_eye_specs(self, tbit, tsample, thres=0.0, nlev=2):
"""Compute the eye diagram spec of this waveform.
This algorithm uses the following steps.
1. set t_off to 0
2. sample the waveform at tbit interval, starting at t0 + t_off.
3. sort the sampled values, get gap between adjacent values.
4. record G, the length of the gap covering thres.
5. increment t_off by tsample, go to step 2 and repeat until
t_off >= tbit.
6. find t_off with maximum G. This is the eye center.
7. at the eye center, compute eye height and eye opening using kmeans
clustering algorithm.
8. return result.
Parameters
----------
tbit : float
eye period.
tsample : float
the resolution to sample the eye. Used to find optimal
time shift and maximum eye opening.
thres : float
the eye vertical threshold.
nlev : int
number of expected levels. 2 for NRZ, 4 for PAM4.
Returns
-------
result : dict
A dictionary from specification to value.
"""
tstart, tend = self.get_xrange()
toff_vec = np.arange(0, tbit, tsample)
best_idx = 0
best_gap = 0.0
best_values = None
mid_lev = nlev // 2
for idx, t_off in enumerate(toff_vec):
# noinspection PyTypeChecker
values = self(np.arange(tstart + t_off, tend, tbit))
values.sort()
up_idx = np.searchsorted(values, [thres])[0]
if up_idx == 0 or up_idx == len(values):
continue
cur_gap = values[up_idx] - values[up_idx - 1]
if cur_gap > best_gap:
best_idx = idx
best_gap = cur_gap
best_values = values
if best_values is None:
raise ValueError("waveform never cross threshold=%.4g" % thres)
vstd = np.std(best_values)
vtemp = best_values / vstd
tmp_arr = np.linspace(vtemp[0], vtemp[-1], nlev) # type: np.ndarray
clusters = svq.kmeans(vtemp, tmp_arr)[0]
# clusters = svq.kmeans(vtemp, 4, iter=50)[0]
clusters *= vstd
clusters.sort()
vcenter = (clusters[mid_lev] + clusters[mid_lev - 1]) / 2.0
# compute eye opening/margin
openings = []
tr_widths = []
last_val = best_values[0]
bot_val = last_val
cur_cidx = 0
for cur_val in best_values:
cur_cluster = clusters[cur_cidx]
next_cluster = clusters[cur_cidx + 1]
if abs(cur_val - cur_cluster) > abs(cur_val - next_cluster):
openings.append(cur_val - last_val)
tr_widths.append(last_val - bot_val)
cur_cidx += 1
if cur_cidx == len(clusters) - 1:
tr_widths.append(best_values[-1] - cur_val)
break
bot_val = cur_val
last_val = cur_val
return {'center': (float(toff_vec[best_idx]), vcenter),
'levels': clusters,
'heights': clusters[1:] - clusters[:-1],
'openings': np.array(openings),
'trace_widths': np.array(tr_widths)
}
def _add_xy(self, other):
if not isinstance(other, Waveform):
raise ValueError("Trying to add non-Waveform object.")
xnew = np.concatenate((self.xvec, other.xvec))
xnew = np.unique(np.around(xnew / self.xtol)) * self.xtol
# noinspection PyTypeChecker
y1 = self(xnew)
y2 = other(xnew)
return xnew, y1 + y2
def __add__(self, other):
if np.isscalar(other):
return Waveform(np.array(self.xvec), self.yvec + other, self.xtol, order=self.order, ext=self.ext)
elif isinstance(other, Waveform):
new_order = max(self.order, other.order)
xvec, yvec = self._add_xy(other)
return Waveform(xvec, yvec, self.xtol, order=new_order, ext=self.ext)
else:
raise Exception('type %s not supported' % type(other))
def __neg__(self):
return Waveform(np.array(self.xvec), -self.yvec, self.xtol, order=self.order, ext=self.ext)
def __mul__(self, scale):
if not np.isscalar(scale):
raise ValueError("Can only multiply by scalar.")
return Waveform(np.array(self.xvec), scale * self.yvec, self.xtol, order=self.order, ext=self.ext)
def __rmul__(self, scale):
return self.__mul__(scale)
================================================
FILE: bag/data/dc.py
================================================
# -*- coding: utf-8 -*-
"""This module defines classes for computing DC operating point.
"""
from typing import Union, Dict
import scipy.sparse
import scipy.optimize
import numpy as np
from bag.tech.mos import MosCharDB
class DCCircuit(object):
"""A class that solves DC operating point of a circuit.
Parameters
----------
ndb : MosCharDB
nmos characterization database.
pdb : MosCharDB
pmos characterization database.
"""
def __init__(self, ndb, pdb):
# type: (MosCharDB, MosCharDB) -> None
self._n = 1
self._ndb = ndb
self._pdb = pdb
self._transistors = {}
self._node_id = {'gnd': 0, 'vss': 0, 'VSS': 0}
self._node_name_lookup = {0: 'gnd'}
self._node_voltage = {0: 0}
def _get_node_id(self, name):
# type: (str) -> int
if name not in self._node_id:
ans = self._n
self._node_id[name] = ans
self._node_name_lookup[ans] = name
self._n += 1
return ans
else:
return self._node_id[name]
def set_voltage_source(self, node_name, voltage):
# type: (str, float) -> None
"""
Specify voltage the a node.
Parameters
----------
node_name : str
the net name.
voltage : float
voltage of the given net.
"""
node_id = self._get_node_id(node_name)
self._node_voltage[node_id] = voltage
def add_transistor(self, d_name, g_name, s_name, b_name, mos_type, intent, w, lch, fg=1):
# type: (str, str, str, str, str, str, Union[float, int], float, int) -> None
"""Adds a small signal transistor model to the circuit.
Parameters
----------
d_name : str
drain net name.
g_name : str
gate net name.
s_name : str
source net name.
b_name : str
body net name. Defaults to 'gnd'.
mos_type : str
transistor type. Either 'nch' or 'pch'.
intent : str
transistor threshold flavor.
w : Union[float, int]
transistor width.
lch : float
transistor channel length.
fg : int
transistor number of fingers.
"""
node_d = self._get_node_id(d_name)
node_g = self._get_node_id(g_name)
node_s = self._get_node_id(s_name)
node_b = self._get_node_id(b_name)
# get existing current function. Initalize if not found.
ids_key = (mos_type, intent, lch)
if ids_key in self._transistors:
arow, acol, bdata, fg_list, ds_list = self._transistors[ids_key]
else:
arow, acol, bdata, fg_list, ds_list = [], [], [], [], []
self._transistors[ids_key] = (arow, acol, bdata, fg_list, ds_list)
# record Ai and bi data
offset = len(fg_list) * 4
arow.extend([offset + 1, offset + 1, offset + 2, offset + 2, offset + 3, offset + 3])
acol.extend([node_b, node_s, node_d, node_s, node_g, node_s])
bdata.append(w)
fg_list.append(fg)
ds_list.append((node_d, node_s))
def solve(self, env, guess_dict, itol=1e-10, inorm=1e-6):
# type: (str, Dict[str, float], float, float) -> Dict[str, float]
"""Solve DC operating point.
Parameters
----------
env : str
the simulation environment.
guess_dict : Dict[str, float]
initial guess dictionary.
itol : float
current error tolerance.
inorm : float
current normalization factor.
Returns
-------
op_dict : Dict[str, float]
DC operating point dictionary.
"""
# step 1: get list of nodes to solve
node_list = [idx for idx in range(self._n) if idx not in self._node_voltage]
reverse_dict = {nid: idx for idx, nid in enumerate(node_list)}
ndim = len(node_list)
# step 2: get Av and bv
amatv = scipy.sparse.csr_matrix(([1] * ndim, (node_list, np.arange(ndim))), shape=(self._n, ndim))
bmatv = np.zeros(self._n)
for nid, val in self._node_voltage.items():
bmatv[nid] = val
# step 3: gather current functions, and output matrix entries
ifun_list = []
out_data = []
out_row = []
out_col = []
out_col_cnt = 0
for (mos_type, intent, lch), (arow, acol, bdata, fg_list, ds_list) in self._transistors.items():
db = self._ndb if mos_type == 'nch' else self._pdb
ifun = db.get_function('ids', env=env, intent=intent, l=lch)
# step 3A: compute Ai and bi
num_tran = len(fg_list)
adata = [1, -1] * (3 * num_tran)
amati = scipy.sparse.csr_matrix((adata, (arow, acol)), shape=(4 * num_tran, self._n))
bmati = np.zeros(4 * num_tran)
bmati[0::4] = bdata
# step 3B: compute A = Ai * Av, b = Ai * bv + bi
amat = amati.dot(amatv)
bmat = amati.dot(bmatv) + bmati
# record scale matrix and function.
scale_mat = scipy.sparse.diags(fg_list) / inorm
ifun_list.append((ifun, scale_mat, amat, bmat))
for node_d, node_s in ds_list:
if node_d in reverse_dict:
out_row.append(reverse_dict[node_d])
out_data.append(-1)
out_col.append(out_col_cnt)
if node_s in reverse_dict:
out_row.append(reverse_dict[node_s])
out_data.append(1)
out_col.append(out_col_cnt)
out_col_cnt += 1
# construct output matrix
out_mat = scipy.sparse.csr_matrix((out_data, (out_row, out_col)), shape=(ndim, out_col_cnt))
# step 4: define zero function
def zero_fun(varr):
iarr = np.empty(out_col_cnt)
offset = 0
for idsf, smat, ai, bi in ifun_list:
num_out = smat.shape[0]
# reshape going row first instead of column
arg = (ai.dot(varr) + bi).reshape(4, -1, order='F').T
if idsf.ndim == 3:
# handle case where transistor source and body are shorted
tmpval = idsf(arg[:, [0, 2, 3]])
else:
tmpval = idsf(arg)
iarr[offset:offset + num_out] = smat.dot(tmpval)
offset += num_out
return out_mat.dot(iarr)
# step 5: define zero function
def jac_fun(varr):
jarr = np.empty((out_col_cnt, ndim))
offset = 0
for idsf, smat, ai, bi in ifun_list:
num_out = smat.shape[0]
# reshape going row first instead of column
arg = (ai.dot(varr) + bi).reshape(4, -1, order='F').T
if idsf.ndim == 3:
# handle case where transistor source and body are shorted
tmpval = idsf.jacobian(arg[:, [0, 2, 3]])
# noinspection PyTypeChecker
tmpval = np.insert(tmpval, 1, 0.0, axis=len(tmpval.shape) - 1)
else:
tmpval = idsf.jacobian(arg)
jcur = smat.dot(tmpval)
for idx in range(num_out):
# ai is sparse matrix; multiplication is matrix
jarr[offset + idx, :] = jcur[idx, :] @ ai[4 * idx:4 * idx + 4, :]
offset += num_out
return out_mat.dot(jarr)
xguess = np.empty(ndim)
for name, guess_val in guess_dict.items():
xguess[reverse_dict[self._node_id[name]]] = guess_val
result = scipy.optimize.root(zero_fun, xguess, jac=jac_fun, tol=itol / inorm, method='hybr')
if not result.success:
raise ValueError('solution failed.')
op_dict = {self._node_name_lookup[nid]: result.x[idx] for idx, nid in enumerate(node_list)}
return op_dict
================================================
FILE: bag/data/digital.py
================================================
# -*- coding: utf-8 -*-
"""This module defines functions useful for digital verification/postprocessing.
"""
from typing import Optional, List, Tuple
import numpy as np
from .core import Waveform
def de_bruijn(n, symbols=None):
# type: (int, Optional[List[float]]) -> List[float]
"""Returns a De Bruijn sequence with subsequence of length n.
a De Bruijn sequence with subsequence of length n is a sequence such that
all possible subsequences of length n appear exactly once somewhere in the
sequence. This method is useful for simulating the worst case eye diagram
given finite impulse response.
Parameters
----------
n : int
length of the subsequence.
symbols : Optional[List[float]] or None
the list of symbols. If None, defaults to [0.0, 1.0].
Returns
-------
seq : List[float]
the de bruijn sequence.
"""
symbols = symbols or [0.0, 1.0]
k = len(symbols)
a = [0] * (k * n)
sequence = []
def db(t, p):
if t > n:
if n % p == 0:
sequence.extend(a[1:p + 1])
else:
a[t] = a[t - p]
db(t + 1, p)
for j in range(a[t - p] + 1, k):
a[t] = j
db(t + 1, t)
db(1, 1)
return [symbols[i] for i in sequence]
def dig_to_pwl(values, tper, trf, td=0):
# type: (List[float], float, float, float) -> Tuple[List[float], List[float]]
"""Convert a list of digital bits to PWL waveform.
This function supports negative delay. However, time/value pairs for negative data
are truncated.
Parameters
----------
values : List[float]
list of values for each bit.
tper : float
the period in seconds.
trf : float
the rise/fall time in seconds.
td : float
the delay
Returns
-------
tvec : List[float]
the time vector.
yvec : List[float]
the value vector.
"""
y0 = values[0]
tcur, ycur = td, y0
tvec, yvec = [], []
for v in values:
if v != ycur:
if tcur >= 0:
tvec.append(tcur)
yvec.append(ycur)
elif tcur < 0 < tcur + trf:
# make sure time starts at 0
tvec.append(0)
yvec.append(ycur - (v - ycur) / trf * tcur)
ycur = v
if tcur + trf >= 0:
tvec.append(tcur + trf)
yvec.append(ycur)
elif tcur + trf < 0 < tcur + tper:
# make sure time starts at 0
tvec.append(0)
yvec.append(ycur)
tcur += tper
else:
if tcur <= 0 < tcur + tper:
# make sure time starts at 0
tvec.append(0)
yvec.append(ycur)
tcur += tper
if not tvec:
# only here if input is constant
tvec = [0, tper]
yvec = [y0, y0]
elif tvec[0] > 0:
# make time start at 0
tvec.insert(0, 0)
yvec.insert(0, y0)
return tvec, yvec
def get_crossing_index(yvec, threshold, n=0, rising=True):
# type: (np.array, float, int, bool) -> int
"""Returns the first index that the given numpy array crosses the given threshold.
Parameters
----------
yvec : np.array
the numpy array.
threshold : float
the crossing threshold.
n : int
returns the nth edge index, with n=0 being the first index.
rising : bool
True to return rising edge index. False to return falling edge index.
Returns
-------
idx : int
the crossing edge index.
"""
bool_vec = yvec >= threshold
qvec = bool_vec.astype(int)
dvec = np.diff(qvec)
dvec = np.maximum(dvec, 0) if rising else np.minimum(dvec, 0)
idx_list = dvec.nonzero()[0]
return idx_list[n]
def get_flop_timing(tvec, d, q, clk, ttol, data_thres=0.5,
clk_thres=0.5, tstart=0.0, clk_edge='rising', tag=None, invert=False):
"""Calculate flop timing parameters given the associated waveforms.
This function performs the following steps:
1. find all valid clock edges. Compute period of the clock (clock waveform
must be periodic).
2. For each valid clock edge:
A. Check if the input changes in the previous cycle. If so, compute tsetup.
Otherwise, tsetup = tperiod.
B. Check if input changes in the current cycle. If so, compute thold.
Otherwise, thold = tperiod.
C. Check that output transition at most once and that output = input.
Otherwise, record an error.
D. record the output data polarity.
3. For each output data polarity, compute the minimum tsetup and thold and any
errors. Return summary as a dictionary.
The output is a dictionary with keys 'setup', 'hold', 'delay', and 'errors'.
the setup/hold/delay entries contains 2-element tuples describing the worst
setup/hold/delay time. The first element is the setup/hold/delay time, and
the second element is the clock edge time at which it occurs. The errors field
stores all clock edge times at which an error occurs.
Parameters
----------
tvec : np.ndarray
the time data.
d : np.ndarray
the input data.
q : np.ndarray
the output data.
clk : np.ndarray
the clock data.
ttol : float
time resolution.
data_thres : float
the data threshold.
clk_thres : float
the clock threshold.
tstart : float
ignore data points before tstart.
clk_edge : str
the clock edge type. Valid values are "rising", "falling", or "both".
tag : obj
an identifier tag to append to results.
invert : bool
if True, the flop output is inverted from the data.
Returns
-------
data : dict[str, any]
A dictionary describing the worst setup/hold/delay and errors, if any.
"""
d_wv = Waveform(tvec, d, ttol)
clk_wv = Waveform(tvec, clk, ttol)
q_wv = Waveform(tvec, q, ttol)
tend = tvec[-1]
# get all clock sampling times and clock period
samp_times = clk_wv.get_all_crossings(clk_thres, start=tstart, edge=clk_edge)
tper = (samp_times[-1] - samp_times[0]) / (len(samp_times) - 1)
# ignore last clock cycle if it's not a full cycle.
if samp_times[-1] + tper > tend:
samp_times = samp_times[:-1]
# compute setup/hold/error for each clock period
data = {'setup': (tper, -1), 'hold': (tper, -1), 'delay': (0.0, -1), 'errors': []}
for t in samp_times:
d_prev = d_wv.get_all_crossings(data_thres, start=t - tper, stop=t, edge='both')
d_cur = d_wv.get_all_crossings(data_thres, start=t, stop=t + tper, edge='both')
q_cur = q_wv.get_all_crossings(data_thres, start=t, stop=t + tper, edge='both')
d_val = d_wv(t) > data_thres
q_val = q_wv(t + tper) > data_thres
# calculate setup/hold/delay
tsetup = t - d_prev[-1] if d_prev else tper
thold = d_cur[0] - t if d_cur else tper
tdelay = q_cur[0] - t if q_cur else 0.0
# check if flop has error
error = (invert != (q_val != d_val)) or (len(q_cur) > 1)
# record results
if tsetup < data['setup'][0]:
data['setup'] = (tsetup, t)
if thold < data['hold'][0]:
data['hold'] = (thold, t)
if tdelay > data['delay'][0]:
data['delay'] = (tdelay, t)
if error:
data['errors'].append(t)
if tag is not None:
data['setup'] += (tag, )
data['hold'] += (tag, )
data['delay'] += (tag, )
data['errors'] = [(t, tag) for t in data['errors']]
return data
================================================
FILE: bag/data/lti.py
================================================
# -*- coding: utf-8 -*-
"""This module defines functions and classes useful for characterizing linear time-invariant circuits.
"""
from typing import Dict, List, Tuple, Union, Optional
import numpy as np
import scipy.signal
import scipy.sparse
import scipy.sparse.linalg
# noinspection PyProtectedMember
from scipy.signal.ltisys import StateSpaceContinuous, TransferFunctionContinuous
class LTICircuit(object):
"""A class that models a linear-time-invariant circuit.
This class computes AC transfer functions for linear-time-invariant circuits.
Note: Since this class work with AC transfer functions, 'gnd' in this circuit is AC ground.
Parameters
----------
udot_tol : float
tolerance to determine if dependency on input derivatives is zero.
"""
_float_min = np.finfo(np.float64).eps
def __init__(self, udot_tol=1e-12):
# type: (float) -> None
self._num_n = 0
self._gmat_data = {} # type: Dict[Tuple[int, int], float]
self._cmat_data = {} # type: Dict[Tuple[int, int], float]
self._vcvs_list = [] # type: List[Tuple[int, int, int, int, float]]
self._ind_data = {} # type: Dict[Tuple[int, int], float]
self._node_id = {'gnd': -1}
self._udot_tol = udot_tol
def _get_node_id(self, name):
# type: (str) -> int
if name not in self._node_id:
ans = self._num_n
self._node_id[name] = ans
self._num_n += 1
return ans
else:
return self._node_id[name]
@staticmethod
def _add(mat, key, val):
# type: (Dict[Tuple[int, int], float], Tuple[int, int], float) -> None
if key in mat:
mat[key] += val
else:
mat[key] = val
def add_res(self, res, p_name, n_name):
# type: (float, str, str) -> None
"""Adds a resistor to the circuit.
Parameters
----------
res : float
the resistance value, in Ohms.
p_name : str
the positive terminal net name.
n_name : str
the negative terminal net name.
"""
# avoid 0 resistance.
res_sgn = 1 if res >= 0 else -1
g = res_sgn / max(abs(res), self._float_min)
self.add_conductance(g, p_name, n_name)
def add_conductance(self, g, p_name, n_name):
# type: (float, str, str) -> None
"""Adds a resistor to the circuit given conductance value.
Parameters
----------
g : float
the conductance value, in inverse Ohms.
p_name : str
the positive terminal net name.
n_name : str
the negative terminal net name.
"""
node_p = self._get_node_id(p_name)
node_n = self._get_node_id(n_name)
if node_p == node_n:
return
if node_p < node_n:
node_p, node_n = node_n, node_p
self._add(self._gmat_data, (node_p, node_p), g)
if node_n >= 0:
self._add(self._gmat_data, (node_p, node_n), -g)
self._add(self._gmat_data, (node_n, node_p), -g)
self._add(self._gmat_data, (node_n, node_n), g)
def add_vccs(self, gm, p_name, n_name, cp_name, cn_name='gnd'):
# type: (float, str, str, str, str) -> None
"""Adds a voltage controlled current source to the circuit.
Parameters
----------
gm : float
the gain of the voltage controlled current source, in Siemens.
p_name : str
the terminal that the current flows out of.
n_name : str
the terminal that the current flows in to.
cp_name : str
the positive voltage control terminal.
cn_name : str
the negative voltage control terminal. Defaults to 'gnd'.
"""
node_p = self._get_node_id(p_name)
node_n = self._get_node_id(n_name)
node_cp = self._get_node_id(cp_name)
node_cn = self._get_node_id(cn_name)
if node_p == node_n or node_cp == node_cn:
return
if node_cp >= 0:
if node_p >= 0:
self._add(self._gmat_data, (node_p, node_cp), gm)
if node_n >= 0:
self._add(self._gmat_data, (node_n, node_cp), -gm)
if node_cn >= 0:
if node_p >= 0:
self._add(self._gmat_data, (node_p, node_cn), -gm)
if node_n >= 0:
self._add(self._gmat_data, (node_n, node_cn), gm)
def add_vcvs(self, gain, p_name, n_name, cp_name, cn_name='gnd'):
# type: (float, str, str, str, str) -> None
"""Adds a voltage controlled voltage source to the circuit.
Parameters
----------
gain : float
the gain of the voltage controlled voltage source.
p_name : str
the positive terminal of the output voltage source.
n_name : str
the negative terminal of the output voltage source.
cp_name : str
the positive voltage control terminal.
cn_name : str
the negative voltage control terminal. Defaults to 'gnd'.
"""
node_p = self._get_node_id(p_name)
node_n = self._get_node_id(n_name)
node_cp = self._get_node_id(cp_name)
node_cn = self._get_node_id(cn_name)
if node_p == node_n:
raise ValueError('positive and negative terminal of a vcvs cannot be the same.')
if node_cp == node_cn:
raise ValueError('positive and negative control terminal of a vcvs cannot be the same.')
if node_p < node_n:
# flip nodes so we always have node_p > node_n, to guarantee node_p >= 0
node_p, node_n, node_cp, node_cn = node_n, node_p, node_cn, node_cp
self._vcvs_list.append((node_p, node_n, node_cp, node_cn, gain))
def add_cap(self, cap, p_name, n_name):
# type: (float, str, str) -> None
"""Adds a capacitor to the circuit.
Parameters
----------
cap : float
the capacitance value, in Farads.
p_name : str
the positive terminal net name.
n_name : str
the negative terminal net name.
"""
node_p = self._get_node_id(p_name)
node_n = self._get_node_id(n_name)
if node_p == node_n:
return
if node_p < node_n:
node_p, node_n = node_n, node_p
self._add(self._cmat_data, (node_p, node_p), cap)
if node_n >= 0:
self._add(self._cmat_data, (node_p, node_n), -cap)
self._add(self._cmat_data, (node_n, node_p), -cap)
self._add(self._cmat_data, (node_n, node_n), cap)
def add_ind(self, ind, p_name, n_name):
# type: (float, str, str) -> None
"""Adds an inductor to the circuit.
Parameters
----------
ind : float
the inductance value, in Henries.
p_name : str
the positive terminal net name.
n_name : str
the negative terminal net name.
"""
node_p = self._get_node_id(p_name)
node_n = self._get_node_id(n_name)
if node_p == node_n:
return
if node_p < node_n:
key = node_n, node_p
else:
key = node_p, node_n
if key not in self._ind_data:
self._ind_data[key] = ind
else:
self._ind_data[key] = 1.0 / (1.0 / ind + 1.0 / self._ind_data[key])
def add_transistor(self, tran_info, d_name, g_name, s_name, b_name='gnd', fg=1, neg_cap=True):
# type: (Dict[str, float], str, str, str, str, Union[float, int], bool) -> None
"""Adds a small signal transistor model to the circuit.
Parameters
----------
tran_info : Dict[str, float]
a dictionary of 1-finger transistor small signal parameters. Should contain gm, gds, gb,
cgd, cgs, cgb, cds, cdb, and csb.
d_name : str
drain net name.
g_name : str
gate net name.
s_name : str
source net name.
b_name : str
body net name. Defaults to 'gnd'.
fg : Union[float, int]
number of transistor fingers.
neg_cap : bool
True to allow negative capacitance (which is there due to model fitting).
"""
gm = tran_info['gm'] * fg
gds = tran_info['gds'] * fg
cgd = tran_info['cgd'] * fg
cgs = tran_info['cgs'] * fg
cds = tran_info['cds'] * fg
cgb = tran_info.get('cgb', 0) * fg
cdb = tran_info.get('cdb', 0) * fg
csb = tran_info.get('csb', 0) * fg
if not neg_cap:
cgd = max(cgd, 0)
cgs = max(cgs, 0)
cds = max(cds, 0)
cgb = max(cgb, 0)
cdb = max(cdb, 0)
csb = max(csb, 0)
self.add_vccs(gm, d_name, s_name, g_name, s_name)
self.add_conductance(gds, d_name, s_name)
self.add_cap(cgd, g_name, d_name)
self.add_cap(cgs, g_name, s_name)
self.add_cap(cds, d_name, s_name)
self.add_cap(cgb, g_name, b_name)
self.add_cap(cdb, d_name, b_name)
self.add_cap(csb, s_name, b_name)
if 'gb' in tran_info:
# only add these if source is not shorted to body.
gb = tran_info['gb'] * fg
self.add_vccs(gb, d_name, s_name, b_name, s_name)
@classmethod
def _count_rank(cls, diag):
# type: (np.ndarray) -> int
diag_abs = np.abs(diag)
float_min = cls._float_min
rank_tol = diag_abs[0] * diag.size * float_min
rank_cnt = diag_abs > rank_tol # type: np.ndarray
return np.count_nonzero(rank_cnt)
@classmethod
def _solve_gx_bw(cls, g, b):
# type: (np.ndarray, np.ndarray) -> Tuple[np.ndarray, np.ndarray]
"""Solve the equation G*x + B*[w, w', ...].T = 0 for x.
Finds matrix Ka, Kw such that x = Ka * a + Kw * [w, w', ...].T solves
the given equation for any value of a.
Parameters
----------
g : np.ndarray
the G matrix, with shape (M, N) and M < N.
b : np.ndarray
the B matrix.
Returns
-------
ka : np.ndarray
the Ky matrix.
kw : np.ndarray
the Kw matrix.
"""
# G = U*S*Vh
u, s, vh = scipy.linalg.svd(g, full_matrices=True, overwrite_a=True)
# let B=Uh*B, so now S*Vh*x + B*w = 0
b = u.T.dot(b)
# let y = Vh*x, or x = V*y, so now S*y + U*B*w = 0
v = vh.T
# truncate the bottom 0 part of S, now S_top*y_top + B_top*w = 0
rank = cls._count_rank(s)
# check bottom part of B. If not 0, there's no solution
b_abs = np.abs(b)
zero_tol = np.amax(b_abs) * cls._float_min
if np.count_nonzero(b_abs[rank:, :] > zero_tol) > 0:
raise ValueError('B matrix bottom is not zero. This circuit has no solution.')
b_top = b[:rank, :]
s_top_inv = 1 / s[:rank] # type: np.ndarray
s_top_inv = np.diag(s_top_inv)
# solving, we get y_top = -S_top^-1*B_top*w = Ku*w
kw = s_top_inv.dot(-b_top)
# now x = V*y = Vl*y_top + Vr*y_bot = Vr*y_bot + Vl*Kw*w = Ky*y_bot = Kw*w
vl = v[:, :rank]
vr = v[:, rank:]
kw = vl.dot(kw)
return vr, kw
@classmethod
def _transform_c_qr(cls, g, c, b, d):
"""Reveal redundant variables by transforming C matrix using QR decomposition"""
q, r, p = scipy.linalg.qr(c, pivoting=True)
rank = cls._count_rank(np.diag(r))
qh = q.T
return rank, qh.dot(g[:, p]), r, qh.dot(b), d[:, p]
# @classmethod
# def _transform_c_svd(cls, g, c, b, d):
# """Reveal redundant variables by transforming C matrix using SVD decomposition"""
# u, s, vh = scipy.linalg.svd(c, full_matrices=True, overwrite_a=True)
# uh = u.T
# v = vh.T
# rank = cls._count_rank(s)
# return rank, uh.dot(g).dot(v), np.diag(s), uh.dot(b), d.dot(v)
@classmethod
def _reduce_state_space(cls, g, c, b, d, e, ndim_w):
"""Reduce state space variables.
Given the state equation G*x + C*x' + B*[w, w', w'', ...].T = 0, and
y = D*x + E*[w, w', w'', ...].T, check if C is full rank. If not,
we compute new G, C, and B matrices with reduced dimensions.
"""
# step 0: transform C and obtain rank
rank, g, c, b, d = cls._transform_c_qr(g, c, b, d)
# rank, g, c, b, d = cls._transform_c_svd(g, c, b, d)
while rank < c.shape[0]:
# step 1: eliminate x' term by looking at bottom part of matrices
ctop = c[:rank, :]
gtop = g[:rank, :]
gbot = g[rank:, :]
btop = b[:rank, :]
bbot = b[rank:, :]
# step 2: find ka and kw from bottom
ka, kw = cls._solve_gx_bw(gbot, bbot)
# step 3: substitute x = ka * a + kw * [w, w', w'', ...].T
g = gtop.dot(ka)
c = ctop.dot(ka)
b = np.zeros((btop.shape[0], btop.shape[1] + ndim_w))
b[:, :btop.shape[1]] = btop + gtop.dot(kw)
b[:, ndim_w:] += ctop.dot(kw)
enew = np.zeros((e.shape[0], e.shape[1] + ndim_w))
enew[:, :-ndim_w] = e + d.dot(kw)
e = enew
d = d.dot(ka)
# step 4: transform C to prepare for next iteration
rank, g, c, b, d = cls._transform_c_qr(g, c, b, d)
# rank, g, c, b, d = cls._transform_c_svd(g, c, b, d)
g, c, b, d, e = cls._simplify(g, c, b, d, e, ndim_w)
return g, c, b, d, e
@classmethod
def _simplify(cls, g, c, b, d, e, ndim_w):
"""Eliminate input derivatives by re-defining state variables.
"""
while b.shape[1] > ndim_w:
kw = scipy.linalg.solve_triangular(c, b[:, ndim_w:])
bnew = np.dot(g, -kw)
bnew[:, :ndim_w] += b[:, :ndim_w]
b = bnew
e[:, :kw.shape[1]] -= d.dot(kw)
return g, c, b, d, e
def _build_mna_matrices(self, inputs, outputs, in_type='v'):
# type: (Union[str, List[str]], Union[str, List[str]], str) -> Tuple[np.ndarray, ...]
"""Create and return MNA matrices representing this circuit.
Parameters
----------
inputs : Union[str, List[str]]
the input voltage/current node name(s).
outputs : Union[str, List[str]]
the output voltage node name(s).
in_type : str
set to 'v' for input voltage sources. Otherwise, current sources.
Returns
-------
g : np.ndarray
the conductance matrix
c : np.ndarray
the capacitance/inductance matrix.
b : np.ndarray
the input-to-state matrix.
d : np.ndarray
the state-to-output matrix.
e : np.ndarray
the input-to-output matrix.
"""
if isinstance(inputs, list) or isinstance(inputs, tuple):
node_ins = [self._node_id[name] for name in inputs]
else:
node_ins = [self._node_id[inputs]]
if isinstance(outputs, list) or isinstance(outputs, tuple):
node_outs = [self._node_id[name] for name in outputs]
else:
node_outs = [self._node_id[outputs]]
is_voltage = (in_type == 'v')
# step 1: construct matrices
gdata, grows, gcols = [], [], []
cdata, crows, ccols = [], [], []
# step 1A: gather conductors/vccs
for (ridx, cidx), gval in self._gmat_data.items():
gdata.append(gval)
grows.append(ridx)
gcols.append(cidx)
# step 1B: gather capacitors
for (ridx, cidx), cval in self._cmat_data.items():
cdata.append(cval)
crows.append(ridx)
ccols.append(cidx)
# step 1C: gather inductors
num_states = self._num_n
for (node_p, node_n), lval in self._ind_data.items():
gdata.append(1)
grows.append(node_p)
gcols.append(num_states)
gdata.append(1)
grows.append(num_states)
gcols.append(node_p)
if node_n >= 0:
gdata.append(-1)
grows.append(node_n)
gcols.append(num_states)
gdata.append(-1)
grows.append(num_states)
gcols.append(node_n)
cdata.append(-lval)
crows.append(num_states)
ccols.append(num_states)
num_states += 1
# step 1D: add currents from vcvs
for node_p, node_n, node_cp, node_cn, gain in self._vcvs_list:
# vcvs means vp - vn - A*vcp + A*vcn = 0, and current flows from p to n
# current flowing out of p
gdata.append(1)
grows.append(node_p)
gcols.append(num_states)
# voltage of p
gdata.append(1)
grows.append(num_states)
gcols.append(node_p)
if node_n >= 0:
# current flowing into n
gdata.append(-1)
grows.append(node_n)
gcols.append(num_states)
# voltage of n
gdata.append(-1)
grows.append(num_states)
gcols.append(node_n)
if node_cp >= 0:
# voltage of cp
gdata.append(-gain)
grows.append(num_states)
gcols.append(node_cp)
if node_cn >= 0:
# voltage of cn
gdata.append(gain)
grows.append(num_states)
gcols.append(node_cn)
num_states += 1
ndim_in = len(node_ins)
if is_voltage:
# step 1E: add current/voltage from input voltage source
b = np.zeros((num_states + ndim_in, ndim_in))
for in_idx, node_in in enumerate(node_ins):
gdata.append(1)
grows.append(node_in)
gcols.append(num_states)
gdata.append(-1)
grows.append(num_states)
gcols.append(node_in)
b[num_states + in_idx, in_idx] = 1
num_states += ndim_in
else:
# inject current to node_in
b = np.zeros((num_states, ndim_in))
for in_idx, node_in in enumerate(node_ins):
b[node_in, in_idx] = -1
# step 2: create matrices
shape = (num_states, num_states)
g = scipy.sparse.csc_matrix((gdata, (grows, gcols)), shape=shape).todense().A
c = scipy.sparse.csc_matrix((cdata, (crows, ccols)), shape=shape).todense().A
ndim_out = len(node_outs)
d = scipy.sparse.csc_matrix((np.ones(ndim_out), (np.arange(ndim_out), node_outs)),
shape=(ndim_out, num_states)).todense().A
e = np.zeros((ndim_out, ndim_in))
return g, c, b, d, e
def get_state_space(self, inputs, outputs, in_type='v'):
# type: (Union[str, List[str]], Union[str, List[str]], str) -> StateSpaceContinuous
"""Compute the state space model from the given inputs to outputs.
Parameters
----------
inputs : Union[str, List[str]]
the input voltage/current node name(s).
outputs : Union[str, List[str]]
the output voltage node name(s).
in_type : str
set to 'v' for input voltage sources. Otherwise, current sources.
Returns
-------
system : StateSpaceContinuous
the scipy state space object. See scipy.signal package on how to use this object.
"""
g0, c0, b0, d0, e0 = self._build_mna_matrices(inputs, outputs, in_type)
ndim_in = e0.shape[1]
g, c, b, d, e = self._reduce_state_space(g0, c0, b0, d0, e0, ndim_in)
amat = scipy.linalg.solve_triangular(c, -g)
bmat = scipy.linalg.solve_triangular(c, -b)
cmat = d
e_abs = np.abs(e)
tol = np.amax(e_abs) * self._udot_tol
if np.count_nonzero(e_abs[:, ndim_in:] > tol) > 0:
print('WARNING: output depends on input derivatives. Ignored.')
print('D matrix: ')
print(e)
dmat = e[:, :ndim_in]
return StateSpaceContinuous(amat, bmat, cmat, dmat)
def get_num_den(self, in_name, out_name, in_type='v', atol=0.0):
# type: (str, str, str, float) -> Tuple[np.ndarray, np.ndarray]
"""Compute the transfer function between the two given nodes.
Parameters
----------
in_name : str
the input voltage/current node name.
out_name : Union[str, List[str]]
the output voltage node name.
in_type : str
set to 'v' for input voltage sources. Otherwise, current sources.
atol : float
absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.
Returns
-------
num : np.ndarray
the numerator polynomial.
den : np.ndarray
the denominator polynomial.
"""
state_space = self.get_state_space(in_name, out_name, in_type=in_type)
num, den = scipy.signal.ss2tf(state_space.A, state_space.B, state_space.C, state_space.D)
num = num[0, :]
# check if numerator has leading zeros.
# this makes it so the user have full control over numerical precision, and
# avoid scipy bad conditioning warnings.
while abs(num[0]) <= atol:
num = num[1:]
return num, den
def get_transfer_function(self, in_name, out_name, in_type='v', atol=0.0):
# type: (str, str, str, float) -> TransferFunctionContinuous
"""Compute the transfer function between the two given nodes.
Parameters
----------
in_name : str
the input voltage/current node name.
out_name : Union[str, List[str]]
the output voltage node name.
in_type : str
set to 'v' for input voltage sources. Otherwise, current sources.
atol : float
absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.
Returns
-------
system : TransferFunctionContinuous
the scipy transfer function object. See scipy.signal package on how to use this object.
"""
num, den = self.get_num_den(in_name, out_name, in_type=in_type, atol=atol)
return TransferFunctionContinuous(num, den)
def get_impedance(self, node_name, freq, atol=0.0):
# type: (str, float, float) -> complex
"""Computes the impedance looking into the given node.
Parameters
----------
node_name : str
the node to compute impedance for. We will inject a current into this node and measure the voltage
on this node.
freq : float
the frequency to compute the impedance at, in Hertz.
atol : float
absolute tolerance for checking zeros in the numerator. Used to filter out scipy warnings.
Returns
-------
impedance : complex
the impedance value, in Ohms.
"""
sys = self.get_transfer_function(node_name, node_name, in_type='i', atol=atol)
w_test = 2 * np.pi * freq
_, zin_vec = sys.freqresp(w=[w_test])
return zin_vec[0]
def get_w_crossings(num, den, atol=1e-8):
# type: (np.multiarray.ndarray, np.multiarray.ndarray, float) -> Tuple[Optional[float], Optional[float]]
"""Given the numerator and denominator of the transfer function, compute gain margin/phase margin frequencies.
To determine the crossover frequencies, we write the transfer function as:
.. math::
\\frac{A(w) + jB(w)}{C(w) + jD(w)}
where :math:`A(w)`, :math:`B(w)`, :math:`C(w)`, and :math:`D(w)` are real polynomials. The gain margin frequency
is the frequency at which:
.. math::
\\frac{B(w)}{A(w)} = \\frac{D(w)}{C(w)} \\implies A(w)D(w) - B(w)C(w) = 0
The phase margin frequency is the frequency at which:
.. math::
\\frac{A^2(w) + B^2(w)}{C^2(w) + D^2(w)} = 1 \implies A^2(w) + B^2(w) - C^2(w) - D^2(w) = 0
This function solves these two equations and returns the smallest real and positive roots.
Parameters
----------
num : np.multiarray.ndarray
the numerator polynomial coefficients array. index 0 is coefficient for highest term.
den : np.multiarray.ndarray
the denominator polynomial coefficients array. index 0 is coefficient for highest term.
atol : float
absolute tolerance used to check if the imaginary part of a root is 0, or if a root is greater than 0.
Returns
-------
w_phase : Optional[float]
lowest positive frequency in rad/s at which the gain becomes unity. None if no such frequency exist.
w_gain : Optional[float]
lower positive frequency in rad/s at which the phase becomes 180 degrees. None if no such frequency exist.
"""
# construct A(w), B(w), C(w), and D(w)
num_flip = num[::-1]
den_flip = den[::-1]
avec = np.copy(num_flip)
bvec = np.copy(num_flip)
cvec = np.copy(den_flip)
dvec = np.copy(den_flip)
avec[1::2] = 0
avec[2::4] *= -1
bvec[0::2] = 0
bvec[3::4] *= -1
cvec[1::2] = 0
cvec[2::4] *= -1
dvec[0::2] = 0
dvec[3::4] *= -1
apoly = np.poly1d(avec[::-1])
bpoly = np.poly1d(bvec[::-1])
cpoly = np.poly1d(cvec[::-1])
dpoly = np.poly1d(dvec[::-1])
# solve for w_phase/w_gain
poly_list = [apoly**2 + bpoly**2 - cpoly**2 - dpoly**2,
apoly * dpoly - bpoly * cpoly]
w_list = [None, None] # type: List[Optional[float]]
for idx in range(2):
for root in poly_list[idx].roots:
root_real = float(root.real)
if abs(root.imag) < atol < root_real:
w_list_idx = w_list[idx]
if w_list_idx is None or root_real < w_list_idx:
w_list[idx] = root_real
return w_list[0], w_list[1]
def get_w_3db(num, den, atol=1e-8):
# type: (np.multiarray.ndarray, np.multiarray.ndarray, float) -> Optional[float]
"""Given the numerator and denominator of the transfer function, compute the 3dB frequency.
To determine the 3dB frequency, we first normalize the transfer function so that its DC gain is one,
then we write the transfer function as:
.. math::
\\frac{A(w) + jB(w)}{C(w) + jD(w)}
where :math:`A(w)`, :math:`B(w)`, :math:`C(w)`, and :math:`D(w)` are real polynomials. The 3dB frequency
is the frequency at which:
.. math::
\\frac{A^2(w) + B^2(w)}{C^2(w) + D^2(w)} = 0.5 \implies A^2(w) + B^2(w) - 0.5\\left(C^2(w) + D^2(w)\\right) = 0
This function solves this equation and returns the smallest real and positive roots.
Parameters
----------
num : np.multiarray.ndarray
the numerator polynomial coefficients array. index 0 is coefficient for highest term.
den : np.multiarray.ndarray
the denominator polynomial coefficients array. index 0 is coefficient for highest term.
atol : float
absolute tolerance used to check if the imaginary part of a root is 0, or if a root is greater than 0.
Returns
-------
w_3db : Optional[float]
the 3dB frequency in rad/s. None if no such frequency exist.
"""
# construct A(w), B(w), C(w), and D(w) of normalized transfer function
num_flip = num[::-1] / num[-1]
den_flip = den[::-1] / den[-1]
avec = np.copy(num_flip)
bvec = np.copy(num_flip)
cvec = np.copy(den_flip)
dvec = np.copy(den_flip)
avec[1::2] = 0
avec[2::4] *= -1
bvec[0::2] = 0
bvec[3::4] *= -1
cvec[1::2] = 0
cvec[2::4] *= -1
dvec[0::2] = 0
dvec[3::4] *= -1
apoly = np.poly1d(avec[::-1])
bpoly = np.poly1d(bvec[::-1])
cpoly = np.poly1d(cvec[::-1])
dpoly = np.poly1d(dvec[::-1])
# solve for w_phase/w_gain
poly = apoly**2 + bpoly**2 - (cpoly**2 + dpoly**2) / 2 # type: np.poly1d
w_ans = None
for root in poly.roots:
root_real = float(root.real)
if abs(root.imag) < atol < root_real and (w_ans is None or root_real < w_ans):
w_ans = root_real
return w_ans
def get_stability_margins(num, den, rtol=1e-8, atol=1e-8):
# type: (np.multiarray.ndarray, np.multiarray.ndarray, float, float) -> Tuple[float, float]
"""Given the numerator and denominator of the transfer function, compute phase and gain margins.
Parameters
----------
num : np.multiarray.ndarray
the numerator polynomial coefficients array. index 0 is coefficient for highest term.
den : np.multiarray.ndarray
the denominator polynomial coefficients array. index 0 is coefficient for highest term.
rtol : float
relative tolerance. Used to check if two frequencies are equal.
atol : float
absolute tolerance. Used to check a number is equal to 0.
Returns
-------
phase_margin : float
the phase margin in degrees. If the system is unstable, a negative number is returned.
gain_margin : float
the gain margin.
"""
poly_n = np.poly1d(num)
poly_d = np.poly1d(den)
# compute gain margin.
w_phase, w_gain = get_w_crossings(num, den, atol=atol)
if w_gain is None:
gain_margin = float('inf')
else:
gain_margin = abs(poly_d(1j * w_gain) / poly_n(1j * w_gain))
# compute phase margin
if w_phase is None:
# gain never equal to 1. That means gain is always greater than 1 or gain is always less than 1.
dc_gain = poly_n(0) / poly_d(0)
if dc_gain < 1 - max(rtol, atol):
# gain is always less than 1, infinite phase margin
phase_margin = float('inf')
else:
# gain is always greater than 1, unstable
phase_margin = -1
elif w_gain is not None and w_phase > w_gain + max(w_gain * rtol, atol):
# unity gain frequency > 180 degree frequency, we're unstable
phase_margin = -1
else:
phase_margin = np.angle(poly_n(1j * w_phase) / poly_d(1j * w_phase), deg=True) + 180
return phase_margin, gain_margin
================================================
FILE: bag/data/ltv.py
================================================
# -*- coding: utf-8 -*-
"""This module defines functions and classes for linear time-varying circuits data post-processing.
"""
import numpy as np
import scipy.interpolate as interp
import scipy.sparse as sparse
def _even_quotient(a, b, tol=1e-6):
"""Returns a / b if it is an integer, -1 if it is not.."""
num = int(round(a / b))
if abs(a - b * num) < abs(b * tol):
return num
return -1
class LTVImpulseFinite(object):
r"""A class that computes finite impulse response of a linear time-varying circuit.
This class computes the time-varying impulse response based on PSS/PAC simulation
data, and provides several useful query methods. Your simulation should be set up
as follows:
#. Setup PSS as usual. We will denote system period as tper and fc = 1/tper.
#. In PAC, set the maxmimum sidebands to m.
#. In PAC, set the input frequency sweep to be absolute, and sweep from 0 to
n * fstep in steps of fstep, where fstep = fc / k for some integer k.
k should be chosen so that the output settles back to 0 after time k * tper. k
should also be chosen such that fstep is a nice round frequency. Otherwise,
numerical errors may introduce strange results.
n should be chosen so that n * fstep is sufficiently large compared to system
bandwidth.
#. In PAC options, set the freqaxis option to be "in".
#. After simulation, PAC should save the output frequency response as a function of
output harmonic number and input frequency. Post-process this into a complex 2D
matrix hmat with shape (2 * m + 1, n + 1), and pass it to this class's constructor.
Parameters
----------
hmat : np.ndarray
the PAC simulation data matrix with shape (2 * m + 1, n + 1).
hmat[a + m, b] is the complex AC gain from input frequency b * fc / k
to output frequency a * fc + b * fc / k.
m : int
number of output sidebands.
n : int
number of input frequencies.
tper : float
the system period, in seconds.
k : int
the ratio between period of the input impulse train and the system period.
Must be an integer.
out0 : :class:`numpy.ndarray`
steady-state output transient waveform with 0 input over 1 period. This should
be a two-column array, where the first column is time vector and second column
is the output. Used to compute transient response.
Notes
-----
This class uses the algorithm described in [1]_ to compute impulse response from PSS/PAC
simulation data. The impulse response :math:`h(t, \tau)` satisfies the following equation:
.. math:: y(t) = \int_{-\infty}^{\infty} h(t, \tau) \cdot x(\tau)\ d\tau
Intuitively, :math:`h(t, \tau)` represents the output at time :math:`t` subject to
an impulse at time :math:`\tau`. As described in the paper, If :math:`w_c` is the system
frequency, and :math:`H_m(jw)` is the frequency response of the system at :math:`mw_c + w`
due to an input sinusoid with frequency :math:`w`, then the impulse response can be calculated as:
.. math::
h(t, \tau) = \frac{1}{kT}\sum_{n=-\infty}^{\infty}\sum_{m=-\infty}^{\infty}
H_m\left (j\dfrac{nw_c}{k}\right) \exp \left[ jmw_ct + j\dfrac{nw_c}{k} (t - \tau)\right]
where :math:`0 \le \tau < T` and :math:`\tau \le t \le \tau + kT`.
References
----------
.. [1] J. Kim, B. S. Leibowitz and M. Jeeradit, "Impulse sensitivity function analysis of
periodic circuits," 2008 IEEE/ACM International Conference on Computer-Aided Design,
San Jose, CA, 2008, pp. 386-391.
.. automethod:: __call__
"""
def __init__(self, hmat, m, n, tper, k, out0):
hmat = np.asarray(hmat)
if hmat.shape != (2 * m + 1, n + 1):
raise ValueError('hmat shape = %s not compatible with M=%d, N=%d' %
(hmat.shape, m, n))
# use symmetry to fill in negative input frequency data.
fullh = np.empty((2 * m + 1, 2 * n + 1), dtype=complex)
fullh[:, n:] = hmat / (k * tper)
fullh[:, :n] = np.fliplr(np.flipud(fullh[:, n + 1:])).conj()
self.hmat = fullh
wc = 2.0 * np.pi / tper
self.m_col = np.arange(-m, m + 1) * (1.0j * wc)
self.n_col = np.arange(-n, n + 1) * (1.0j * wc / k)
self.m_col = self.m_col.reshape((-1, 1))
self.n_col = self.n_col.reshape((-1, 1))
self.tper = tper
self.k = k
self.outfun = interp.interp1d(out0[:, 0], out0[:, 1], bounds_error=True,
assume_sorted=True)
@staticmethod
def _print_debug_msg(result):
res_imag = np.imag(result).flatten()
res_real = np.real(result).flatten()
res_ratio = np.abs(res_imag / (res_real + 1e-18))
idx = np.argmax(res_ratio)
print('max imag/real ratio: %.4g, imag = %.4g, real = %.4g' %
(res_ratio[idx], res_imag[idx], res_real[idx]))
def __call__(self, t, tau, debug=False):
"""Calculate h(t, tau).
Compute h(t, tau), which is the output at t subject to an impulse
at time tau. standard numpy broadcasting rules apply.
Parameters
----------
t : array-like
the output time.
tau : array-like
the input impulse time.
debug : bool
True to print debug messages.
Returns
-------
val : :class:`numpy.ndarray`
the time-varying impulse response evaluated at the given coordinates.
"""
# broadcast arguments to same shape
t, tau = np.broadcast_arrays(t, tau)
# compute impulse using efficient matrix multiply and numpy broadcasting.
dt = t - tau
zero_indices = (dt < 0) | (dt > self.k * self.tper)
t_row = t.reshape((1, -1))
dt_row = dt.reshape((1, -1))
tmp = np.dot(self.hmat, np.exp(np.dot(self.n_col, dt_row))) * np.exp(np.dot(self.m_col, t_row))
result = np.sum(tmp, axis=0).reshape(dt.shape)
# zero element such that dt < 0 or dt > k * T.
result[zero_indices] = 0.0
if debug:
self._print_debug_msg(result)
# discard imaginary part
return np.real(result)
def _get_core(self, num_points, debug=False):
"""Returns h(dt, tau) matrix and output waveform over 1 period. Used by lsim.
Compute h(dt, tau) for 0 <= tau < T and 0 <= dt < kT, where dt = t - tau.
"""
dt_vec = np.linspace(0.0, self.k * self.tper, self.k * num_points, endpoint=False) # type: np.ndarray
tvec_per = dt_vec[:num_points]
tau_col = tvec_per.reshape((-1, 1))
dt_row = dt_vec.reshape((1, -1))
# use matrix multiply to sum across n
tmp = np.dot(self.hmat, np.exp(np.dot(self.n_col, dt_row)))
# use broadcast multiply for exp(-jwm*(t-tau)) term
tmp = tmp * np.exp(np.dot(self.m_col, dt_row))
# use matrix multiply to sum across m
result = np.dot(np.exp(np.dot(tau_col, self.m_col.T)), tmp).T
if debug:
self._print_debug_msg(result)
# discard imaginary part
result = np.real(result)
# compute output waveform
wvfm = self.outfun(tvec_per)
return result, wvfm
def visualize(self, fig_idx, num_points, num_period,
plot_color=True, plot_3d=False, show=True):
"""Visualize the time-varying impulse response.
Parameters
----------
fig_idx : int
starting figure index.
num_points : int
number of sample points in a period.
num_period : int
number of output period.
plot_color : bool
True to create a plot of the time-varying impulse response as 2D color plot.
plot_3d : bool
True to create a 3D plot of the impulse response.
show : bool
True to show the plots immediately. Set to False if you want to create some
other plots.
"""
if not plot_color and not plot_3d:
# do nothing.
return
tot_points = num_period * num_points
tau_vec = np.linspace(0, self.tper, num_points, endpoint=False)
dt_vec = np.linspace(0, num_period * self.tper, tot_points, endpoint=False)
dt, tau = np.meshgrid(dt_vec, tau_vec, indexing='ij', copy=False)
t = tau + dt
result, _ = self._get_core(num_points)
result = result[:num_period * num_points, :]
import matplotlib.pyplot as plt
from matplotlib import cm
if plot_color:
# plot 2D color
fig = plt.figure(fig_idx)
fig_idx += 1
ax = fig.gca()
cp = ax.pcolor(t, tau, result, cmap=cm.cubehelix)
plt.colorbar(cp)
ax.set_title('Impulse response contours')
ax.set_ylabel('impulse time')
ax.set_xlabel('output time')
if plot_3d:
# plot 3D impulse response
# noinspection PyUnresolvedReferences
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(fig_idx)
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(t, tau, result, rstride=1, cstride=1, linewidth=0, cmap=cm.cubehelix)
ax.set_title('Impulse response')
ax.set_ylabel('impulse time')
ax.set_xlabel('output time')
if show:
plt.show()
def lsim(self, u, tstep, tstart=0.0, ac_only=False, periodic=False, debug=False):
r"""Compute the output waveform given input waveform.
This method assumes zero initial state. The output waveform will be the
same length as the input waveform, so pad zeros if necessary.
Parameters
----------
u : array-like
the input waveform.
tstep : float
the input/output time step, in seconds. Must evenly divide system period.
tstart : float
the time corresponding to u[0]. Assume u = 0 for all time before tstart.
Defaults to 0.
ac_only : bool
Return output waveform due to AC input only and without steady-state
transient.
periodic : bool
True if the input is periodic. If so, returns steady state output.
debug : bool
True to print debug messages.
Returns
-------
y : :class:`numpy.ndarray`
the output waveform.
Notes
-----
This method computes the integral:
.. math:: y(t) = \int_{-\infty}^{\infty} h(t, \tau) \cdot x(\tau)\ d\tau
using the following algorithm:
#. set :math:`d\tau = \texttt{tstep}`.
#. Compute :math:`h(\tau + dt, \tau)` for :math:`0 \le dt < kT` and
:math:`0 \le \tau < T`, then express as a kN-by-N matrix. This matrix
completely describes the time-varying impulse response.
#. tile the impulse response matrix horizontally until its number of columns
matches input signal length, then multiply column i by u[i].
#. Compute y as the sum of all anti-diagonals of the matrix computed in
previous step, multiplied by :math:`d\tau`. Truncate if necessary.
"""
u = np.asarray(u)
nstep = _even_quotient(self.tper, tstep)
ndelay = _even_quotient(tstart, tstep)
# error checking
if len(u.shape) != 1:
raise ValueError('u must be a 1D array.')
if nstep < 0:
raise ValueError('Time step = %.4g does not evenly divide'
'System period = %.4g' % (tstep, self.tper))
if ndelay < 0:
raise ValueError('Time step = %.4g does not evenly divide'
'Startimg time = %.4g' % (tstep, tstart))
if periodic and nstep != u.size:
raise ValueError('Periodic waveform must have same period as system period.')
# calculate and tile hcore
ntot = u.size
hcore, outwv = self._get_core(nstep, debug=debug)
hcore = np.roll(hcore, -ndelay, axis=1)
outwv = np.roll(outwv, -ndelay)
if periodic:
# input periodic; more efficient math.
hcore *= u
hcore = np.tile(hcore, (1, self.k + 1))
y = np.bincount(np.sum(np.indices(hcore.shape), axis=0).flat, hcore.flat)
y = y[self.k * nstep:(self.k + 1) * nstep] * tstep
else:
ntile = int(np.ceil(ntot * 1.0 / nstep))
hcore = np.tile(hcore, (1, ntile))
outwv = np.tile(outwv, (ntile,))
hcore = hcore[:, :ntot]
outwv = outwv[:ntot]
# broadcast multiply
hcore *= u
# magic code from stackoverflow
# returns an array of the sums of all anti-diagonals.
y = np.bincount(np.sum(np.indices(hcore.shape), axis=0).flat, hcore.flat)[:ntot] * tstep
if not ac_only:
# add output steady state transient
y += outwv
return y
def lsim_digital(self, tsym, tstep, data, pulse, tstart=0.0, nchain=1, tdelta=0.0, **kwargs):
"""Compute output waveform given input pulse shape and data.
This method is similar to :func:`~bag.data.ltv.LTVImpulseFinite.lsim`, but
assumes the input is superposition of shifted and scaled copies of a given
pulse waveform. This assumption speeds up the computation and is useful
for high speed link design.
Parameters
----------
tsym : float
the symbol period, in seconds. Must evenly divide system period.
tstep : float
the output time step, in seconds. Must evenly divide symbol period.
data : list[float]
list of symbol values.
pulse : np.ndarray
the pulse waveform as a two-column array. The first column is time,
second column is pulse waveform value. Linear interpolation will be used
if necessary. Time must start at 0.0 and be increasing.
tstart : float
time of the first data symbol. Defaults to 0.0
nchain : int
number of blocks in a chain. Defaults to 1. This argument is useful if
you have multiple blocks cascaded together in a chain, and you wish to find
the output waveform at the end of the chain.
tdelta : float
time difference between adjacent elements in a chain. Defaults to 0. This
argument is useful for simulating a chain of latches, where blocks operate
on alternate phases of the clock.
kwargs : dict[str, any]
additional keyword arguments for :func:`~bag.data.ltv.LTVImpulseFinite.lsim`.
Returns
-------
output : :class:`numpy.ndarray`
the output waveform over N symbol period, where N is the given data length.
"""
# check tsym evenly divides system period
nsym = _even_quotient(self.tper, tsym)
if nsym < 0:
raise ValueError('Symbol period %.4g does not evenly divide '
'system period %.4g' % (tsym, self.tper))
# check tstep evenly divides tsym
nstep = _even_quotient(tsym, tstep)
if nstep < 0:
raise ValueError('Time step %.4g does not evenly divide '
'symbol period %.4g' % (tstep, tsym))
# check tstep evenly divides tstart
ndelay = _even_quotient(tstart, tstep)
if ndelay < 0:
raise ValueError('Time step %.4g does not evenly divide '
'starting time %.4g' % (tstep, tstart))
nper = nstep * nsym
pulse = np.asarray(pulse)
tvec = pulse[:, 0]
pvec = pulse[:, 1]
# find input length
# noinspection PyUnresolvedReferences
nlast = min(np.nonzero(pvec)[0][-1] + 1, tvec.size - 1)
tlast = tvec[nlast]
ntot = int(np.ceil(tlast / tstep)) + nchain * self.k * nper + nstep * (nsym - 1)
# interpolate input
pfun = interp.interp1d(tvec, pvec, kind='linear', copy=False, bounds_error=False,
fill_value=0.0, assume_sorted=True)
tin = np.linspace(0.0, ntot * tstep, ntot, endpoint=False)
pin = pfun(tin)
# super-impose pulse responses
num_out = len(data) * nstep
output = np.zeros(num_out)
for idx in range(nsym):
# get output pulse response
pout = pin
for j in range(nchain):
pout = self.lsim(pout, tstep, tstart=tstart + j * tdelta, periodic=False,
ac_only=True, **kwargs)
# construct superposition matrix
cur_data = data[idx::nsym]
offsets = np.arange(0, len(cur_data) * nper, nper) * -1
diags = np.tile(cur_data, (ntot, 1)).T
dia_mat = sparse.dia_matrix((diags, offsets), shape=(num_out, ntot))
# superimpose
output += dia_mat.dot(pout)
# shift input pulse.
pin = np.roll(pin, nstep)
# compute output steady state waveform
out_pss = self.outfun(np.linspace(0.0, self.tper, nper, endpoint=False))
out_pss = np.roll(out_pss, -ndelay)
for j in range(1, nchain):
out_pss = self.lsim(out_pss, tstep, tstart=tstart + j * tdelta, periodic=True,
ac_only=False, **kwargs)
ntile = int(np.ceil(num_out * 1.0 / nper))
out_pss = np.tile(out_pss, (ntile,))
output += out_pss[:num_out]
return output
================================================
FILE: bag/data/mos.py
================================================
# -*- coding: utf-8 -*-
"""This module defines classes for computing DC operating point.
"""
from typing import Dict
import numpy as np
def mos_y_to_ss(sim_data, char_freq, fg, ibias, cfit_method='average'):
# type: (Dict[str, np.ndarray], float, int, np.ndarray, str) -> Dict[str, np.ndarray]
"""Convert transistor Y parameters to small-signal parameters.
This function computes MOSFET small signal parameters from 3-port
Y parameter measurements done on gate, drain and source, with body
bias fixed. This functions fits the Y parameter to a capcitor-only
small signal model using least-mean-square error.
Parameters
----------
sim_data : Dict[str, np.ndarray]
A dictionary of Y parameters values stored as complex numpy arrays.
char_freq : float
the frequency Y parameters are measured at.
fg : int
number of transistor fingers used for the Y parameter measurement.
ibias : np.ndarray
the DC bias current of the transistor. Always positive.
cfit_method : str
method used to extract capacitance from Y parameters. Currently
supports 'average' or 'worst'
Returns
-------
ss_dict : Dict[str, np.ndarray]
A dictionary of small signal parameter values stored as numpy
arrays. These values are normalized to 1-finger transistor.
"""
w = 2 * np.pi * char_freq
gm = (sim_data['y21'].real - sim_data['y31'].real) / 2.0 # type: np.ndarray
gds = (sim_data['y22'].real - sim_data['y32'].real) / 2.0 # type: np.ndarray
gb = (sim_data['y33'].real - sim_data['y23'].real) / 2.0 - gm - gds # type: np.ndarray
cgd12 = -sim_data['y12'].imag / w
cgd21 = -sim_data['y21'].imag / w
cgs13 = -sim_data['y13'].imag / w
cgs31 = -sim_data['y31'].imag / w
cds23 = -sim_data['y23'].imag / w
cds32 = -sim_data['y32'].imag / w
cgg = sim_data['y11'].imag / w
cdd = sim_data['y22'].imag / w
css = sim_data['y33'].imag / w
if cfit_method == 'average':
cgd = (cgd12 + cgd21) / 2 # type: np.ndarray
cgs = (cgs13 + cgs31) / 2 # type: np.ndarray
cds = (cds23 + cds32) / 2 # type: np.ndarray
elif cfit_method == 'worst':
cgd = np.maximum(cgd12, cgd21)
cgs = np.maximum(cgs13, cgs31)
cds = np.maximum(cds23, cds32)
else:
raise ValueError('Unknown cfit_method = %s' % cfit_method)
cgb = cgg - cgd - cgs # type: np.ndarray
cdb = cdd - cds - cgd # type: np.ndarray
csb = css - cgs - cds # type: np.ndarray
ibias = ibias / fg
gm = gm / fg
gds = gds / fg
gb = gb / fg
cgd = cgd / fg
cgs = cgs / fg
cds = cds / fg
cgb = cgb / fg
cdb = cdb / fg
csb = csb / fg
return dict(
ibias=ibias,
gm=gm,
gds=gds,
gb=gb,
cgd=cgd,
cgs=cgs,
cds=cds,
cgb=cgb,
cdb=cdb,
csb=csb,
)
================================================
FILE: bag/data/plot.py
================================================
# -*- coding: utf-8 -*-
"""This module contains utilities to improve waveform plotting in python.
"""
import numpy as np
import scipy.interpolate as interp
from matplotlib.lines import Line2D
from matplotlib.figure import Figure
from matplotlib.text import Annotation
import matplotlib.pyplot as plt
from ..math import float_to_si_string
# Vega category10 palette
color_cycle = ['#1f77b4', '#ff7f0e',
'#2ca02c', '#d62728',
'#9467bd', '#8c564b',
'#e377c2', '#7f7f7f',
'#bcbd22', '#17becf',
]
def figure(fig_id, picker=5.0):
"""Create a WaveformPlotter.
Parameters
----------
fig_id : int
the figure ID.
picker : float
picker event pixel tolerance.
Returns
-------
plotter : bag.data.plot.WaveformPlotter
a plotter that helps you make interactive matplotlib figures.
"""
return WaveformPlotter(fig_id, picker=picker)
def plot_waveforms(xvec, panel_list, fig=1):
"""Plot waveforms in vertical panels with shared X axis.
Parameters
----------
xvec : :class:`numpy.ndarray`
the X data.
panel_list : list[list[(str, :class:`numpy.ndarray`)]]
list of lists of Y data. Each sub-list is one panel. Each element of the sub-list
is a tuple of signal name and signal data.
fig : int
the figure ID.
"""
nrow = len(panel_list)
if nrow > 0:
myfig = plt.figure(fig, FigureClass=MarkerFigure) # type: MarkerFigure
ax0 = None
for idx, panel in enumerate(panel_list):
if ax0 is None:
ax = plt.subplot(nrow, 1, idx + 1)
ax0 = ax
else:
ax = plt.subplot(nrow, 1, idx + 1, sharex=ax0)
for name, sig in panel:
ax.plot(xvec, sig, label=name, picker=5.0)
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.9, box.height])
# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
myfig.setup_callbacks()
plt.show(block=False)
def _fpart(x):
return x - int(x)
def _rfpart(x):
return 1 - _fpart(x)
def draw_line(x0, y0, x1, y1, xmax, grid):
"""Draws an anti-aliased line in img from p1 to p2 with the given color."""
if x0 > x1:
# x1 is wrapped around
x1 += xmax
dx, dy = x1 - x0, y1 - y0
steep = dx < abs(dy)
if steep:
x0, y0, x1, y1, dx, dy = y0, x0, y1, x1, dy, dx
gradient = dy * 1.0 / dx
# handle first endpoint
xpxl1 = int(x0 + 0.5)
yend = y0 + gradient * (xpxl1 - x0)
xgap = _rfpart(x0 + 0.5)
ypxl1 = int(yend)
if steep:
grid[ypxl1 % xmax, xpxl1] += _rfpart(yend) * xgap
grid[(ypxl1 + 1) % xmax, xpxl1] += _fpart(yend) * xgap
else:
grid[xpxl1 % xmax, ypxl1] += _rfpart(yend) * xgap
grid[xpxl1 % xmax, ypxl1 + 1] += _fpart(yend) * xgap
intery = yend + gradient # first y-intersection for the main loop
# do not color second endpoint to avoid double coloring.
xpxl2 = int(x1 + 0.5)
# main loop
if steep:
for x in range(xpxl1 + 1, xpxl2):
xval = int(intery)
grid[xval % xmax, x] += _rfpart(intery)
grid[(xval + 1) % xmax, x] += _fpart(intery)
intery += gradient
else:
for x in range(xpxl1 + 1, xpxl2):
xval = x % xmax
grid[xval, int(intery)] += _rfpart(intery)
grid[xval, int(intery) + 1] += _fpart(intery)
intery += gradient
def plot_eye_heatmap(fig, tvec, yvec, tper, tstart=None, tend=None, toff=None,
tstep=None, vstep=None,
cmap=None, vmargin=0.05, interpolation='gaussian',
repeat=False):
"""Plot eye diagram heat map.
Parameters
----------
fig : int
the figure ID.
tvec : np.ndarray
the time data.
yvec : np.ndarray
waveform data.
tper : float
the eye period.
tstart : float
starting time. Defaults to first point.
tend : float
ending time. Defaults to last point.
toff : float
eye offset. Defaults to 0.
tstep : float or None
horizontal bin size. Defaults to using 200 bins.
vstep : float or None
vertical bin size. Defaults to using 200 bins.
cmap :
the colormap used for coloring the heat map. If None, defaults to cubehelix_r
vmargin : float
vertical margin in percentage of maximum/minimum waveform values. Defaults
to 5 percent. This is used so that there some room between top/bottom of
eye and the plot.
interpolation : str
interpolation method. Defaults to 'gaussian'. Use 'none' for no interpolation.
repeat : bool
True to repeat the eye diagram once to the right. This is useful if you
want to look at edge transistions.
"""
if not toff:
toff = 0.0
if tstart is None:
tstart = tvec[0]
if tend is None:
tend = tvec[-1]
if tstep is None:
num_h = 200
else:
num_h = int(np.ceil(tper / tstep))
arr_idx = (tstart <= tvec) & (tvec < tend)
tplot = np.mod((tvec[arr_idx] - toff), tper) / tper * num_h # type: np.ndarray
yplot = yvec[arr_idx]
# get vertical range
ymin, ymax = np.amin(yplot), np.amax(yplot)
yrang = (ymax - ymin) * (1 + vmargin)
ymid = (ymin + ymax) / 2.0
ymin = ymid - yrang / 2.0
ymax = ymin + yrang
if vstep is None:
num_v = 200
else:
num_v = int(np.ceil(yrang / vstep))
# rescale Y axis
yplot = (yplot - ymin) / yrang * num_v
grid = np.zeros((num_h, num_v), dtype=float)
for idx in range(yplot.size - 1):
draw_line(tplot[idx], yplot[idx], tplot[idx + 1], yplot[idx + 1], num_h, grid)
if cmap is None:
from matplotlib import cm
# noinspection PyUnresolvedReferences
cmap = cm.cubehelix_r
plt.figure(fig)
grid = grid.T[::-1, :]
if repeat:
grid = np.tile(grid, (1, 2))
tper *= 2.0
plt.imshow(grid, extent=[0, tper, ymin, ymax], cmap=cmap,
interpolation=interpolation, aspect='auto')
cb = plt.colorbar()
cb.set_label('counts')
return grid
def plot_eye(fig, tvec, yvec_list, tper, tstart=None, tend=None,
toff_list=None, name_list=None, alpha=1.0):
"""Plot eye diagram.
Parameters
----------
fig : int
the figure ID.
tvec : np.ndarray
the time data.
yvec_list : list[np.ndarray]
list of waveforms to plot in eye diagram.
tper : float
the period.
tstart : float
starting time. Defaults to first point.
tend : float
ending time. Defaults to last point.
toff_list : list[float]
offset to apply to each waveform. Defaults to zeros.
name_list : list[str] or None
the name of each waveform. Defaults to numbers.
alpha : float
the transparency of each trace. Can be used to mimic heatmap.
"""
if not yvec_list:
return
if not name_list:
name_list = [str(num) for num in range(len(yvec_list))]
if not toff_list:
toff_list = [0.0] * len(yvec_list)
if tstart is None:
tstart = tvec[0]
if tend is None:
tend = tvec[-1]
# get new tstep that evenly divides tper and new x vector
tstep_given = (tvec[-1] - tvec[0]) / (tvec.size - 1)
num_samp = int(round(tper / tstep_given))
t_plot = np.linspace(0.0, tper, num_samp, endpoint=False)
# find tstart and tend in number of tper.
nstart = int(np.floor(tstart / tper))
nend = int(np.ceil(tend / tper))
ncycle = nend - nstart
teye = np.linspace(nstart * tper, nend * tper, num_samp * ncycle, endpoint=False) # type: np.ndarray
teye = teye.reshape((ncycle, num_samp))
myfig = plt.figure(fig, FigureClass=MarkerFigure) # type: MarkerFigure
ax = plt.subplot()
legend_lines = []
for idx, yvec in enumerate(yvec_list):
color = color_cycle[idx % len(color_cycle)]
toff = toff_list[idx]
# get eye traces
yfun = interp.interp1d(tvec - toff, yvec, kind='linear', copy=False, bounds_error=False,
fill_value=np.nan, assume_sorted=True)
plot_list = []
for cycle_idx in range(ncycle):
plot_list.append(t_plot)
plot_list.append(yfun(teye[cycle_idx, :]))
lines = ax.plot(*plot_list, alpha=alpha, color=color, picker=4.0, linewidth=2)
legend_lines.append(lines[0])
# Put a legend to the right of the current axis
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.9, box.height])
ax.legend(legend_lines, name_list, loc='center left', bbox_to_anchor=(1, 0.5))
myfig.setup_callbacks()
plt.show(block=False)
def _find_closest_point(x, y, xvec, yvec, xnorm, ynorm):
"""Find point on PWL waveform described by xvec, yvec closest to (x, y)"""
xnvec = xvec / xnorm
ynvec = yvec / ynorm
xn = x / xnorm
yn = y / ynorm
dx = np.diff(xnvec)
dy = np.diff(ynvec)
px = (xn - xnvec[:-1])
py = (yn - ynvec[:-1])
that = (px * dx + py * dy) / (dx ** 2 + dy ** 2)
t = np.minimum(np.maximum(that, 0), 1)
minx = xnvec[:-1] + t * dx
miny = ynvec[:-1] + t * dy
dist = (minx - xn) ** 2 + (miny - yn) ** 2
idx = np.argmin(dist)
return minx[idx] * xnorm, miny[idx] * ynorm
class WaveformPlotter(object):
"""A custom matplotlib interactive plotting class.
This class adds many useful features, such as ability to add/remove markers,
ability to toggle waveforms on and off, and so on.
Parameters
----------
fig_idx : int
the figure index.
picker : float
picker event pixel tolerance.
normal_width : float
normal linewidth.
select_width : float
selected linewidth.
"""
def __init__(self, fig_idx, picker=5.0, normal_width=1.5, select_width=3.0):
self.figure = plt.figure(fig_idx, FigureClass=MarkerFigure) # type: MarkerFigure
self.picker = picker
self.norm_lw = normal_width
self.top_lw = select_width
self.ax = self.figure.gca()
self.ax.set_prop_cycle('color', color_cycle)
self.leline_lookup = {}
self.letext_lookup = {}
self.last_top = None
self.legend = None
self.resized_legend = False
def plot(self, *args, **kwargs):
if self.figure is None:
raise ValueError('figure closed already')
if 'picker' not in kwargs:
kwargs['picker'] = self.picker
kwargs['linewidth'] = self.norm_lw
if 'lw' in kwargs:
del kwargs['lw']
return self.ax.plot(*args, **kwargs)
def setup(self):
if self.figure is None:
raise ValueError('figure closed already')
self.figure.tight_layout()
# Put a legend to the right of the current axis
ax_lines, ax_labels = self.ax.get_legend_handles_labels()
self.legend = self.ax.legend(ax_lines, ax_labels, loc='center left',
bbox_to_anchor=(1, 0.5), fancybox=True)
le_lines = self.legend.get_lines()
le_texts = self.legend.get_texts()
for leline, letext, axline in zip(le_lines, le_texts, ax_lines):
self.leline_lookup[leline] = (letext, axline)
self.letext_lookup[letext] = (leline, axline)
leline.set_picker(self.picker)
letext.set_picker(self.picker)
letext.set_alpha(0.5)
le_texts[-1].set_alpha(1.0)
ax_lines[-1].set_zorder(2)
ax_lines[-1].set_linewidth(self.top_lw)
self.last_top = (le_texts[-1], ax_lines[-1])
self.figure.register_pick_event(self.leline_lookup, self.legend_line_picked)
self.figure.register_pick_event(self.letext_lookup, self.legend_text_picked)
self.figure.setup_callbacks()
self.figure.canvas.mpl_connect('draw_event', self.fix_legend_location)
self.figure.canvas.mpl_connect('close_event', self.figure_closed)
self.figure.canvas.mpl_connect('resize_event', self.figure_resized)
# noinspection PyUnusedLocal
def figure_closed(self, event):
self.figure.close_figure()
self.figure = None
self.ax = None
self.leline_lookup = None
self.letext_lookup = None
self.last_top = None
self.legend = None
# noinspection PyUnusedLocal
def figure_resized(self, event):
self.resized_legend = False
self.fix_legend_location(None)
# noinspection PyUnusedLocal
def fix_legend_location(self, event):
if not self.resized_legend:
self.figure.tight_layout()
inv_tran = self.figure.transFigure.inverted()
leg_box = inv_tran.transform(self.legend.get_window_extent())
leg_width = leg_box[1][0] - leg_box[0][0]
box = self.ax.get_position()
# print box.x0, box.y0, box.width, box.height, leg_width, leg_frame.get_height()
self.ax.set_position([box.x0, box.y0, box.width - leg_width, box.height])
self.resized_legend = True
self.figure.canvas.draw()
def legend_line_picked(self, artist):
letext, axline = self.leline_lookup[artist]
visible = not axline.get_visible()
if visible:
artist.set_alpha(1.0)
else:
artist.set_alpha(0.2)
if visible and (self.last_top[1] is not axline):
# set to be top line
self.legend_text_picked(letext, draw=False)
self.figure.set_line_visibility(axline, visible)
def legend_text_picked(self, artist, draw=True):
leline, axline = self.letext_lookup[artist]
self.last_top[0].set_alpha(0.5)
self.last_top[1].set_zorder(1)
self.last_top[1].set_linewidth(self.norm_lw)
axline.set_zorder(2)
artist.set_alpha(1.0)
axline.set_linewidth(self.top_lw)
self.last_top = (artist, axline)
# if draw is False, this method is not called from
# legend_line_picked(), so we'll never have recursion issues.
if draw:
if not axline.get_visible():
# set line to be visible if not
# draw() will be called in legend_line_picked
self.legend_line_picked(leline)
else:
self.figure.canvas.draw()
# noinspection PyAbstractClass
class MarkerFigure(Figure):
def __init__(self, **kwargs):
Figure.__init__(self, **kwargs)
self.markers = []
self.epsilon = 10.0
self.drag_idx = -1
self.timer = None
self.marker_line_info = None
self.pick_sets = []
self.pick_funs = []
def set_line_visibility(self, axline, visible):
axline.set_visible(visible)
if not visible:
# delete all markers on this line
del_idx_list = [idx for idx, item in enumerate(self.markers) if item[2] is axline]
for targ_idx in reversed(del_idx_list):
an, pt, _, _ = self.markers[targ_idx]
del self.markers[targ_idx]
# print targ_idx, an
an.set_visible(False)
pt.set_visible(False)
self.canvas.draw()
def register_pick_event(self, artist_set, fun):
self.pick_sets.append(artist_set)
self.pick_funs.append(fun)
def on_button_release(self, event):
"""Disable data cursor dragging. """
if event.button == 1:
self.drag_idx = -1
def on_motion(self, event):
"""Move data cursor around. """
ax = event.inaxes
if self.drag_idx >= 0 and ax is not None and event.button == 1:
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
anno, pt, line, bg = self.markers[self.drag_idx]
x, y = _find_closest_point(event.xdata, event.ydata,
line.get_xdata(), line.get_ydata(),
xmax - xmin, ymax - ymin)
pt.set_data([x], [y])
xstr, ystr = float_to_si_string(x, 4), float_to_si_string(y, 4)
anno.set_text('x: %s\ny: %s' % (xstr, ystr))
anno.xy = (x, y)
self.canvas.restore_region(bg)
anno.set_visible(True)
pt.set_visible(True)
ax.draw_artist(anno)
ax.draw_artist(pt)
self.canvas.blit(ax.bbox)
def _get_idx_under_point(self, event):
"""Find selected data cursor."""
mx = event.x
my = event.y
mind = None
minidx = None
# find closest marker point
for idx, (an, pt, _, _) in enumerate(self.markers):
xv, yv = pt.get_xdata()[0], pt.get_ydata()[0]
xp, yp = event.inaxes.transData.transform([xv, yv])
# print xv, yv, xp, yp, mx, my
d = ((mx - xp) ** 2 + (my - yp) ** 2) ** 0.5
if mind is None or d < mind:
mind = d
minidx = idx
if mind is not None and mind < self.epsilon:
return minidx
return -1
def on_pick(self, event):
artist = event.artist
if not artist.get_visible():
return
for idx, artist_set in enumerate(self.pick_sets):
if artist in artist_set:
self.pick_funs[idx](artist)
return
if isinstance(artist, Line2D):
mevent = event.mouseevent
# figure out if we picked marker or line
self.drag_idx = self._get_idx_under_point(mevent)
if self.drag_idx >= 0:
# picked marker.
ax = mevent.inaxes
an, pt, _, _ = self.markers[self.drag_idx]
an.set_visible(False)
pt.set_visible(False)
self.canvas.draw()
self.markers[self.drag_idx][-1] = self.canvas.copy_from_bbox(ax.bbox)
an.set_visible(True)
pt.set_visible(True)
ax.draw_artist(an)
ax.draw_artist(pt)
self.canvas.blit(ax.bbox)
else:
# save data to plot marker later
mxval = mevent.xdata
button = mevent.button
if mxval is not None and button == 1 and not self.marker_line_info:
self.marker_line_info = (artist, mxval, mevent.ydata,
button, mevent.inaxes)
elif isinstance(artist, Annotation):
# delete marker.
mevent = event.mouseevent
if mevent.button == 3:
targ_idx = None
for idx, (an, pt, _, _) in enumerate(self.markers):
if an is artist:
targ_idx = idx
break
if targ_idx is not None:
an, pt, _, _ = self.markers[targ_idx]
del self.markers[targ_idx]
an.set_visible(False)
pt.set_visible(False)
self.canvas.draw()
def _create_marker(self):
if self.marker_line_info:
artist, mxval, myval, button, ax = self.marker_line_info
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
mxval, myval = _find_closest_point(mxval, myval,
artist.get_xdata(), artist.get_ydata(),
xmax - xmin, ymax - ymin)
pt = ax.plot(mxval, myval, 'ko', picker=5.0)[0]
xstr, ystr = float_to_si_string(mxval, 4), float_to_si_string(myval, 4)
msg = 'x: %s\ny: %s' % (xstr, ystr)
anno = ax.annotate(msg, xy=(mxval, myval), bbox=dict(boxstyle='round', fc='yellow', alpha=0.3),
arrowprops=dict(arrowstyle="->"))
anno.draggable()
anno.set_picker(True)
self.markers.append([anno, pt, artist, None])
ax.draw_artist(anno)
ax.draw_artist(pt)
self.canvas.blit(ax.bbox)
self.marker_line_info = None
def close_figure(self):
self.timer.stop()
def setup_callbacks(self):
self.canvas.mpl_connect('pick_event', self.on_pick)
self.canvas.mpl_connect('motion_notify_event', self.on_motion)
self.canvas.mpl_connect('button_release_event', self.on_button_release)
# use timer to make sure we won't create multiple markers at once when
# clicked on overlapping lines.
self.timer = self.canvas.new_timer(interval=100)
self.timer.add_callback(self._create_marker)
self.timer.start()
================================================
FILE: bag/design/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: bag/design/__init__.py
================================================
# -*- coding: utf-8 -*-
"""This package defines design template classes.
"""
from .module import Module, ModuleDB, SchInstance, MosModuleBase, ResPhysicalModuleBase, ResMetalModule
__all__ = ['Module', 'ModuleDB', 'SchInstance', 'MosModuleBase', 'ResPhysicalModuleBase', 'ResMetalModule']
================================================
FILE: bag/design/module.py
================================================
# -*- coding: utf-8 -*-
"""This module defines base design module class and primitive design classes.
"""
import os
import abc
from typing import TYPE_CHECKING, List, Dict, Optional, Tuple, Any, Type, Set, Sequence, \
Callable, Union
from ..math import float_to_si_string
from ..io import read_yaml
from ..util.cache import DesignMaster, MasterDB
if TYPE_CHECKING:
from ..core import BagProject
from ..layout.core import TechInfo
class ModuleDB(MasterDB):
"""A database of all modules.
This class is responsible for keeping track of module libraries and
creating new modules.
Parameters
----------
lib_defs : str
path to the design library definition file.
tech_info : TechInfo
the TechInfo instance.
sch_exc_libs : List[str]
list of libraries that are excluded from import.
prj : Optional[BagProject]
the BagProject instance.
name_prefix : str
generated layout name prefix.
name_suffix : str
generated layout name suffix.
lib_path : str
path to create generated library in.
"""
def __init__(self, lib_defs, tech_info, sch_exc_libs, prj=None, name_prefix='',
name_suffix='', lib_path=''):
# type: (str, TechInfo, List[str], Optional[BagProject], str, str, str) -> None
MasterDB.__init__(self, '', lib_defs=lib_defs, name_prefix=name_prefix,
name_suffix=name_suffix)
self._prj = prj
self._tech_info = tech_info
self._exc_libs = set(sch_exc_libs)
self.lib_path = lib_path
def create_master_instance(self, gen_cls, lib_name, params, used_cell_names, **kwargs):
# type: (Type[Module], str, Dict[str, Any], Set[str], **Any) -> Module
"""Create a new non-finalized master instance.
This instance is used to determine if we created this instance before.
Parameters
----------
gen_cls : Type[Module]
the generator Python class.
lib_name : str
generated instance library name.
params : Dict[str, Any]
instance parameters dictionary.
used_cell_names : Set[str]
a set of all used cell names.
**kwargs : Any
optional arguments for the generator.
Returns
-------
master : Module
the non-finalized generated instance.
"""
kwargs = kwargs.copy()
kwargs['lib_name'] = lib_name
kwargs['params'] = params
kwargs['used_names'] = used_cell_names
# noinspection PyTypeChecker
return gen_cls(self, **kwargs)
def create_masters_in_db(self, lib_name, content_list, debug=False):
# type: (str, Sequence[Any], bool) -> None
"""Create the masters in the design database.
Parameters
----------
lib_name : str
library to create the designs in.
content_list : Sequence[Any]
a list of the master contents. Must be created in this order.
debug : bool
True to print debug messages
"""
if self._prj is None:
raise ValueError('BagProject is not defined.')
self._prj.instantiate_schematic(lib_name, content_list, lib_path=self.lib_path)
@property
def tech_info(self):
# type: () -> TechInfo
"""the :class:`~bag.layout.core.TechInfo` instance."""
return self._tech_info
def is_lib_excluded(self, lib_name):
# type: (str) -> bool
"""Returns true if the given schematic library does not contain generators.
Parameters
----------
lib_name : str
library name
Returns
-------
is_excluded : bool
True if given library is excluded.
"""
return lib_name in self._exc_libs
class SchInstance(object):
"""A class representing a schematic instance.
Parameters
----------
database : ModuleDB
the schematic generator database.
gen_lib_name : str
the schematic generator library name.
gen_cell_name : str
the schematic generator cell name.
inst_name : str
name of this instance.
static : bool
True if the schematic generator is static.
connections : Optional[Dict[str, str]]
If given, initialize instance terminal connections to this dictionary.
master : Optional[Module]
If given, set the master of this instance.
parameters : Optional[Dict[str, Any]]
If given, set the instance parameters to this dictionary.
"""
def __init__(self,
database, # type: MasterDB
gen_lib_name, # type: str
gen_cell_name, # type: str
inst_name, # type: str
static=False, # type: bool
connections=None, # type: Optional[Dict[str, str]]
master=None, # type: Optional[Module]
parameters=None, # type: Optional[Dict[str, Any]]
):
# type: (...) -> None
self._db = database
self._master = master
self._name = inst_name
self._gen_lib_name = gen_lib_name
self._gen_cell_name = gen_cell_name
self._static = static
self._term_mapping = {} if connections is None else connections
self.parameters = {} if parameters is None else parameters
def change_generator(self, gen_lib_name, gen_cell_name, static=False):
# type: (str, str, bool) -> None
"""Change the master associated with this instance.
All instance parameters and terminal mappings will be reset.
Parameters
----------
gen_lib_name : str
the new schematic generator library name.
gen_cell_name : str
the new schematic generator cell name.
static : bool
True if the schematic generator is static.
"""
self._master = None
self._gen_lib_name = gen_lib_name
self._gen_cell_name = gen_cell_name
self._static = static
self.parameters.clear()
self._term_mapping.clear()
@property
def name(self):
# type: () -> str
"""Returns the instance name."""
return self._name
@property
def connections(self):
# type: () -> Dict[str, str]
"""Returns the instance terminals connection dictionary."""
return self._term_mapping
@property
def is_primitive(self):
# type: () -> bool
"""Returns true if this is an instance of a primitive schematic generator."""
if self._static:
return True
if self._master is None:
raise ValueError('Instance %s has no master. '
'Did you forget to call design()?' % self._name)
return self._master.is_primitive()
@property
def should_delete(self):
# type: () -> bool
"""Returns true if this instance should be deleted."""
return self._master is not None and self._master.should_delete_instance()
@property
def master(self):
# type: () -> Optional[Module]
return self._master
@property
def master_cell_name(self):
# type: () -> str
"""Returns the schematic master cell name."""
return self._gen_cell_name if self._master is None else self._master.cell_name
@property
def master_key(self):
# type: () -> Any
return self._master.key
def copy(self, inst_name, connections=None):
# type: (str, Optional[Dict[str, str]]) -> SchInstance
"""Returns a copy of this SchInstance.
Parameters
----------
inst_name : str
the new instance name.
connections : Optional[Dict[str, str]]
If given, will set the connections of this instance to this dictionary.
Returns
-------
sch_inst : SchInstance
a copy of this SchInstance, with connections potentially updated.
"""
if connections is None:
connections = self._term_mapping.copy()
return SchInstance(self._db, self._gen_lib_name, self._gen_cell_name, inst_name,
static=self._static, connections=connections, master=self._master,
parameters=self.parameters.copy())
def get_master_lib_name(self, impl_lib):
# type: (str) -> str
"""Returns the schematic master library name.
Parameters
----------
impl_lib : str
library where schematic masters will be created.
Returns
-------
master_lib : str
the schematic master library name.
"""
return self._gen_lib_name if self.is_primitive else impl_lib
def design_specs(self, *args, **kwargs):
# type: (*Any, **Any) -> None
"""Update the instance master."""
self._update_master('design_specs', args, kwargs)
def design(self, *args, **kwargs):
# type: (*Any, **Any) -> None
"""Update the instance master."""
self._update_master('design', args, kwargs)
def _update_master(self, design_fun, args, kwargs):
# type: (str, Tuple[Any, ...], Dict[str, Any]) -> None
"""Create a new master."""
if args:
key = 'args'
idx = 1
while key in kwargs:
key = 'args_%d' % idx
idx += 1
kwargs[key] = args
else:
key = None
self._master = self._db.new_master(self._gen_lib_name, self._gen_cell_name,
params=kwargs, design_args=key,
design_fun=design_fun) # type: Module
if self._master.is_primitive():
self.parameters.update(self._master.get_schematic_parameters())
def implement_design(self, lib_name, top_cell_name='', prefix='', suffix='', **kwargs):
# type: (str, str, str, str, **Any) -> None
"""Implement this design module in the given library.
If the given library already exists, this method will not delete or override
any pre-existing cells in that library.
If you use this method, you do not need to call update_structure(),
as this method calls it for you.
This method only works if BagProject is given.
Parameters
----------
lib_name : str
name of the new library to put the generated schematics.
top_cell_name : str
the cell name of the top level design.
prefix : str
prefix to add to cell names.
suffix : str
suffix to add to cell names.
**kwargs : Any
additional arguments.
"""
if 'erase' in kwargs:
print('DEPRECATED WARNING: erase is no longer supported '
'in implement_design() and has no effect')
debug = kwargs.get('debug', False)
rename_dict = kwargs.get('rename_dict', None)
if not top_cell_name:
top_cell_name = None
if 'lib_path' in kwargs:
self._db.lib_path = kwargs['lib_path']
self._db.cell_prefix = prefix
self._db.cell_suffix = suffix
self._db.instantiate_masters([self._master], [top_cell_name], lib_name=lib_name,
debug=debug, rename_dict=rename_dict)
def get_layout_params(self, **kwargs):
# type: (Any) -> Dict[str, Any]
"""Backwards compatibility function."""
if hasattr(self._master, 'get_layout_params'):
return getattr(self._master, 'get_layout_params')(**kwargs)
else:
return kwargs
class Module(DesignMaster, metaclass=abc.ABCMeta):
"""The base class of all schematic generators. This represents a schematic master.
This class defines all the methods needed to implement a design in the CAD database.
Parameters
----------
database : ModuleDB
the design database object.
yaml_fname : str
the netlist information file name.
**kwargs :
additional arguments
Attributes
----------
parameters : dict[str, any]
the design parameters dictionary.
instances : dict[str, None or :class:`~bag.design.Module` or list[:class:`~bag.design.Module`]]
the instance dictionary.
"""
# noinspection PyUnusedLocal
def __init__(self, database, yaml_fname, **kwargs):
# type: (ModuleDB, str, **Any) -> None
lib_name = kwargs['lib_name']
params = kwargs['params']
used_names = kwargs['used_names']
design_fun = kwargs['design_fun']
design_args = kwargs['design_args']
self.tech_info = database.tech_info
self.instances = {} # type: Dict[str, Union[SchInstance, List[SchInstance]]]
self.pin_map = {}
self.new_pins = []
self.parameters = {}
self._pin_list = None
self._yaml_fname = os.path.abspath(yaml_fname)
self.sch_info = read_yaml(self._yaml_fname)
self._orig_lib_name = self.sch_info['lib_name']
self._orig_cell_name = self.sch_info['cell_name']
self._design_fun = design_fun
self._design_args = design_args
# create initial instances and populate instance map
for inst_name, inst_attr in self.sch_info['instances'].items():
lib_name = inst_attr['lib_name']
cell_name = inst_attr['cell_name']
static = database.is_lib_excluded(lib_name)
self.instances[inst_name] = SchInstance(database, lib_name, cell_name, inst_name,
static=static)
# fill in pin map
for pin in self.sch_info['pins']:
self.pin_map[pin] = pin
# initialize schematic master
DesignMaster.__init__(self, database, lib_name, params, used_names)
@property
def pin_list(self):
# type: () -> List[str]
return self._pin_list
@abc.abstractmethod
def design(self, **kwargs):
"""To be overridden by subclasses to design this module.
To design instances of this module, you can
call their :meth:`.design` method or any other ways you coded.
To modify schematic structure, call:
:meth:`.rename_pin`
:meth:`.delete_instance`
:meth:`.replace_instance_master`
:meth:`.reconnect_instance_terminal`
:meth:`.array_instance`
"""
pass
def finalize(self):
# type: () -> None
"""Finalize this master instance.
"""
# invoke design function
fun = getattr(self, self._design_fun)
if self._design_args:
args = self.params.pop(self._design_args)
fun(*args, **self.params)
else:
fun(**self.params)
# backwards compatibility
if self.key is None:
self.params.clear()
self.params.update(self.parameters)
self.update_master_info()
self.children = set()
for inst_list in self.instances.values():
if isinstance(inst_list, SchInstance):
if not inst_list.is_primitive:
self.children.add(inst_list.master_key)
else:
for inst in inst_list:
if not inst.is_primitive:
self.children.add(inst.master_key)
# compute pins
self._pin_list = [pin_name for pin_name, _ in self.new_pins]
self._pin_list.extend((val for val in self.pin_map.values() if val))
# call super finalize routine
super(Module, self).finalize()
@classmethod
def get_params_info(cls):
# type: () -> Optional[Dict[str, str]]
"""Returns a dictionary from parameter names to descriptions.
Returns
-------
param_info : Optional[Dict[str, str]]
dictionary from parameter names to descriptions.
"""
return None
def get_master_basename(self):
# type: () -> str
"""Returns the base name to use for this instance.
Returns
-------
basename : str
the base name for this instance.
"""
return self._orig_cell_name
def get_content(self, lib_name, rename_fun):
# type: (str, Callable[[str], str]) -> Optional[Tuple[Any,...]]
"""Returns the content of this master instance.
Parameters
----------
lib_name : str
the library to create the design masters in.
rename_fun : Callable[[str], str]
a function that renames design masters.
Returns
-------
content : Optional[Tuple[Any,...]]
the master content data structure.
"""
if self.is_primitive():
return None
# populate instance transform mapping dictionary
inst_map = {}
for inst_name, inst_list in self.instances.items():
if isinstance(inst_list, SchInstance):
inst_list = [inst_list]
info_list = []
for inst in inst_list:
if not inst.should_delete:
cur_lib = inst.get_master_lib_name(lib_name)
info_list.append(dict(
name=inst.name,
lib_name=cur_lib,
cell_name= inst.master_cell_name if inst.is_primitive else rename_fun(inst.master_cell_name),
params=inst.parameters,
term_mapping=inst.connections,
))
inst_map[inst_name] = info_list
return (self._orig_lib_name, self._orig_cell_name, rename_fun(self.cell_name),
self.pin_map, inst_map, self.new_pins)
@property
def cell_name(self):
# type: () -> str
"""The master cell name."""
if self.is_primitive():
return self.get_cell_name_from_parameters()
return super(Module, self).cell_name
@property
def orig_cell_name(self):
# type: () -> str
"""The original schematic template cell name."""
return self._orig_cell_name
def is_primitive(self):
# type: () -> bool
"""Returns True if this Module represents a BAG primitive.
NOTE: This method is only used by BAG and schematic primitives. This method prevents
the module from being copied during design implementation. Custom subclasses should
not override this method.
Returns
-------
is_primitive : bool
True if this Module represents a BAG primitive.
"""
return False
def should_delete_instance(self):
# type: () -> bool
"""Returns True if this instance should be deleted based on its parameters.
This method is mainly used to delete 0 finger or 0 width transistors. However,
You can override this method if there exists parameter settings which corresponds
to an empty schematic.
Returns
-------
delete : bool
True if parent should delete this instance.
"""
return False
def get_schematic_parameters(self):
# type: () -> Dict[str, str]
"""Returns the schematic parameter dictionary of this instance.
NOTE: This method is only used by BAG primitives, as they are
implemented with parameterized cells in the CAD database. Custom
subclasses should not override this method.
Returns
-------
params : Dict[str, str]
the schematic parameter dictionary.
"""
return {}
def get_cell_name_from_parameters(self):
"""Returns new cell name based on parameters.
NOTE: This method is only used by BAG primitives. This method
enables a BAG primitive to change the cell master based on
design parameters (e.g. change transistor instance based on the
intent parameter). Custom subclasses should not override this
method.
Returns
-------
cell : str
the cell name based on parameters.
"""
return super(Module, self).cell_name
def rename_pin(self, old_pin, new_pin):
# type: (str, str) -> None
"""Renames an input/output pin of this schematic.
NOTE: Make sure to call :meth:`.reconnect_instance_terminal` so that instances are
connected to the new pin.
Parameters
----------
gitextract_e9aig5le/
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── bag/
│ ├── LICENSE
│ ├── __init__.py
│ ├── concurrent/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── core.py
│ ├── core.py
│ ├── data/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ ├── dc.py
│ │ ├── digital.py
│ │ ├── lti.py
│ │ ├── ltv.py
│ │ ├── mos.py
│ │ └── plot.py
│ ├── design/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── module.py
│ ├── interface/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── database.py
│ │ ├── ocean.py
│ │ ├── server.py
│ │ ├── simulator.py
│ │ ├── skill.py
│ │ ├── templates/
│ │ │ ├── LICENSE
│ │ │ ├── Module.pyi
│ │ │ ├── PrimModule.pyi
│ │ │ ├── calibreview_setup.txt
│ │ │ ├── load_results.ocn
│ │ │ └── run_simulation.ocn
│ │ └── zmqwrapper.py
│ ├── io/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── file.py
│ │ ├── gui.py
│ │ ├── process.py
│ │ ├── sim_data.py
│ │ └── template.py
│ ├── layout/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ ├── digital.py
│ │ ├── objects.py
│ │ ├── routing/
│ │ │ ├── LICENSE
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── fill.py
│ │ │ └── grid.py
│ │ ├── tech.py
│ │ ├── template.py
│ │ └── util.py
│ ├── math/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── dfun.py
│ │ └── interpolate.py
│ ├── mdao/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── components.py
│ │ └── core.py
│ ├── simulation/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ └── core_v2.py
│ ├── tech/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── core.py
│ │ └── mos.py
│ ├── util/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── cache.py
│ │ ├── immutable.py
│ │ ├── interval.py
│ │ ├── parse.py
│ │ └── search.py
│ ├── verification/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── calibre.py
│ │ ├── icv.py
│ │ ├── pvs.py
│ │ ├── templates/
│ │ │ ├── LICENSE
│ │ │ ├── layout_export_config.txt
│ │ │ └── si_env.txt
│ │ └── virtuoso.py
│ └── virtuoso.py
├── docs/
│ ├── .gitignore
│ ├── LICENSE
│ ├── Makefile
│ ├── README
│ ├── refresh_api.sh
│ └── source/
│ ├── LICENSE
│ ├── api/
│ │ ├── LICENSE
│ │ ├── bag.data.rst
│ │ ├── bag.design.rst
│ │ ├── bag.interface.rst
│ │ ├── bag.io.rst
│ │ ├── bag.layout.routing.rst
│ │ ├── bag.layout.rst
│ │ ├── bag.math.rst
│ │ ├── bag.mdao.rst
│ │ ├── bag.rst
│ │ ├── bag.tech.rst
│ │ ├── bag.util.rst
│ │ ├── bag.verification.rst
│ │ └── modules.rst
│ ├── conf.py
│ ├── developer/
│ │ ├── LICENSE
│ │ └── developer.rst
│ ├── index.rst
│ ├── overview/
│ │ ├── LICENSE
│ │ ├── design.rst
│ │ ├── overview.rst
│ │ ├── schematic.rst
│ │ └── testbench.rst
│ ├── setup/
│ │ ├── LICENSE
│ │ ├── bag_config/
│ │ │ ├── LICENSE
│ │ │ ├── bag_config.rst
│ │ │ ├── database/
│ │ │ │ └── database.rst
│ │ │ ├── misc.rst
│ │ │ ├── simulation/
│ │ │ │ └── simulation.rst
│ │ │ └── socket/
│ │ │ └── socket.rst
│ │ ├── config_summary.rst
│ │ ├── install_python.rst
│ │ ├── new_pdk.rst
│ │ ├── pyoptsparse.rst
│ │ ├── setup.rst
│ │ └── tech_config/
│ │ ├── LICENSE
│ │ ├── layout/
│ │ │ └── layout.rst
│ │ ├── misc.rst
│ │ ├── mos/
│ │ │ └── mos.rst
│ │ └── tech_config.rst
│ └── tutorial/
│ ├── LICENSE
│ ├── figures/
│ │ └── LICENSE
│ └── tutorial.rst
├── run_scripts/
│ ├── LICENSE
│ ├── clean_cds_lib.py
│ ├── compile_verilog.il
│ ├── gen_cell.py
│ ├── generate_verilog.py
│ ├── meas_cell.py
│ ├── run_bag.sh
│ ├── setup_submodules.py
│ ├── sim_cell.py
│ ├── start_bag.il
│ ├── start_bag.sh
│ ├── start_bag_ICADV12d3.il
│ └── virt_server.sh
├── setup.py
└── tests/
├── LICENSE
├── __init__.py
└── layout/
├── LICENSE
├── __init__.py
└── routing/
├── LICENSE
├── __init__.py
└── test_fill.py
SYMBOL INDEX (1515 symbols across 62 files)
FILE: bag/concurrent/core.py
function batch_async_task (line 17) | def batch_async_task(coro_list):
class SubProcessManager (line 52) | class SubProcessManager(object):
method __init__ (line 65) | def __init__(self, max_workers=None, cancel_timeout=10.0):
method _kill_subprocess (line 75) | async def _kill_subprocess(self, proc: Optional[Process]) -> None:
method async_new_subprocess (line 105) | async def async_new_subprocess(self,
method async_new_subprocess_flow (line 155) | async def async_new_subprocess_flow(self,
method batch_subprocess (line 220) | def batch_subprocess(self, proc_info_list):
method batch_subprocess_flow (line 253) | def batch_subprocess_flow(self, proc_info_list):
FILE: bag/core.py
function _get_config_file_abspath (line 36) | def _get_config_file_abspath(fname):
function _get_port_number (line 53) | def _get_port_number(port_file):
function _import_class_from_str (line 78) | def _import_class_from_str(class_str):
class Testbench (line 100) | class Testbench(object):
method __init__ (line 133) | def __init__(self, # type: Testbench
method get_defined_simulation_environments (line 158) | def get_defined_simulation_environments(self):
method get_current_simulation_environments (line 163) | def get_current_simulation_environments(self):
method add_output (line 168) | def add_output(self, var, expr):
method set_parameter (line 183) | def set_parameter(self, name, val, precision=6):
method set_env_parameter (line 202) | def set_env_parameter(self, name, val_list, precision=6):
method set_sweep_parameter (line 234) | def set_sweep_parameter(self, name, precision=6, **kwargs):
method set_simulation_environments (line 277) | def set_simulation_environments(self, env_list):
method set_simulation_view (line 290) | def set_simulation_view(self, lib_name, cell_name, sim_view):
method update_testbench (line 311) | def update_testbench(self):
method run_simulation (line 328) | def run_simulation(self, precision=6, sim_tag=None):
method load_sim_results (line 348) | def load_sim_results(self, hist_name, precision=6):
method async_run_simulation (line 368) | async def async_run_simulation(self,
method async_load_results (line 390) | async def async_load_results(self, hist_name: str, precision: int = 6)...
function create_tech_info (line 411) | def create_tech_info(bag_config_path=None):
class BagProject (line 432) | class BagProject(object):
method __init__ (line 454) | def __init__(self, bag_config_path=None, port=None):
method default_lib_path (line 503) | def default_lib_path(self):
method close_bag_server (line 507) | def close_bag_server(self):
method close_sim_server (line 514) | def close_sim_server(self):
method import_design_library (line 521) | def import_design_library(self, lib_name):
method import_sch_cellview (line 536) | def import_sch_cellview(self, lib_name: str, cell_name: str) -> None:
method get_cells_in_library (line 554) | def get_cells_in_library(self, lib_name):
method make_template_db (line 575) | def make_template_db(self, impl_lib, grid_specs, use_cybagoa=True, gds...
method generate_cell (line 606) | def generate_cell(self, # type: BagProject
method replace_dut_in_wrapper (line 752) | def replace_dut_in_wrapper(self, params: Dict[str, Any], dut_lib: str,
method simulate_cell (line 763) | def simulate_cell(self,
method measure_cell (line 951) | def measure_cell(self,
method create_library (line 1021) | def create_library(self, lib_name, lib_path=''):
method create_design_module (line 1038) | def create_design_module(self, lib_name, cell_name, **kwargs):
method new_schematic_instance (line 1058) | def new_schematic_instance(self, lib_name='', cell_name='', params=Non...
method clear_schematic_database (line 1095) | def clear_schematic_database(self):
method instantiate_schematic (line 1100) | def instantiate_schematic(self, lib_name, content_list, lib_path=''):
method batch_schematic (line 1120) | def batch_schematic(self, # type: BagProject
method configure_testbench (line 1156) | def configure_testbench(self, tb_lib, tb_cell):
method load_testbench (line 1183) | def load_testbench(self, tb_lib, tb_cell):
method instantiate_layout_pcell (line 1208) | def instantiate_layout_pcell(self, lib_name, cell_name, inst_lib, inst...
method instantiate_layout (line 1237) | def instantiate_layout(self, lib_name, view_name, via_tech, layout_list):
method release_write_locks (line 1257) | def release_write_locks(self, lib_name, cell_view_list):
method run_lvs (line 1273) | def run_lvs(self, # type: BagProject
method run_rcx (line 1306) | def run_rcx(self, # type: BagProject
method export_layout (line 1357) | def export_layout(self, lib_name, cell_name, out_file, **kwargs):
method batch_export_layout (line 1386) | def batch_export_layout(self, info_list):
method async_run_lvs (line 1421) | async def async_run_lvs(self, lib_name: str, cell_name: str, **kwargs:...
method async_run_rcx (line 1446) | async def async_run_rcx(self, # type: BagProject
method create_schematic_from_netlist (line 1487) | def create_schematic_from_netlist(self, netlist, lib_name, cell_name,
method create_verilog_view (line 1513) | def create_verilog_view(self, verilog_file, lib_name, cell_name, **kwa...
FILE: bag/data/core.py
class Waveform (line 12) | class Waveform(object):
method __init__ (line 31) | def __init__(self, xvec, yvec, xtol, order=3, ext=3):
method xvec (line 40) | def xvec(self):
method yvec (line 45) | def yvec(self):
method order (line 50) | def order(self):
method xtol (line 55) | def xtol(self):
method ext (line 60) | def ext(self):
method __call__ (line 64) | def __call__(self, *arg, **kwargs):
method get_xrange (line 68) | def get_xrange(self):
method shift_by (line 80) | def shift_by(self, xshift):
method get_all_crossings (line 95) | def get_all_crossings(self, threshold, start=None, stop=None, edge='bo...
method get_crossing (line 158) | def get_crossing(self, threshold, start=None, stop=None, n=1, edge='bo...
method to_arrays (line 184) | def to_arrays(self, xmin=None, xmax=None):
method get_eye_specs (line 214) | def get_eye_specs(self, tbit, tsample, thres=0.0, nlev=2):
method _add_xy (line 306) | def _add_xy(self, other):
method __add__ (line 316) | def __add__(self, other):
method __neg__ (line 326) | def __neg__(self):
method __mul__ (line 329) | def __mul__(self, scale):
method __rmul__ (line 334) | def __rmul__(self, scale):
FILE: bag/data/dc.py
class DCCircuit (line 15) | class DCCircuit(object):
method __init__ (line 26) | def __init__(self, ndb, pdb):
method _get_node_id (line 36) | def _get_node_id(self, name):
method set_voltage_source (line 47) | def set_voltage_source(self, node_name, voltage):
method add_transistor (line 62) | def add_transistor(self, d_name, g_name, s_name, b_name, mos_type, int...
method solve (line 108) | def solve(self, env, guess_dict, itol=1e-10, inorm=1e-6):
FILE: bag/data/digital.py
function de_bruijn (line 13) | def de_bruijn(n, symbols=None):
function dig_to_pwl (line 55) | def dig_to_pwl(values, tper, trf, td=0):
function get_crossing_index (line 120) | def get_crossing_index(yvec, threshold, n=0, rising=True):
function get_flop_timing (line 150) | def get_flop_timing(tvec, d, q, clk, ttol, data_thres=0.5,
FILE: bag/data/lti.py
class LTICircuit (line 16) | class LTICircuit(object):
method __init__ (line 31) | def __init__(self, udot_tol=1e-12):
method _get_node_id (line 41) | def _get_node_id(self, name):
method _add (line 52) | def _add(mat, key, val):
method add_res (line 59) | def add_res(self, res, p_name, n_name):
method add_conductance (line 77) | def add_conductance(self, g, p_name, n_name):
method add_vccs (line 104) | def add_vccs(self, gm, p_name, n_name, cp_name, cn_name='gnd'):
method add_vcvs (line 140) | def add_vcvs(self, gain, p_name, n_name, cp_name, cn_name='gnd'):
method add_cap (line 172) | def add_cap(self, cap, p_name, n_name):
method add_ind (line 199) | def add_ind(self, ind, p_name, n_name):
method add_transistor (line 227) | def add_transistor(self, tran_info, d_name, g_name, s_name, b_name='gn...
method _count_rank (line 281) | def _count_rank(cls, diag):
method _solve_gx_bw (line 290) | def _solve_gx_bw(cls, g, b):
method _transform_c_qr (line 336) | def _transform_c_qr(cls, g, c, b, d):
method _reduce_state_space (line 353) | def _reduce_state_space(cls, g, c, b, d, e, ndim_w):
method _simplify (line 390) | def _simplify(cls, g, c, b, d, e, ndim_w):
method _build_mna_matrices (line 401) | def _build_mna_matrices(self, inputs, outputs, in_type='v'):
method get_state_space (line 533) | def get_state_space(self, inputs, outputs, in_type='v'):
method get_num_den (line 567) | def get_num_den(self, in_name, out_name, in_type='v', atol=0.0):
method get_transfer_function (line 600) | def get_transfer_function(self, in_name, out_name, in_type='v', atol=0...
method get_impedance (line 623) | def get_impedance(self, node_name, freq, atol=0.0):
function get_w_crossings (line 648) | def get_w_crossings(num, den, atol=1e-8):
function get_w_3db (line 727) | def get_w_3db(num, den, atol=1e-8):
function get_stability_margins (line 793) | def get_stability_margins(num, den, rtol=1e-8, atol=1e-8):
FILE: bag/data/ltv.py
function _even_quotient (line 11) | def _even_quotient(a, b, tol=1e-6):
class LTVImpulseFinite (line 19) | class LTVImpulseFinite(object):
method __init__ (line 93) | def __init__(self, hmat, m, n, tper, k, out0):
method _print_debug_msg (line 116) | def _print_debug_msg(result):
method __call__ (line 124) | def __call__(self, t, tau, debug=False):
method _get_core (line 164) | def _get_core(self, num_points, debug=False):
method visualize (line 189) | def visualize(self, fig_idx, num_points, num_period,
method lsim (line 250) | def lsim(self, u, tstep, tstart=0.0, ac_only=False, periodic=False, de...
method lsim_digital (line 341) | def lsim_digital(self, tsym, tstep, data, pulse, tstart=0.0, nchain=1,...
FILE: bag/data/mos.py
function mos_y_to_ss (line 11) | def mos_y_to_ss(sim_data, char_freq, fg, ibias, cfit_method='average'):
FILE: bag/data/plot.py
function figure (line 25) | def figure(fig_id, picker=5.0):
function plot_waveforms (line 43) | def plot_waveforms(xvec, panel_list, fig=1):
function _fpart (line 81) | def _fpart(x):
function _rfpart (line 85) | def _rfpart(x):
function draw_line (line 89) | def draw_line(x0, y0, x1, y1, xmax, grid):
function plot_eye_heatmap (line 133) | def plot_eye_heatmap(fig, tvec, yvec, tper, tstart=None, tend=None, toff...
function plot_eye (line 223) | def plot_eye(fig, tvec, yvec_list, tper, tstart=None, tend=None,
function _find_closest_point (line 298) | def _find_closest_point(x, y, xvec, yvec, xnorm, ynorm):
class WaveformPlotter (line 321) | class WaveformPlotter(object):
method __init__ (line 339) | def __init__(self, fig_idx, picker=5.0, normal_width=1.5, select_width...
method plot (line 352) | def plot(self, *args, **kwargs):
method setup (line 363) | def setup(self):
method figure_closed (line 395) | def figure_closed(self, event):
method figure_resized (line 405) | def figure_resized(self, event):
method fix_legend_location (line 410) | def fix_legend_location(self, event):
method legend_line_picked (line 422) | def legend_line_picked(self, artist):
method legend_text_picked (line 434) | def legend_text_picked(self, artist, draw=True):
class MarkerFigure (line 456) | class MarkerFigure(Figure):
method __init__ (line 457) | def __init__(self, **kwargs):
method set_line_visibility (line 467) | def set_line_visibility(self, axline, visible):
method register_pick_event (line 481) | def register_pick_event(self, artist_set, fun):
method on_button_release (line 485) | def on_button_release(self, event):
method on_motion (line 490) | def on_motion(self, event):
method _get_idx_under_point (line 511) | def _get_idx_under_point(self, event):
method on_pick (line 531) | def on_pick(self, event):
method _create_marker (line 582) | def _create_marker(self):
method close_figure (line 604) | def close_figure(self):
method setup_callbacks (line 607) | def setup_callbacks(self):
FILE: bag/design/module.py
class ModuleDB (line 20) | class ModuleDB(MasterDB):
method __init__ (line 44) | def __init__(self, lib_defs, tech_info, sch_exc_libs, prj=None, name_p...
method create_master_instance (line 55) | def create_master_instance(self, gen_cls, lib_name, params, used_cell_...
method create_masters_in_db (line 86) | def create_masters_in_db(self, lib_name, content_list, debug=False):
method tech_info (line 105) | def tech_info(self):
method is_lib_excluded (line 110) | def is_lib_excluded(self, lib_name):
class SchInstance (line 127) | class SchInstance(object):
method __init__ (line 150) | def __init__(self,
method change_generator (line 170) | def change_generator(self, gen_lib_name, gen_cell_name, static=False):
method name (line 193) | def name(self):
method connections (line 199) | def connections(self):
method is_primitive (line 205) | def is_primitive(self):
method should_delete (line 216) | def should_delete(self):
method master (line 222) | def master(self):
method master_cell_name (line 227) | def master_cell_name(self):
method master_key (line 233) | def master_key(self):
method copy (line 237) | def copy(self, inst_name, connections=None):
method get_master_lib_name (line 259) | def get_master_lib_name(self, impl_lib):
method design_specs (line 275) | def design_specs(self, *args, **kwargs):
method design (line 280) | def design(self, *args, **kwargs):
method _update_master (line 285) | def _update_master(self, design_fun, args, kwargs):
method implement_design (line 303) | def implement_design(self, lib_name, top_cell_name='', prefix='', suff...
method get_layout_params (line 345) | def get_layout_params(self, **kwargs):
class Module (line 354) | class Module(DesignMaster, metaclass=abc.ABCMeta):
method __init__ (line 377) | def __init__(self, database, yaml_fname, **kwargs):
method pin_list (line 417) | def pin_list(self):
method design (line 422) | def design(self, **kwargs):
method finalize (line 442) | def finalize(self):
method get_params_info (line 479) | def get_params_info(cls):
method get_master_basename (line 490) | def get_master_basename(self):
method get_content (line 501) | def get_content(self, lib_name, rename_fun):
method cell_name (line 543) | def cell_name(self):
method orig_cell_name (line 551) | def orig_cell_name(self):
method is_primitive (line 556) | def is_primitive(self):
method should_delete_instance (line 571) | def should_delete_instance(self):
method get_schematic_parameters (line 586) | def get_schematic_parameters(self):
method get_cell_name_from_parameters (line 601) | def get_cell_name_from_parameters(self):
method rename_pin (line 617) | def rename_pin(self, old_pin, new_pin):
method add_pin (line 633) | def add_pin(self, new_pin, pin_type):
method remove_pin (line 649) | def remove_pin(self, remove_pin):
method delete_instance (line 660) | def delete_instance(self, inst_name):
method replace_instance_master (line 671) | def replace_instance_master(self, inst_name, lib_name, cell_name, stat...
method reconnect_instance_terminal (line 704) | def reconnect_instance_terminal(self, inst_name, term_name, net_name, ...
method array_instance (line 756) | def array_instance(self, inst_name, inst_name_list, term_list=None):
method design_dc_bias_sources (line 790) | def design_dc_bias_sources(self, # type: Module
method design_dummy_transistors (line 862) | def design_dummy_transistors(self, dum_info, inst_name, vdd_name, vss_...
class MosModuleBase (line 911) | class MosModuleBase(Module):
method __init__ (line 924) | def __init__(self, database, yaml_file, **kwargs):
method get_params_info (line 928) | def get_params_info(cls):
method design (line 937) | def design(self, w=1e-6, l=60e-9, nf=1, intent='standard'):
method get_schematic_parameters (line 940) | def get_schematic_parameters(self):
method get_cell_name_from_parameters (line 953) | def get_cell_name_from_parameters(self):
method is_primitive (line 958) | def is_primitive(self):
method should_delete_instance (line 962) | def should_delete_instance(self):
class ResPhysicalModuleBase (line 967) | class ResPhysicalModuleBase(Module):
method __init__ (line 980) | def __init__(self, database, yaml_file, **kwargs):
method get_params_info (line 984) | def get_params_info(cls):
method design (line 992) | def design(self, w=1e-6, l=1e-6, intent='standard'):
method get_schematic_parameters (line 995) | def get_schematic_parameters(self):
method get_cell_name_from_parameters (line 1004) | def get_cell_name_from_parameters(self):
method is_primitive (line 1008) | def is_primitive(self):
method should_delete_instance (line 1012) | def should_delete_instance(self):
class ResMetalModule (line 1017) | class ResMetalModule(Module):
method __init__ (line 1030) | def __init__(self, database, yaml_file, **kwargs):
method get_params_info (line 1034) | def get_params_info(cls):
method design (line 1042) | def design(self, w, l, layer):
method get_schematic_parameters (line 1046) | def get_schematic_parameters(self):
method is_primitive (line 1056) | def is_primitive(self):
method should_delete_instance (line 1060) | def should_delete_instance(self):
FILE: bag/interface/base.py
class InterfaceBase (line 11) | class InterfaceBase:
method __init__ (line 16) | def __init__(self):
method render_file_template (line 19) | def render_file_template(self, temp_name, params):
FILE: bag/interface/database.py
function dict_to_item_list (line 21) | def dict_to_item_list(table):
function format_inst_map (line 37) | def format_inst_map(inst_map):
class DbAccess (line 62) | class DbAccess(InterfaceBase, abc.ABC):
method __init__ (line 73) | def __init__(self, tmp_dir, db_config):
method get_default_lib_path (line 95) | def get_default_lib_path(cls, db_config):
method default_lib_path (line 104) | def default_lib_path(self):
method close (line 115) | def close(self):
method parse_schematic_template (line 121) | def parse_schematic_template(self, lib_name, cell_name):
method get_cells_in_library (line 139) | def get_cells_in_library(self, lib_name):
method create_library (line 157) | def create_library(self, lib_name, lib_path=''):
method create_implementation (line 170) | def create_implementation(self, lib_name, template_list, change_list, ...
method configure_testbench (line 187) | def configure_testbench(self, tb_lib, tb_cell):
method get_testbench_info (line 211) | def get_testbench_info(self, tb_lib, tb_cell):
method update_testbench (line 235) | def update_testbench(self, # type: DbAccess
method instantiate_layout_pcell (line 264) | def instantiate_layout_pcell(self, lib_name, cell_name, view_name,
method instantiate_layout (line 288) | def instantiate_layout(self, lib_name, view_name, via_tech, layout_list):
method release_write_locks (line 306) | def release_write_locks(self, lib_name, cell_view_list):
method create_schematic_from_netlist (line 320) | def create_schematic_from_netlist(self, netlist, lib_name, cell_name,
method create_verilog_view (line 343) | def create_verilog_view(self, verilog_file, lib_name, cell_name, **kwa...
method get_python_template (line 360) | def get_python_template(self, lib_name, cell_name, primitive_table):
method _process_rcx_output (line 408) | def _process_rcx_output(self, netlist, log_fname, lib_name, cell_name,...
method async_run_lvs (line 419) | async def async_run_lvs(self, lib_name: str, cell_name: str, **kwargs:...
method async_run_rcx (line 445) | async def async_run_rcx(self, # type: DbAccess
method async_export_layout (line 491) | async def async_export_layout(self, lib_name: str, cell_name: str,
method import_design_library (line 519) | def import_design_library(self, lib_name, dsn_db, new_lib_path):
method import_sch_cellview (line 535) | def import_sch_cellview(self, lib_name, cell_name, dsn_db, new_lib_path):
method _import_design (line 554) | def _import_design(self, lib_name, cell_name, imported_cells, dsn_db, ...
method instantiate_schematic (line 600) | def instantiate_schematic(self, lib_name, content_list, lib_path=''):
FILE: bag/interface/ocean.py
class OceanInterface (line 17) | class OceanInterface(SimProcessManager):
method __init__ (line 28) | def __init__(self, tmp_dir, sim_config):
method format_parameter_value (line 34) | def format_parameter_value(self, param_config, precision):
method _get_ocean_info (line 86) | def _get_ocean_info(self, save_dir, script_fname, log_fname):
method setup_sim_process (line 102) | def setup_sim_process(self, lib, cell, outputs, precision, sim_tag):
method setup_load_process (line 140) | def setup_load_process(self, lib, cell, hist_name, outputs, precision):
FILE: bag/interface/server.py
function _object_to_skill_file_helper (line 31) | def _object_to_skill_file_helper(py_obj, file_obj):
function object_to_skill_file (line 75) | def object_to_skill_file(py_obj, file_obj):
class SkillServer (line 97) | class SkillServer(object):
method __init__ (line 118) | def __init__(self, router, virt_in, virt_out, tmpdir=None):
method run (line 128) | def run(self):
method send_skill (line 152) | def send_skill(self, expr):
method recv_skill (line 163) | def recv_skill(self):
method close (line 171) | def close(self):
method process_skill_request (line 175) | def process_skill_request(self, request):
method process_skill_result (line 228) | def process_skill_result(self, msg, out_file=None):
FILE: bag/interface/simulator.py
class SimAccess (line 18) | class SimAccess(InterfaceBase, abc.ABC):
method __init__ (line 29) | def __init__(self, tmp_dir, sim_config):
method format_parameter_value (line 37) | def format_parameter_value(self, param_config, precision):
method async_run_simulation (line 75) | async def async_run_simulation(self, tb_lib, tb_cell, outputs, precisi...
method async_load_results (line 100) | async def async_load_results(self, lib, cell, hist_name, outputs, prec...
class SimProcessManager (line 128) | class SimProcessManager(SimAccess, metaclass=abc.ABCMeta):
method __init__ (line 139) | def __init__(self, tmp_dir, sim_config):
method setup_sim_process (line 149) | def setup_sim_process(self, lib, cell, outputs, precision, sim_tag):
method setup_load_process (line 182) | def setup_load_process(self, lib, cell, hist_name, outputs, precision):
method async_run_simulation (line 214) | async def async_run_simulation(self, tb_lib: str, tb_cell: str,
method async_load_results (line 224) | async def async_load_results(self, lib: str, cell: str, hist_name: str,
FILE: bag/interface/skill.py
function _dict_to_pcell_params (line 22) | def _dict_to_pcell_params(table):
function to_skill_list_str (line 54) | def to_skill_list_str(pylist):
function _handle_reply (line 72) | def _handle_reply(reply):
class VirtuosoException (line 88) | class VirtuosoException(Exception):
method __init__ (line 91) | def __init__(self, *args, **kwargs):
class SkillInterface (line 96) | class SkillInterface(DbAccess):
method __init__ (line 112) | def __init__(self, dealer, tmp_dir, db_config):
method close (line 119) | def close(self):
method _eval_skill (line 125) | def _eval_skill(self, expr, input_files=None, out_file=None):
method parse_schematic_template (line 178) | def parse_schematic_template(self, lib_name, cell_name):
method get_cells_in_library (line 196) | def get_cells_in_library(self, lib_name):
method create_library (line 214) | def create_library(self, lib_name, lib_path=''):
method create_implementation (line 229) | def create_implementation(self, lib_name, template_list, change_list, ...
method configure_testbench (line 289) | def configure_testbench(self, tb_lib, tb_cell):
method get_testbench_info (line 330) | def get_testbench_info(self, tb_lib, tb_cell):
method update_testbench (line 358) | def update_testbench(self,
method instantiate_layout_pcell (line 395) | def instantiate_layout_pcell(self, lib_name, cell_name, view_name,
method instantiate_layout (line 428) | def instantiate_layout(self, lib_name, view_name, via_tech, layout_list):
method release_write_locks (line 467) | def release_write_locks(self, lib_name, cell_view_list):
method create_schematic_from_netlist (line 481) | def create_schematic_from_netlist(self, netlist, lib_name, cell_name,
method get_cell_directory (line 569) | def get_cell_directory(self, lib_name, cell_name):
method create_verilog_view (line 591) | def create_verilog_view(self, verilog_file, lib_name, cell_name, **kwa...
FILE: bag/interface/templates/Module.pyi
function __init__ (line 22) | def __init__(self, database, parent=None, prj=None, **kwargs):
function get_params_info (line 26) | def get_params_info(cls):
function design (line 38) | def design(self):
FILE: bag/interface/templates/PrimModule.pyi
function __init__ (line 18) | def __init__(self, database, parent=None, prj=None, **kwargs):
FILE: bag/interface/zmqwrapper.py
class ZMQDealer (line 17) | class ZMQDealer(object):
method __init__ (line 37) | def __init__(self, port, pipeline=100, host='localhost', log_file=None):
method log_msg (line 61) | def log_msg(self, msg):
method log_obj (line 66) | def log_obj(self, msg, obj):
method close (line 72) | def close(self):
method send_obj (line 76) | def send_obj(self, obj):
method recv_obj (line 89) | def recv_obj(self, timeout=None, enable_cancel=False):
method recv_msg (line 128) | def recv_msg(self):
class ZMQRouter (line 141) | class ZMQRouter(object):
method __init__ (line 164) | def __init__(self, port=None, min_port=5000, max_port=9999, pipeline=1...
method get_port (line 189) | def get_port(self):
method is_closed (line 193) | def is_closed(self):
method close (line 197) | def close(self):
method log_msg (line 201) | def log_msg(self, msg):
method log_obj (line 206) | def log_obj(self, msg, obj):
method send_msg (line 212) | def send_msg(self, msg, addr=None):
method send_obj (line 230) | def send_obj(self, obj, addr=None):
method poll_for_read (line 250) | def poll_for_read(self, timeout):
method recv_obj (line 265) | def recv_obj(self):
method get_last_sender_addr (line 280) | def get_last_sender_addr(self):
FILE: bag/io/common.py
function fix_string (line 14) | def fix_string(obj):
function to_bytes (line 37) | def to_bytes(my_str):
function set_encoding (line 53) | def set_encoding(new_encoding):
function get_encoding (line 67) | def get_encoding():
function set_error_policy (line 78) | def set_error_policy(new_policy):
function get_error_policy (line 91) | def get_error_policy():
FILE: bag/io/file.py
class Pickle (line 20) | class Pickle:
method save (line 25) | def save(obj, file, **kwargs) -> None:
method load (line 30) | def load(file, **kwargs):
class Yaml (line 35) | class Yaml:
method save (line 41) | def save(obj, file, **kwargs) -> None:
method load (line 46) | def load(file, **kwargs):
function open_file (line 51) | def open_file(fname, mode):
function read_file (line 73) | def read_file(fname):
function readlines_iter (line 91) | def readlines_iter(fname):
function read_yaml_env (line 109) | def read_yaml_env(fname):
function read_yaml (line 129) | def read_yaml(fname):
function read_resource (line 148) | def read_resource(package, fname):
function write_file (line 167) | def write_file(fname, content, append=False, mkdir=True):
function make_temp_dir (line 191) | def make_temp_dir(prefix, parent_dir=None):
function open_temp (line 206) | def open_temp(**kwargs):
FILE: bag/io/gui.py
class StdinThread (line 19) | class StdinThread(QtCore.QThread):
method __init__ (line 23) | def __init__(self, parent):
method run (line 27) | def run(self):
class LogWidget (line 43) | class LogWidget(QtWidgets.QFrame):
method __init__ (line 51) | def __init__(self, parent=None):
method clear_log (line 70) | def clear_log(self):
method save_log (line 74) | def save_log(self):
method print_file (line 80) | def print_file(self, file_obj):
class LogViewer (line 93) | class LogViewer(QtWidgets.QWidget):
method __init__ (line 96) | def __init__(self):
method closeEvent (line 133) | def closeEvent(self, evt):
method parse_cmd (line 140) | def parse_cmd(self, cmd):
method change_log (line 154) | def change_log(self, new_idx):
method update_logfile (line 172) | def update_logfile(self, fname):
method remove_log (line 177) | def remove_log(self, log_tag):
method add_log (line 183) | def add_log(self, log_tag, log_file):
function app_start (line 190) | def app_start():
function start_viewer (line 199) | def start_viewer():
function add_log (line 208) | def add_log(proc, tag, fname):
function remove_log (line 219) | def remove_log(proc, tag):
function close (line 230) | def close(proc):
FILE: bag/io/process.py
function run_proc_with_quit (line 26) | def run_proc_with_quit(proc_id, quit_dict, args, logfile=None, append=Fa...
function run_and_wait (line 54) | def run_and_wait(args, timeout=None, logfile=None, append=False,
class ProcessManager (line 98) | class ProcessManager(object):
method __init__ (line 113) | def __init__(self, max_workers=None, cancel_timeout=10.0):
method close (line 123) | def close(self, timeout=10.0):
method new_thread (line 137) | def new_thread(self, fun, basename=None, callback=None):
method new_process (line 182) | def new_process(self, args, basename=None, logfile=None, append=False,
method _get_output (line 234) | def _get_output(future, timeout=None):
method cancel (line 244) | def cancel(self, proc_id, timeout=None):
method done (line 294) | def done(self, proc_id):
method wait (line 309) | def wait(self, proc_id, timeout=None, cancel_timeout=None):
method _start_cmd (line 349) | def _start_cmd(self, args, proc_id, logfile=None, append=False, env=No...
FILE: bag/io/sim_data.py
class SweepArray (line 20) | class SweepArray(np.ndarray):
method __new__ (line 24) | def __new__(cls, data, sweep_params=None):
method __array_finalize__ (line 33) | def __array_finalize__(self, obj):
method __reduce__ (line 39) | def __reduce__(self):
method __setstate__ (line 48) | def __setstate__(self, state):
function _get_sweep_params (line 55) | def _get_sweep_params(fname):
function load_sim_results (line 105) | def load_sim_results(save_dir):
function save_sim_results (line 182) | def save_sim_results(results, fname, compression='gzip'):
function load_sim_file (line 224) | def load_sim_file(fname):
FILE: bag/io/template.py
function new_template_env (line 9) | def new_template_env(parent_package, tmp_folder):
FILE: bag/layout/core.py
class TechInfo (line 26) | class TechInfo(object, metaclass=abc.ABCMeta):
method __init__ (line 49) | def __init__(self, res, layout_unit, via_tech, process_params):
method get_well_layers (line 56) | def get_well_layers(self, sub_type):
method get_implant_layers (line 62) | def get_implant_layers(self, mos_type, res_type=None):
method get_threshold_layers (line 81) | def get_threshold_layers(self, mos_type, threshold, res_type=None):
method get_exclude_layer (line 87) | def get_exclude_layer(self, layer_id):
method get_dnw_margin_unit (line 93) | def get_dnw_margin_unit(self, dnw_mode):
method get_dnw_layers (line 110) | def get_dnw_layers(self):
method get_res_metal_layers (line 122) | def get_res_metal_layers(self, layer_id):
method get_metal_dummy_layers (line 139) | def get_metal_dummy_layers(self, layer_id):
method add_cell_boundary (line 156) | def add_cell_boundary(self, template, box):
method draw_device_blockage (line 171) | def draw_device_blockage(self, template):
method get_via_drc_info (line 182) | def get_via_drc_info(self, vname, vtype, mtype, mw_unit, is_bot):
method get_min_space (line 228) | def get_min_space(self, layer_type, width, unit_mode=False, same_color...
method get_min_line_end_space (line 250) | def get_min_line_end_space(self, layer_type, width, unit_mode=False):
method get_min_length (line 270) | def get_min_length(self, layer_type, width):
method get_layer_id (line 289) | def get_layer_id(self, layer_name):
method get_layer_name (line 305) | def get_layer_name(self, layer_id):
method get_layer_type (line 322) | def get_layer_type(self, layer_name):
method get_via_name (line 338) | def get_via_name(self, bot_layer_id):
method get_metal_em_specs (line 354) | def get_metal_em_specs(self, layer_name, w, l=-1, vertical=False, **kw...
method get_via_em_specs (line 383) | def get_via_em_specs(self, via_name, # type: str
method get_res_rsquare (line 427) | def get_res_rsquare(self, res_type):
method get_res_width_bounds (line 445) | def get_res_width_bounds(self, res_type):
method get_res_length_bounds (line 463) | def get_res_length_bounds(self, res_type):
method get_res_min_nsquare (line 481) | def get_res_min_nsquare(self, res_type):
method get_res_em_specs (line 497) | def get_res_em_specs(self, res_type, w, l=-1, **kwargs):
method via_tech_name (line 525) | def via_tech_name(self):
method pin_purpose (line 530) | def pin_purpose(self):
method resolution (line 535) | def resolution(self):
method layout_unit (line 540) | def layout_unit(self):
method merge_well (line 544) | def merge_well(self, template, inst_list, sub_type, threshold=None, re...
method use_flip_parity (line 565) | def use_flip_parity(self):
method finalize_template (line 570) | def finalize_template(self, template):
method get_res_info (line 582) | def get_res_info(self, res_type, w, l, **kwargs):
method get_via_types (line 622) | def get_via_types(self, bmtype, tmtype):
method get_best_via_array (line 625) | def get_best_via_array(self, vname, bmtype, tmtype, bot_dir, top_dir, ...
method _via_better (line 851) | def _via_better(self, mdim_list1, mdim_list2):
method get_via_id (line 865) | def get_via_id(self, bot_layer, top_layer):
method get_via_info (line 884) | def get_via_info(self, bbox, bot_layer, top_layer, bot_dir, bot_len=-1...
method design_resistor (line 1019) | def design_resistor(self, res_type, res_targ, idc=0.0, iac_rms=0.0,
class DummyTechInfo (line 1124) | class DummyTechInfo(TechInfo):
method __init__ (line 1133) | def __init__(self, tech_params):
method get_well_layers (line 1136) | def get_well_layers(self, sub_type):
method get_implant_layers (line 1139) | def get_implant_layers(self, mos_type, res_type=None):
method get_threshold_layers (line 1142) | def get_threshold_layers(self, mos_type, threshold, res_type=None):
method get_dnw_layers (line 1145) | def get_dnw_layers(self):
method get_exclude_layer (line 1149) | def get_exclude_layer(self, layer_id):
method get_dnw_margin_unit (line 1154) | def get_dnw_margin_unit(self, dnw_mode):
method get_res_metal_layers (line 1158) | def get_res_metal_layers(self, layer_id):
method get_metal_dummy_layers (line 1162) | def get_metal_dummy_layers(self, layer_id):
method add_cell_boundary (line 1166) | def add_cell_boundary(self, template, box):
method draw_device_blockage (line 1169) | def draw_device_blockage(self, template):
method get_via_drc_info (line 1172) | def get_via_drc_info(self, vname, vtype, mtype, mw_unit, is_bot):
method get_min_space (line 1175) | def get_min_space(self, layer_type, width, unit_mode=False, same_color...
method get_min_line_end_space (line 1178) | def get_min_line_end_space(self, layer_type, width, unit_mode=False):
method get_min_length (line 1181) | def get_min_length(self, layer_type, width):
method get_layer_id (line 1184) | def get_layer_id(self, layer_name):
method get_layer_name (line 1187) | def get_layer_name(self, layer_id):
method get_layer_type (line 1190) | def get_layer_type(self, layer_name):
method get_via_name (line 1193) | def get_via_name(self, bot_layer_id):
method get_metal_em_specs (line 1196) | def get_metal_em_specs(self, layer_name, w, l=-1, vertical=False, **kw...
method get_via_em_specs (line 1199) | def get_via_em_specs(self, via_name, bm_layer, tm_layer, via_type='squ...
method get_res_rsquare (line 1203) | def get_res_rsquare(self, res_type):
method get_res_width_bounds (line 1206) | def get_res_width_bounds(self, res_type):
method get_res_length_bounds (line 1209) | def get_res_length_bounds(self, res_type):
method get_res_min_nsquare (line 1212) | def get_res_min_nsquare(self, res_type):
method get_res_em_specs (line 1215) | def get_res_em_specs(self, res_type, w, l=-1, **kwargs):
class BagLayout (line 1219) | class BagLayout(object):
method __init__ (line 1230) | def __init__(self, grid, use_cybagoa=False):
method pin_purpose (line 1253) | def pin_purpose(self):
method is_empty (line 1258) | def is_empty(self):
method inst_iter (line 1262) | def inst_iter(self):
method finalize (line 1266) | def finalize(self):
method get_rect_bbox (line 1321) | def get_rect_bbox(self, layer):
method get_masters_set (line 1340) | def get_masters_set(self):
method _get_unused_inst_name (line 1344) | def _get_unused_inst_name(self, inst_name):
method _format_inst (line 1355) | def _format_inst(self, inst):
method get_content (line 1364) | def get_content(self, # type: BagLayout
method add_instance (line 1430) | def add_instance(self, instance):
method move_all_by (line 1446) | def move_all_by(self, dx=0.0, dy=0.0, unit_mode=False):
method add_instance_primitive (line 1468) | def add_instance_primitive(self, # type: BagLayout
method add_rect (line 1553) | def add_rect(self, rect):
method add_path (line 1566) | def add_path(self, path):
method add_polygon (line 1580) | def add_polygon(self, polygon):
method add_blockage (line 1594) | def add_blockage(self, blockage):
method add_boundary (line 1608) | def add_boundary(self, boundary):
method add_via (line 1622) | def add_via(self, via):
method add_via_primitive (line 1638) | def add_via_primitive(self, via_type, loc, num_rows=1, num_cols=1, sp_...
method add_pin (line 1705) | def add_pin(self, net_name, layer, bbox, pin_name=None, label=None):
method add_label (line 1752) | def add_label(self, label, layer, bbox):
FILE: bag/layout/digital.py
class StdCellBase (line 19) | class StdCellBase(TemplateBase, metaclass=abc.ABCMeta):
method __init__ (line 37) | def __init__(self, temp_db, lib_name, params, used_names, **kwargs):
method min_space_width (line 51) | def min_space_width(self):
method std_col_width (line 57) | def std_col_width(self):
method std_col_width_unit (line 63) | def std_col_width_unit(self):
method std_row_height (line 70) | def std_row_height(self):
method std_row_height_unit (line 76) | def std_row_height_unit(self):
method std_size (line 83) | def std_size(self):
method std_routing_layers (line 89) | def std_routing_layers(self):
method get_num_columns (line 94) | def get_num_columns(self, layer_id, num_tr):
method set_draw_boundaries (line 114) | def set_draw_boundaries(self, draw_boundaries):
method get_space_blocks (line 130) | def get_space_blocks(self):
method get_cell_params (line 135) | def get_cell_params(self, cell_name):
method set_std_size (line 149) | def set_std_size(self, std_size, top_layer=-1):
method update_routing_grid (line 185) | def update_routing_grid(self):
method get_num_tracks (line 201) | def get_num_tracks(self, layer_id):
method add_std_instance (line 228) | def add_std_instance(self, master, inst_name=None, loc=(0, 0), nx=1, n...
method draw_boundaries (line 303) | def draw_boundaries(self):
method fill_space (line 367) | def fill_space(self):
method add_std_space (line 380) | def add_std_space(self, loc, num_col, update_used_blks=True):
class StdCellTemplate (line 431) | class StdCellTemplate(StdCellBase):
method __init__ (line 449) | def __init__(self, temp_db, lib_name, params, used_names, **kwargs):
method sch_params (line 455) | def sch_params(self):
method get_params_info (line 459) | def get_params_info(cls):
method get_layout_basename (line 475) | def get_layout_basename(self):
method compute_unique_key (line 478) | def compute_unique_key(self):
method get_sch_master_info (line 482) | def get_sch_master_info(self):
method draw_layout (line 488) | def draw_layout(self):
FILE: bag/layout/objects.py
class Figure (line 25) | class Figure(object, metaclass=abc.ABCMeta):
method __init__ (line 34) | def __init__(self, resolution):
method transform (line 40) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
method move_by (line 46) | def move_by(self, dx=0, dy=0, unit_mode=False):
method resolution (line 62) | def resolution(self):
method destroyed (line 68) | def destroyed(self):
method valid (line 74) | def valid(self):
method check_destroyed (line 79) | def check_destroyed(self):
method destroy (line 85) | def destroy(self):
class Arrayable (line 92) | class Arrayable(Figure, metaclass=abc.ABCMeta):
method __init__ (line 113) | def __init__(self, res, nx=1, ny=1, spx=0, spy=0, unit_mode=False):
method nx (line 126) | def nx(self):
method nx (line 132) | def nx(self, val):
method ny (line 141) | def ny(self):
method ny (line 147) | def ny(self, val):
method spx (line 156) | def spx(self):
method spx (line 162) | def spx(self, val):
method spx_unit (line 171) | def spx_unit(self):
method spx_unit (line 177) | def spx_unit(self, val):
method spy (line 186) | def spy(self):
method spy (line 192) | def spy(self, val):
method spy_unit (line 201) | def spy_unit(self):
method spy_unit (line 207) | def spy_unit(self, val):
method valid (line 216) | def valid(self):
method get_item_location (line 221) | def get_item_location(self, row=0, col=0, unit_mode=False):
class InstanceInfo (line 251) | class InstanceInfo(dict):
method __init__ (line 258) | def __init__(self, res, change_orient=True, **kwargs):
method lib (line 292) | def lib(self):
method cell (line 297) | def cell(self):
method view (line 302) | def view(self):
method name (line 307) | def name(self):
method name (line 312) | def name(self, new_name):
method loc (line 317) | def loc(self):
method orient (line 323) | def orient(self):
method num_rows (line 328) | def num_rows(self):
method num_cols (line 333) | def num_cols(self):
method sp_rows (line 338) | def sp_rows(self):
method sp_cols (line 343) | def sp_cols(self):
method params (line 348) | def params(self):
method params (line 353) | def params(self, new_params):
method master_key (line 358) | def master_key(self):
method master_key (line 362) | def master_key(self, value):
method angle_reflect (line 366) | def angle_reflect(self):
method copy (line 388) | def copy(self):
method move_by (line 392) | def move_by(self, dx=0, dy=0):
class Instance (line 409) | class Instance(Arrayable):
method __init__ (line 438) | def __init__(self,
method new_master_with (line 464) | def new_master_with(self, **kwargs):
method blockage_iter (line 479) | def blockage_iter(self, layer_id, test_box, spx=0, spy=0):
method all_rect_iter (line 515) | def all_rect_iter(self):
method intersection_rect_iter (line 532) | def intersection_rect_iter(self, layer_id, test_box):
method get_rect_bbox (line 563) | def get_rect_bbox(self, layer):
method track_bbox_iter (line 575) | def track_bbox_iter(self):
method master (line 582) | def master(self):
method location (line 588) | def location(self):
method location (line 594) | def location(self, new_loc):
method location_unit (line 602) | def location_unit(self):
method location_unit (line 608) | def location_unit(self, new_loc):
method orientation (line 615) | def orientation(self):
method orientation (line 621) | def orientation(self, val):
method content (line 630) | def content(self):
method bound_box (line 648) | def bound_box(self):
method array_box (line 657) | def array_box(self):
method fill_box (line 670) | def fill_box(self):
method get_bound_box_of (line 682) | def get_bound_box_of(self, row=0, col=0):
method move_by (line 690) | def move_by(self, dx=0, dy=0, unit_mode=False):
method translate_master_box (line 708) | def translate_master_box(self, box):
method translate_master_location (line 724) | def translate_master_location(self,
method translate_master_track (line 755) | def translate_master_track(self, layer_id, track_idx):
method get_port (line 775) | def get_port(self, name='', row=0, col=0):
method get_pin (line 800) | def get_pin(self, name='', row=0, col=0, layer=-1):
method get_all_port_pins (line 827) | def get_all_port_pins(self, name='', layer=-1):
method port_pins_iter (line 855) | def port_pins_iter(self, name='', layer=-1):
method port_names_iter (line 882) | def port_names_iter(self):
method has_port (line 893) | def has_port(self, port_name):
method has_prim_port (line 898) | def has_prim_port(self, port_name):
method transform (line 903) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
class Rect (line 919) | class Rect(Arrayable):
method __init__ (line 942) | def __init__(self, layer, bbox, nx=1, ny=1, spx=0, spy=0, unit_mode=Fa...
method bbox_array (line 958) | def bbox_array(self):
method layer (line 970) | def layer(self):
method layer (line 975) | def layer(self, val):
method bbox (line 986) | def bbox(self):
method bbox (line 991) | def bbox(self, val):
method content (line 1000) | def content(self):
method move_by (line 1013) | def move_by(self, dx=0, dy=0, unit_mode=False):
method extend (line 1028) | def extend(self, x=None, y=None):
method transform (line 1041) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
method destroy (line 1054) | def destroy(self):
class Path (line 1061) | class Path(Figure):
method __init__ (line 1083) | def __init__(self,
method compress_points (line 1115) | def compress_points(cls, pts_unit):
method layer (line 1146) | def layer(self):
method valid (line 1152) | def valid(self):
method width (line 1158) | def width(self):
method points (line 1162) | def points(self):
method points_unit (line 1167) | def points_unit(self):
method content (line 1172) | def content(self):
method move_by (line 1183) | def move_by(self, dx=0, dy=0, unit_mode=False):
method transform (line 1201) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
class PathCollection (line 1223) | class PathCollection(Figure):
method __init__ (line 1236) | def __init__(self, resolution, paths, poly_paths = None):
method move_by (line 1241) | def move_by(self, dx=0, dy=0, unit_mode=False):
method transform (line 1257) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=True):
class TLineBus (line 1270) | class TLineBus(PathCollection):
method __init__ (line 1293) | def __init__(self, resolution, layer, points, widths, spaces, end_styl...
method paths_iter (line 1327) | def paths_iter(self):
method poly_paths_iter (line 1330) | def poly_paths_iter(self):
method create_paths (line 1333) | def create_paths(self, delta_list, res):
method create_poly_paths (line 1388) | def create_poly_paths(self, delta_list, res):
class Polygon (line 1707) | class Polygon(Figure):
method __init__ (line 1723) | def __init__(self,
method layer (line 1743) | def layer(self):
method points (line 1749) | def points(self):
method points_unit (line 1754) | def points_unit(self):
method content (line 1759) | def content(self):
method move_by (line 1767) | def move_by(self, dx=0, dy=0, unit_mode=False):
method transform (line 1774) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
class Blockage (line 1796) | class Blockage(Polygon):
method __init__ (line 1815) | def __init__(self, resolution, block_type, block_layer, points, unit_m...
method layer (line 1822) | def layer(self):
method type (line 1827) | def type(self):
method content (line 1833) | def content(self):
class Boundary (line 1843) | class Boundary(Polygon):
method __init__ (line 1860) | def __init__(self, resolution, boundary_type, points, unit_mode=False):
method type (line 1866) | def type(self):
method content (line 1872) | def content(self):
class ViaInfo (line 1881) | class ViaInfo(dict):
method __init__ (line 1888) | def __init__(self, res, **kwargs):
method id (line 1898) | def id(self):
method loc (line 1903) | def loc(self):
method orient (line 1909) | def orient(self):
method num_rows (line 1914) | def num_rows(self):
method num_cols (line 1919) | def num_cols(self):
method sp_rows (line 1924) | def sp_rows(self):
method sp_cols (line 1929) | def sp_cols(self):
method enc1 (line 1934) | def enc1(self):
method enc2 (line 1940) | def enc2(self):
method cut_width (line 1946) | def cut_width(self):
method cut_height (line 1951) | def cut_height(self):
method arr_nx (line 1956) | def arr_nx(self):
method arr_ny (line 1961) | def arr_ny(self):
method arr_spx (line 1966) | def arr_spx(self):
method arr_spy (line 1971) | def arr_spy(self):
method move_by (line 1975) | def move_by(self, dx=0, dy=0):
class Via (line 1992) | class Via(Arrayable):
method __init__ (line 2026) | def __init__(self, tech, bbox, bot_layer, top_layer, bot_dir,
method _update (line 2058) | def _update(self):
method top_box (line 2065) | def top_box(self):
method bottom_box (line 2071) | def bottom_box(self):
method bot_layer (line 2077) | def bot_layer(self):
method top_layer (line 2082) | def top_layer(self):
method bottom_direction (line 2087) | def bottom_direction(self):
method bottom_direction (line 2092) | def bottom_direction(self, new_bot_dir):
method top_direction (line 2099) | def top_direction(self):
method top_direction (line 2106) | def top_direction(self, new_top_dir):
method extend (line 2113) | def extend(self):
method extend (line 2118) | def extend(self, new_val):
method bbox (line 2122) | def bbox(self):
method bbox_array (line 2127) | def bbox_array(self):
method bbox (line 2139) | def bbox(self, new_bbox):
method content (line 2148) | def content(self):
method move_by (line 2161) | def move_by(self, dx=0, dy=0, unit_mode=False):
method transform (line 2179) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False, copy=Fal...
class PinInfo (line 2196) | class PinInfo(dict):
method __init__ (line 2202) | def __init__(self, res, **kwargs):
method net_name (line 2209) | def net_name(self):
method pin_name (line 2214) | def pin_name(self):
method label (line 2219) | def label(self):
method layer (line 2224) | def layer(self):
method bbox (line 2230) | def bbox(self):
method make_rect (line 2237) | def make_rect(self):
method move_by (line 2241) | def move_by(self, dx=0, dy=0):
FILE: bag/layout/routing/base.py
class TrackID (line 15) | class TrackID(object):
method __init__ (line 32) | def __init__(self, layer_id, track_idx, width=1, num=1, pitch=0.0):
method __repr__ (line 43) | def __repr__(self):
method __str__ (line 60) | def __str__(self):
method layer_id (line 64) | def layer_id(self):
method width (line 69) | def width(self):
method base_index (line 74) | def base_index(self):
method index_htr (line 81) | def index_htr(self):
method num (line 86) | def num(self):
method pitch (line 91) | def pitch(self):
method pitch_htr (line 98) | def pitch_htr(self):
method get_immutable_key (line 102) | def get_immutable_key(self):
method get_bounds (line 105) | def get_bounds(self, grid, unit_mode=False):
method __iter__ (line 133) | def __iter__(self):
method sub_tracks_iter (line 143) | def sub_tracks_iter(self, grid):
method transform (line 174) | def transform(self, grid, loc=(0, 0), orient="R0", unit_mode=False):
class WireArray (line 202) | class WireArray(object):
method __init__ (line 219) | def __init__(self, track_id, lower, upper, res=None, unit_mode=False):
method __repr__ (line 233) | def __repr__(self):
method __str__ (line 237) | def __str__(self):
method resolution (line 241) | def resolution(self):
method lower (line 245) | def lower(self):
method upper (line 249) | def upper(self):
method middle (line 253) | def middle(self):
method lower_unit (line 257) | def lower_unit(self):
method upper_unit (line 261) | def upper_unit(self):
method middle_unit (line 265) | def middle_unit(self):
method track_id (line 269) | def track_id(self):
method layer_id (line 275) | def layer_id(self):
method width (line 281) | def width(self):
method list_to_warr (line 285) | def list_to_warr(cls, warr_list):
method single_warr_iter (line 316) | def single_warr_iter(cls, warr):
method get_immutable_key (line 323) | def get_immutable_key(self):
method to_warr_list (line 327) | def to_warr_list(self):
method warr_iter (line 330) | def warr_iter(self):
method get_bbox_array (line 338) | def get_bbox_array(self, grid):
method wire_iter (line 366) | def wire_iter(self, grid):
method wire_arr_iter (line 389) | def wire_arr_iter(self, grid):
method transform (line 427) | def transform(self, grid, loc=(0, 0), orient='R0', unit_mode=False):
class Port (line 469) | class Port(object):
method __init__ (line 483) | def __init__(self, term_name, pin_dict, label=''):
method __iter__ (line 488) | def __iter__(self):
method get_single_layer (line 496) | def get_single_layer(self):
method _get_layer (line 503) | def _get_layer(self, layer):
method net_name (line 511) | def net_name(self):
method label (line 516) | def label(self):
method get_pins (line 520) | def get_pins(self, layer=-1):
method get_bounding_box (line 537) | def get_bounding_box(self, grid, layer=-1):
method transform (line 562) | def transform(self, grid, loc=(0, 0), orient='R0', unit_mode=False):
class TrackManager (line 594) | class TrackManager(object):
method __init__ (line 614) | def __init__(self,
method grid (line 629) | def grid(self):
method half_space (line 634) | def half_space(self):
method get_width (line 638) | def get_width(self, layer_id, track_type):
method get_space (line 655) | def get_space(self, # type: TrackManager
method _get_space_from_tuple (line 708) | def _get_space_from_tuple(cls, layer_id, ntup, sp_dict):
method _get_space_from_type (line 718) | def _get_space_from_type(cls, layer_id, wtype, sp_dict):
method get_next_track (line 738) | def get_next_track(self, # type: TrackManager
method place_wires (line 778) | def place_wires(self, # type: TrackManager
method _get_align_delta (line 823) | def _get_align_delta(cls, tot_ntr, num_used, alignment):
method align_wires (line 837) | def align_wires(self, # type: TrackManager
method spread_wires (line 876) | def spread_wires(self, # type: TrackManager
FILE: bag/layout/routing/fill.py
class RectIndex (line 19) | class RectIndex(object):
method __init__ (line 22) | def __init__(self, resolution, basename=None, overwrite=False):
method bound_box (line 33) | def bound_box(self):
method close (line 38) | def close(self):
method record_box (line 41) | def record_box(self, box, dx, dy):
method rect_iter (line 50) | def rect_iter(self):
method intersection_iter (line 56) | def intersection_iter(self, box, dx=0, dy=0):
method intersection_rect_iter (line 68) | def intersection_rect_iter(self, box):
class UsedTracks (line 77) | class UsedTracks(object):
method __init__ (line 81) | def __init__(self, save_file_basename=None, overwrite=False):
method __iter__ (line 87) | def __iter__(self):
method get_track_bbox (line 90) | def get_track_bbox(self, layer_id):
method track_box_iter (line 96) | def track_box_iter(self):
method record_box (line 101) | def record_box(self, layer_id, box, dx, dy, res):
method close (line 113) | def close(self):
method record_rect (line 117) | def record_rect(self, grid, layer_name, box_arr, dx=-1, dy=-1):
method all_rect_iter (line 165) | def all_rect_iter(self):
method intersection_rect_iter (line 171) | def intersection_rect_iter(self, layer_id, box):
method blockage_iter (line 177) | def blockage_iter(self, layer_id, test_box, spx=0, spy=0):
function fill_symmetric_const_space (line 183) | def fill_symmetric_const_space(area, sp_max, n_min, n_max, offset=0):
function fill_symmetric_min_density_info (line 264) | def fill_symmetric_min_density_info(area, targ_area, n_min, n_max, sp_min,
function fill_symmetric_max_density_info (line 349) | def fill_symmetric_max_density_info(area, targ_area, n_min, n_max, sp_min,
function fill_symmetric_max_density (line 462) | def fill_symmetric_max_density(area, # type: int
class InsufficientAreaError (line 519) | class InsufficientAreaError(ValueError):
class FillTooSmallError (line 523) | class FillTooSmallError(ValueError):
class NoFillAbutEdgeError (line 527) | class NoFillAbutEdgeError(ValueError):
class NoFillChoiceError (line 531) | class NoFillChoiceError(ValueError):
class EmptyRegionError (line 535) | class EmptyRegionError(ValueError):
function fill_symmetric_max_num_info (line 539) | def fill_symmetric_max_num_info(tot_area, nfill, n_min, n_max, sp_min,
function _fill_symmetric_info (line 625) | def _fill_symmetric_info(tot_area, num_blk_tot, sp, inc_sp=True, fill_on...
function _get_min_max_blk_len (line 800) | def _get_min_max_blk_len(fill_info):
function fill_symmetric_interval (line 808) | def fill_symmetric_interval(tot_area, sp, num_diff_sp, sp_edge, blk0, bl...
function fill_symmetric_helper (line 894) | def fill_symmetric_helper(tot_area, num_blk_tot, sp, offset=0, inc_sp=Tr...
FILE: bag/layout/routing/grid.py
class RoutingGrid (line 18) | class RoutingGrid(object):
method __init__ (line 51) | def __init__(self, # type: RoutingGrid
method __contains__ (line 101) | def __contains__(self, layer):
method get_middle_track (line 107) | def get_middle_track(cls, tr1, tr2, round_up=False):
method _get_track_offset (line 118) | def _get_track_offset(self, layer_id):
method get_flip_parity (line 124) | def get_flip_parity(self):
method get_bot_common_layer (line 129) | def get_bot_common_layer(self, inst_grid, inst_top_layer):
method get_flip_parity_at (line 160) | def get_flip_parity_at(self, # type: RoutingGrid
method set_flip_parity (line 226) | def set_flip_parity(self, fp):
method tech_info (line 233) | def tech_info(self):
method resolution (line 239) | def resolution(self):
method layout_unit (line 245) | def layout_unit(self):
method top_private_layer (line 251) | def top_private_layer(self):
method update_block_pitch (line 256) | def update_block_pitch(self):
method _update_block_pitch_helper (line 272) | def _update_block_pitch_helper(self, lay_list):
method get_direction (line 290) | def get_direction(self, layer_id):
method get_track_pitch (line 306) | def get_track_pitch(self, layer_id, unit_mode=False):
method get_track_width (line 325) | def get_track_width(self, layer_id, width_ntr, unit_mode=False):
method get_track_width_inverse (line 351) | def get_track_width_inverse(self, layer_id, width, mode=-1, unit_mode=...
method get_num_tracks (line 398) | def get_num_tracks(self, size, layer_id):
method get_min_length (line 426) | def get_min_length(self, layer_id, width_ntr, unit_mode=False):
method get_space (line 457) | def get_space(self, layer_id, width_ntr, same_color=False, unit_mode=F...
method get_num_space_tracks (line 489) | def get_num_space_tracks(self, layer_id, width_ntr, half_space=False, ...
method get_line_end_space (line 529) | def get_line_end_space(self, layer_id, width_ntr, unit_mode=False):
method get_line_end_space_tracks (line 557) | def get_line_end_space_tracks(self, wire_layer, space_layer, width_ntr...
method get_max_track_width (line 600) | def get_max_track_width(self, layer_id, num_tracks, tot_space, half_en...
method get_evenly_spaced_tracks (line 640) | def get_evenly_spaced_tracks(num_tracks, tot_space, track_width, half_...
method get_block_size (line 680) | def get_block_size(self, layer_id, unit_mode=False, include_private=Fa...
method get_fill_size (line 736) | def get_fill_size(self, # type: RoutingGrid
method size_defined (line 790) | def size_defined(self, layer_id):
method get_size_pitch (line 795) | def get_size_pitch(self, layer_id, unit_mode=False):
method get_size_tuple (line 827) | def get_size_tuple(self, # type: RoutingGrid
method get_size_dimension (line 888) | def get_size_dimension(self, # type: RoutingGrid
method convert_size (line 917) | def convert_size(self, size, new_top_layer):
method get_track_info (line 936) | def get_track_info(self, layer_id, unit_mode=False):
method get_track_parity (line 959) | def get_track_parity(self, layer_id, tr_idx):
method get_layer_name (line 983) | def get_layer_name(self, layer_id, tr_idx):
method get_wire_bounds (line 1007) | def get_wire_bounds(self, layer_id, tr_idx, width=1, unit_mode=False):
method get_bbox (line 1037) | def get_bbox(self, layer_id, tr_idx, lower, upper, width=1, unit_mode=...
method get_min_track_width (line 1073) | def get_min_track_width(self, layer_id, idc=0, iac_rms=0, iac_peak=0, ...
method get_min_track_width_for_via (line 1178) | def get_min_track_width_for_via(self,
method get_track_index_range (line 1202) | def get_track_index_range(self, # type: RoutingGrid
method get_overlap_tracks (line 1287) | def get_overlap_tracks(self, # type: RoutingGrid
method get_via_extensions_dim (line 1329) | def get_via_extensions_dim(self, # type: RoutingGrid
method get_via_extensions (line 1388) | def get_via_extensions(self, bot_layer_id, bot_width, top_width, unit_...
method coord_to_track (line 1414) | def coord_to_track(self, layer_id, coord, unit_mode=False):
method find_next_track (line 1445) | def find_next_track(self, layer_id, coord, tr_width=1, half_track=False,
method coord_to_nearest_track (line 1482) | def coord_to_nearest_track(self, layer_id, coord, half_track=False, mo...
method coord_to_nearest_fill_track (line 1549) | def coord_to_nearest_fill_track(self, layer_id, coord, fill_config, mo...
method transform_track (line 1579) | def transform_track(self, # type: RoutingGrid
method track_to_coord (line 1638) | def track_to_coord(self, layer_id, track_idx, unit_mode=False):
method interval_to_track (line 1662) | def interval_to_track(self, # type: RoutingGrid
method copy (line 1710) | def copy(self):
method ignore_layers_under (line 1735) | def ignore_layers_under(self, layer_id):
method add_new_layer (line 1749) | def add_new_layer(self, layer_id, tr_space, tr_width, direction,
method set_track_offset (line 1816) | def set_track_offset(self, layer_id, offset, unit_mode=False):
method add_width_override (line 1834) | def add_width_override(self, layer_id, width_ntr, tr_width, unit_mode=...
FILE: bag/layout/tech.py
class TechInfoConfig (line 14) | class TechInfoConfig(TechInfo, metaclass=abc.ABCMeta):
method __init__ (line 16) | def __init__(self, config, tech_params, mos_entry_name='mos'):
method get_metal_em_specs (line 26) | def get_metal_em_specs(self, layer_name, w, l=-1, vertical=False, **kw...
method get_via_em_specs (line 30) | def get_via_em_specs(self, via_name, bm_layer, tm_layer, via_type='squ...
method get_res_em_specs (line 35) | def get_res_em_specs(self, res_type, w, l=-1, **kwargs):
method add_cell_boundary (line 39) | def add_cell_boundary(self, template, box):
method draw_device_blockage (line 44) | def draw_device_blockage(self, template):
method get_via_arr_enc (line 49) | def get_via_arr_enc(self, vname, vtype, mtype, mw_unit, is_bot):
method pin_purpose (line 54) | def pin_purpose(self):
method get_via_types (line 57) | def get_via_types(self, bmtype, tmtype):
method get_well_layers (line 64) | def get_well_layers(self, sub_type):
method get_implant_layers (line 68) | def get_implant_layers(self, mos_type, res_type=None):
method get_threshold_layers (line 77) | def get_threshold_layers(self, mos_type, threshold, res_type=None):
method get_exclude_layer (line 86) | def get_exclude_layer(self, layer_id):
method get_dnw_margin_unit (line 91) | def get_dnw_margin_unit(self, dnw_mode):
method get_dnw_layers (line 95) | def get_dnw_layers(self):
method get_res_metal_layers (line 99) | def get_res_metal_layers(self, layer_id):
method get_metal_dummy_layers (line 103) | def get_metal_dummy_layers(self, layer_id):
method use_flip_parity (line 107) | def use_flip_parity(self):
method get_layer_name (line 111) | def get_layer_name(self, layer_id):
method get_layer_id (line 116) | def get_layer_id(self, layer_name):
method get_layer_type (line 123) | def get_layer_type(self, layer_name):
method get_idc_scale_factor (line 128) | def get_idc_scale_factor(self, temp, mtype, is_res=False):
method get_via_name (line 146) | def get_via_name(self, bot_layer_id):
method get_via_id (line 150) | def get_via_id(self, bot_layer, top_layer):
method get_via_drc_info (line 154) | def get_via_drc_info(self, vname, vtype, mtype, mw_unit, is_bot):
method _space_helper (line 214) | def _space_helper(self, config_name, layer_type, width):
method get_min_space_unit (line 228) | def get_min_space_unit(self, layer_type, w_unit, same_color=False):
method get_min_line_end_space_unit (line 237) | def get_min_line_end_space_unit(self, layer_type, w_unit):
method get_min_space (line 240) | def get_min_space(self, layer_type, width, unit_mode=False, same_color...
method get_min_line_end_space (line 252) | def get_min_line_end_space(self, layer_type, width, unit_mode=False):
method layer_id_to_type (line 264) | def layer_id_to_type(self, layer_id):
method get_min_length_unit (line 269) | def get_min_length_unit(self, layer_type, w_unit):
method get_min_length (line 294) | def get_min_length(self, layer_type, width):
method get_res_rsquare (line 299) | def get_res_rsquare(self, res_type):
method get_res_width_bounds (line 302) | def get_res_width_bounds(self, res_type):
method get_res_length_bounds (line 305) | def get_res_length_bounds(self, res_type):
method get_res_min_nsquare (line 308) | def get_res_min_nsquare(self, res_type):
FILE: bag/layout/template.py
class TemplateDB (line 52) | class TemplateDB(MasterDB):
method __init__ (line 82) | def __init__(self, # type: TemplateDB
method create_master_instance (line 133) | def create_master_instance(self, gen_cls, lib_name, params, used_cell_...
method create_masters_in_db (line 160) | def create_masters_in_db(self, lib_name, content_list, debug=False):
method grid (line 232) | def grid(self):
method new_template (line 237) | def new_template(self, lib_name='', temp_name='', params=None, temp_cl...
method instantiate_layout (line 268) | def instantiate_layout(self, prj, template, top_cell_name=None, debug=...
method batch_layout (line 287) | def batch_layout(self,
method save_to_cache (line 317) | def save_to_cache(self, temp_list, dir_name, debug=False):
method _create_gds (line 333) | def _create_gds(self, lib_name, content_list, debug=False):
method _add_gds_via (line 454) | def _add_gds_via(self, gds_cell, via, lay_map, via_lay_info, x0, y0):
class TemplateBase (line 496) | class TemplateBase(DesignMaster, metaclass=abc.ABCMeta):
method __init__ (line 527) | def __init__(self, temp_db, lib_name, params, used_names, **kwargs):
method draw_layout (line 564) | def draw_layout(self):
method populate_params (line 574) | def populate_params(self, table, params_info, default_params, **kwargs):
method get_master_basename (line 592) | def get_master_basename(self):
method get_layout_basename (line 603) | def get_layout_basename(self):
method get_content (line 614) | def get_content(self, lib_name, rename_fun):
method finalize (line 634) | def finalize(self):
method get_cache_properties (line 690) | def get_cache_properties(cls):
method template_db (line 696) | def template_db(self):
method is_empty (line 703) | def is_empty(self):
method grid (line 709) | def grid(self):
method grid (line 715) | def grid(self, new_grid):
method array_box (line 724) | def array_box(self):
method array_box (line 730) | def array_box(self, new_array_box):
method fill_box (line 739) | def fill_box(self):
method fill_box (line 745) | def fill_box(self, new_box):
method top_layer (line 754) | def top_layer(self):
method size (line 764) | def size(self):
method bound_box (line 770) | def bound_box(self):
method size (line 783) | def size(self, new_size):
method used_tracks (line 792) | def used_tracks(self):
method _update_flip_parity (line 796) | def _update_flip_parity(self):
method instance_iter (line 808) | def instance_iter(self):
method blockage_iter (line 811) | def blockage_iter(self, layer_id, test_box, spx=0, spy=0):
method all_rect_iter (line 819) | def all_rect_iter(self):
method intersection_rect_iter (line 827) | def intersection_rect_iter(self, layer_id, box):
method open_interval_iter (line 834) | def open_interval_iter(self, # type: TemplateBase
method is_track_available (line 866) | def is_track_available(self, # type: TemplateBase
method get_rect_bbox (line 906) | def get_rect_bbox(self, layer):
method get_track_bbox (line 924) | def get_track_bbox(self, layer_id):
method track_bbox_iter (line 932) | def track_bbox_iter(self):
method new_template_with (line 938) | def new_template_with(self, **kwargs):
method set_size_from_bound_box (line 959) | def set_size_from_bound_box(self, top_layer_id, bbox, round_up=False,
method set_size_from_array_box (line 986) | def set_size_from_array_box(self, top_layer_id):
method write_summary_file (line 1011) | def write_summary_file(self, fname, lib_name, cell_name):
method write_to_disk (line 1050) | def write_to_disk(self, fname, lib_name, cell_name, debug=False):
method merge_inst_tracks (line 1086) | def merge_inst_tracks(self):
method get_pin_name (line 1096) | def get_pin_name(self, name):
method get_port (line 1116) | def get_port(self, name=''):
method has_port (line 1137) | def has_port(self, port_name):
method port_names_iter (line 1142) | def port_names_iter(self):
method get_prim_port (line 1153) | def get_prim_port(self, name=''):
method has_prim_port (line 1174) | def has_prim_port(self, port_name):
method prim_port_names_iter (line 1179) | def prim_port_names_iter(self):
method new_template (line 1190) | def new_template(self, params=None, temp_cls=None, debug=False, **kwar...
method move_all_by (line 1214) | def move_all_by(self, dx=0.0, dy=0.0, unit_mode=False):
method add_instance (line 1232) | def add_instance(self, # type: TemplateBase
method add_instance_primitive (line 1285) | def add_instance_primitive(self, # type: TemplateBase
method add_rect (line 1339) | def add_rect(self, # type: TemplateBase
method add_res_metal (line 1379) | def add_res_metal(self, layer_id, bbox, **kwargs):
method add_path (line 1404) | def add_path(self, path):
method add_polygon (line 1494) | def add_polygon(self, polygon):
method add_blockage (line 1511) | def add_blockage(self, blockage):
method add_cell_boundary (line 1528) | def add_cell_boundary(self, box):
method add_boundary (line 1541) | def add_boundary(self, boundary):
method reexport (line 1558) | def reexport(self, port, net_name='', label='', show=True):
method add_pin_primitive (line 1603) | def add_pin_primitive(self, net_name, layer, bbox, label='', show=True):
method add_label (line 1643) | def add_label(self, label, layer, bbox):
method add_pin (line 1660) | def add_pin(self, net_name, wire_arr_list, label='', show=True, edge_m...
method add_via (line 1723) | def add_via(self, # type: TemplateBase
method add_via_primitive (line 1777) | def add_via_primitive(self, via_type, # type: str
method add_via_on_grid (line 1856) | def add_via_on_grid(self, bot_layer_id, bot_track, top_track, bot_widt...
method extend_wires (line 1889) | def extend_wires(self, # type: TemplateBase
method add_wires (line 1971) | def add_wires(self, # type: TemplateBase
method add_res_metal_warr (line 2021) | def add_res_metal_warr(self, # type: TemplateBase
method add_mom_cap (line 2055) | def add_mom_cap(self, # type: TemplateBase
method reserve_tracks (line 2340) | def reserve_tracks(self, # type: TemplateBase
method connect_wires (line 2380) | def connect_wires(self, # type: TemplateBase
method _draw_via_on_track (line 2556) | def _draw_via_on_track(self, wlayer, box_arr, track_id, tl_unit=None,
method connect_bbox_to_tracks (line 2619) | def connect_bbox_to_tracks(self, # type: TemplateBase
method connect_bbox_to_differential_tracks (line 2722) | def connect_bbox_to_differential_tracks(self, # type: TemplateBase
method connect_bbox_to_matching_tracks (line 2776) | def connect_bbox_to_matching_tracks(self, # type: TemplateBase
method connect_to_tracks (line 2899) | def connect_to_tracks(self, # type: TemplateBase
method connect_to_track_wires (line 3048) | def connect_to_track_wires(self, # type: TemplateBase
method connect_with_via_stack (line 3098) | def connect_with_via_stack(self, # type: TemplateBase
method strap_wires (line 3239) | def strap_wires(self, # type: TemplateBase
method _strap_wires_helper (line 3299) | def _strap_wires_helper(self, # type: TemplateBase
method connect_differential_tracks (line 3394) | def connect_differential_tracks(self, # type: TemplateBase
method connect_differential_wires (line 3449) | def connect_differential_wires(self, # type: TemplateBase
method connect_matching_tracks (line 3486) | def connect_matching_tracks(self, # type: TemplateBase
method draw_vias_on_intersections (line 3624) | def draw_vias_on_intersections(self, bot_warr_list, top_warr_list):
method mark_bbox_used (line 3687) | def mark_bbox_used(self, layer_id, bbox):
method get_available_tracks (line 3694) | def get_available_tracks(self, # type: TemplateBase
method do_power_fill (line 3715) | def do_power_fill(self, # type: TemplateBase
method do_max_space_fill2 (line 3810) | def do_max_space_fill2(self, # type: TemplateBase
method do_max_space_fill (line 3979) | def do_max_space_fill(self, # type: TemplateBase
method _fill_poly_bounds (line 4097) | def _fill_poly_bounds(self, poly, layer_id, is_horiz, min_len2, fill_p...
method _get_flat_poly_iter (line 4144) | def _get_flat_poly_iter(cls, poly):
method _fill_long_edge_helper (line 4152) | def _fill_long_edge_helper(self, layer_id, grid, tot_geo, long_box, co...
method _fill_tran_edge_helper (line 4184) | def _fill_tran_edge_helper(self, layer_id, grid, tot_geo, tran_box, tr...
class CachedTemplate (line 4205) | class CachedTemplate(TemplateBase):
method __init__ (line 4208) | def __init__(self, temp_db, lib_name, params, used_names, **kwargs):
method get_params_info (line 4213) | def get_params_info(cls):
method draw_layout (line 4219) | def draw_layout(self):
class BlackBoxTemplate (line 4243) | class BlackBoxTemplate(TemplateBase):
method __init__ (line 4246) | def __init__(self, temp_db, lib_name, params, used_names, **kwargs):
method sch_params (line 4252) | def sch_params(self):
method get_params_info (line 4257) | def get_params_info(cls):
method get_layout_basename (line 4268) | def get_layout_basename(self):
method draw_layout (line 4271) | def draw_layout(self):
method _register_pin (line 4302) | def _register_pin(self, lay_id, lay_name, term_name, box, show_pins):
FILE: bag/layout/util.py
function tuple2_to_int (line 26) | def tuple2_to_int(input_tuple: Tuple[Any, Any]) -> Tuple[int, int]:
function tuple2_to_float_int (line 35) | def tuple2_to_float_int(input_tuple: Tuple[Any, Any]) -> Tuple[float, int]:
function transform_point (line 44) | def transform_point(x, y, loc, orient):
function get_inverse_transform (line 55) | def get_inverse_transform(loc, orient):
function transform_loc_orient (line 69) | def transform_loc_orient(loc, orient, trans_loc, trans_orient):
class PortSpec (line 81) | class PortSpec(object):
method __init__ (line 92) | def __init__(self, ntr, idc):
method ntr (line 97) | def ntr(self):
method idc (line 102) | def idc(self):
method __str__ (line 106) | def __str__(self):
method __repr__ (line 109) | def __repr__(self):
class BBox (line 114) | class BBox(object):
method __init__ (line 134) | def __init__(self, left, bottom, right, top, resolution, unit_mode=Fal...
method get_invalid_bbox (line 152) | def get_invalid_bbox(cls):
method left (line 164) | def left(self):
method left_unit (line 169) | def left_unit(self):
method right (line 174) | def right(self):
method right_unit (line 179) | def right_unit(self):
method bottom (line 184) | def bottom(self):
method bottom_unit (line 189) | def bottom_unit(self):
method top (line 194) | def top(self):
method top_unit (line 199) | def top_unit(self):
method resolution (line 204) | def resolution(self):
method width (line 209) | def width(self):
method width_unit (line 214) | def width_unit(self):
method height (line 219) | def height(self):
method height_unit (line 224) | def height_unit(self):
method xc (line 229) | def xc(self):
method xc_unit (line 234) | def xc_unit(self):
method yc (line 239) | def yc(self):
method yc_unit (line 244) | def yc_unit(self):
method get_points (line 248) | def get_points(self, unit_mode=False):
method as_bbox_array (line 273) | def as_bbox_array(self):
method as_bbox_collection (line 277) | def as_bbox_collection(self):
method merge (line 281) | def merge(self, bbox):
method intersect (line 306) | def intersect(self, bbox):
method overlaps (line 326) | def overlaps(self, bbox):
method extend (line 335) | def extend(self, x=None, y=None, unit_mode=False):
method expand (line 367) | def expand(self, dx=0, dy=0, unit_mode=False):
method transform (line 392) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False):
method move_by (line 424) | def move_by(self, dx=0, dy=0, unit_mode=False):
method flip_xy (line 449) | def flip_xy(self):
method with_interval (line 455) | def with_interval(self, direction, lower, upper, unit_mode=False):
method get_interval (line 464) | def get_interval(self, direction, unit_mode=False):
method get_bounds (line 491) | def get_bounds(self, unit_mode=False):
method is_physical (line 510) | def is_physical(self):
method is_valid (line 520) | def is_valid(self):
method get_immutable_key (line 530) | def get_immutable_key(self):
method __str__ (line 535) | def __str__(self):
method __repr__ (line 538) | def __repr__(self):
method __hash__ (line 543) | def __hash__(self):
method __eq__ (line 546) | def __eq__(self, other):
class BBoxArray (line 550) | class BBoxArray(object):
method __init__ (line 571) | def __init__(self, bbox, nx=1, ny=1, spx=0, spy=0, unit_mode=False):
method __iter__ (line 590) | def __iter__(self):
method base (line 600) | def base(self):
method nx (line 606) | def nx(self):
method ny (line 612) | def ny(self):
method spx (line 618) | def spx(self):
method spx_unit (line 624) | def spx_unit(self):
method spy (line 630) | def spy(self):
method spy_unit (line 636) | def spy_unit(self):
method left (line 642) | def left(self):
method left_unit (line 648) | def left_unit(self):
method right (line 654) | def right(self):
method right_unit (line 660) | def right_unit(self):
method bottom (line 666) | def bottom(self):
method bottom_unit (line 672) | def bottom_unit(self):
method top (line 678) | def top(self):
method top_unit (line 684) | def top_unit(self):
method xc (line 690) | def xc(self):
method xc_unit (line 694) | def xc_unit(self):
method yc (line 699) | def yc(self):
method yc_unit (line 703) | def yc_unit(self):
method as_bbox_collection (line 707) | def as_bbox_collection(self):
method get_bbox (line 712) | def get_bbox(self, idx):
method get_overall_bbox (line 727) | def get_overall_bbox(self):
method move_by (line 738) | def move_by(self, dx=0, dy=0, unit_mode=False):
method transform (line 758) | def transform(self, loc=(0, 0), orient='R0', unit_mode=False):
method arrayed_copies (line 807) | def arrayed_copies(self, nx=1, ny=1, spx=0, spy=0, unit_mode=False):
method _array_helper (line 845) | def _array_helper(n1, sp1, n2, sp2):
method __str__ (line 861) | def __str__(self):
method __repr__ (line 864) | def __repr__(self):
class BBoxCollection (line 871) | class BBoxCollection(object):
method __init__ (line 883) | def __init__(self, box_arr_list):
method __iter__ (line 886) | def __iter__(self):
method __reversed__ (line 890) | def __reversed__(self):
method __len__ (line 893) | def __len__(self):
method as_bbox_array (line 896) | def as_bbox_array(self):
method as_bbox (line 914) | def as_bbox(self):
method get_bounding_box (line 934) | def get_bounding_box(self):
method transform (line 950) | def transform(self, loc=(0, 0), orient='R0'):
method __str__ (line 970) | def __str__(self):
method __repr__ (line 973) | def __repr__(self):
class Pin (line 977) | class Pin(object):
method __init__ (line 994) | def __init__(self, pin_name, term_name, layer, bbox):
method pin_name (line 1004) | def pin_name(self):
method term_name (line 1009) | def term_name(self):
method layer (line 1014) | def layer(self):
method bbox (line 1019) | def bbox(self):
method __str__ (line 1023) | def __str__(self):
method __repr__ (line 1026) | def __repr__(self):
FILE: bag/math/__init__.py
function float_to_si_string (line 18) | def float_to_si_string(num, precision=6):
function si_string_to_float (line 48) | def si_string_to_float(si_str):
function gcd (line 68) | def gcd(a, b):
function lcm (line 89) | def lcm(arr, init=1):
FILE: bag/math/dfun.py
class DiffFunction (line 12) | class DiffFunction(abc.ABC):
method __init__ (line 26) | def __init__(self, input_ranges, delta_list=None):
method input_ranges (line 37) | def input_ranges(self):
method ndim (line 42) | def ndim(self):
method __call__ (line 48) | def __call__(self, xi):
method get_input_range (line 65) | def get_input_range(self, idx):
method deriv (line 70) | def deriv(self, xi, j):
method jacobian (line 89) | def jacobian(self, xi):
method _fd (line 116) | def _fd(self, xi, idx, delta):
method _fd_jacobian (line 152) | def _fd_jacobian(self, xi, delta_list):
method transform_input (line 184) | def transform_input(self, amat, bmat):
method __add__ (line 202) | def __add__(self, other):
method __radd__ (line 213) | def __radd__(self, other):
method __sub__ (line 217) | def __sub__(self, other):
method __rsub__ (line 228) | def __rsub__(self, other):
method __mul__ (line 239) | def __mul__(self, other):
method __rmul__ (line 250) | def __rmul__(self, other):
method __pow__ (line 254) | def __pow__(self, other):
method __div__ (line 263) | def __div__(self, other):
method __truediv__ (line 274) | def __truediv__(self, other):
method __rdiv__ (line 278) | def __rdiv__(self, other):
method __rtruediv__ (line 289) | def __rtruediv__(self, other):
method __neg__ (line 293) | def __neg__(self):
class InLinTransformFunction (line 298) | class InLinTransformFunction(DiffFunction):
method __init__ (line 312) | def __init__(self, f1, amat, bmat):
method _get_arg (line 325) | def _get_arg(self, xi):
method __call__ (line 335) | def __call__(self, xi):
method deriv (line 342) | def deriv(self, xi, j):
method jacobian (line 346) | def jacobian(self, xi):
class ScaleAddFunction (line 353) | class ScaleAddFunction(DiffFunction):
method __init__ (line 365) | def __init__(self, f1, adder, scaler):
method __call__ (line 372) | def __call__(self, xi):
method deriv (line 375) | def deriv(self, xi, j):
method jacobian (line 378) | def jacobian(self, xi):
function _intersection (line 382) | def _intersection(*args):
class SumDiffFunction (line 402) | class SumDiffFunction(DiffFunction):
method __init__ (line 414) | def __init__(self, f1, f2, f2_sgn=1.0):
method __call__ (line 424) | def __call__(self, xi):
method deriv (line 427) | def deriv(self, xi, j):
method jacobian (line 430) | def jacobian(self, xi):
class ProdFunction (line 434) | class ProdFunction(DiffFunction):
method __init__ (line 444) | def __init__(self, f1, f2):
method __call__ (line 453) | def __call__(self, xi):
method deriv (line 456) | def deriv(self, xi, j):
method jacobian (line 459) | def jacobian(self, xi):
class DivFunction (line 467) | class DivFunction(DiffFunction):
method __init__ (line 477) | def __init__(self, f1, f2):
method __call__ (line 486) | def __call__(self, xi):
method deriv (line 489) | def deriv(self, xi, j):
method jacobian (line 493) | def jacobian(self, xi):
class PwrFunction (line 502) | class PwrFunction(DiffFunction):
method __init__ (line 514) | def __init__(self, f, pwr, scale=1.0):
method __call__ (line 521) | def __call__(self, xi):
method deriv (line 524) | def deriv(self, xi, j):
method jacobian (line 527) | def jacobian(self, xi):
class VectorDiffFunction (line 533) | class VectorDiffFunction(object):
method __init__ (line 542) | def __init__(self, fun_list):
method in_dim (line 559) | def in_dim(self):
method out_dim (line 565) | def out_dim(self):
method get_input_range (line 570) | def get_input_range(self, idx):
method __call__ (line 575) | def __call__(self, xi):
method jacobian (line 595) | def jacobian(self, xi):
method deriv (line 615) | def deriv(self, xi, i, j):
FILE: bag/math/interpolate.py
function _scales_to_points (line 18) | def _scales_to_points(scale_list, values, delta=1e-4):
function interpolate_grid (line 42) | def interpolate_grid(scale_list, values, method='spline',
class LinearInterpolator (line 91) | class LinearInterpolator(DiffFunction):
method __init__ (line 109) | def __init__(self, points, values, delta_list, extrapolate=False):
method get_input_points (line 119) | def get_input_points(self, idx):
method __call__ (line 124) | def __call__(self, xi):
method integrate (line 142) | def integrate(self, xstart, xstop, axis=-1, logx=False, logy=False, ra...
class Interpolator1D (line 268) | class Interpolator1D(DiffFunction):
method __init__ (line 285) | def __init__(self, scale_list, values, method='spline', extrapolate=Fa...
method __call__ (line 308) | def __call__(self, xi):
method deriv (line 326) | def deriv(self, xi, idx):
class Spline2D (line 350) | class Spline2D(DiffFunction):
method __init__ (line 365) | def __init__(self, scale_list, values, extrapolate=False):
method _get_xy (line 386) | def _get_xy(self, xi):
method __call__ (line 402) | def __call__(self, xi):
method deriv (line 418) | def deriv(self, xi, idx):
class MapCoordinateSpline (line 443) | class MapCoordinateSpline(DiffFunction):
method __init__ (line 472) | def __init__(self, scale_list, values, extrapolate=False, num_extrapol...
method _normalize_inputs (line 502) | def _normalize_inputs(self, xi):
method __call__ (line 519) | def __call__(self, xi):
FILE: bag/mdao/components.py
class VecFunComponent (line 10) | class VecFunComponent(omdao.Component):
method __init__ (line 33) | def __init__(self, output_name, fun_list, params,
method __call__ (line 62) | def __call__(self, **kwargs):
method _get_inputs (line 79) | def _get_inputs(self, params):
method solve_nonlinear (line 97) | def solve_nonlinear(self, params, unknowns, resids=None):
method linearize (line 119) | def linearize(self, params, unknowns=None, resids=None):
FILE: bag/mdao/core.py
class GroupBuilder (line 14) | class GroupBuilder(object):
method __init__ (line 23) | def __init__(self):
method _add_node (line 27) | def _add_node(self, name, ndim, **kwargs):
method _add_edge (line 32) | def _add_edge(self, parent, child):
method get_inputs (line 40) | def get_inputs(self):
method get_variables (line 50) | def get_variables(self):
method get_variable_info (line 60) | def get_variable_info(self, name):
method add_fun (line 80) | def add_fun(self, var_name, fun_list, params, param_ranges, vector_par...
method add_var (line 139) | def add_var(self, variable, vmin, vmax, ndim=1):
method set_input_limit (line 157) | def set_input_limit(self, var, equals=None, lower=None, upper=None):
method add_expr (line 185) | def add_expr(self, eqn, ndim):
method build (line 217) | def build(self, debug=False):
FILE: bag/simulation/core.py
class TestbenchManager (line 23) | class TestbenchManager(object, metaclass=abc.ABCMeta):
method __init__ (line 43) | def __init__(self,
method setup_testbench (line 60) | def setup_testbench(self, tb):
method setup_and_simulate (line 74) | async def setup_and_simulate(self, prj: BagProject,
method record_array (line 99) | def record_array(cls, output_dict, data_dict, arr, arr_name, sweep_par...
method _create_tb_schematic (line 132) | def _create_tb_schematic(self, prj, sch_params):
class MeasurementManager (line 157) | class MeasurementManager(object, metaclass=abc.ABCMeta):
method __init__ (line 184) | def __init__(self, # type: MeasurementManager
method get_initial_state (line 205) | def get_initial_state(self):
method get_testbench_info (line 211) | def get_testbench_info(self, # type: MeasurementManager
method process_output (line 248) | def process_output(self, state, data, tb_manager):
method get_testbench_name (line 272) | def get_testbench_name(self, tb_type):
method async_measure_performance (line 277) | async def async_measure_performance(self,
method get_state_output (line 339) | def get_state_output(self, state):
method get_testbench_specs (line 345) | def get_testbench_specs(self, tb_type):
method get_default_tb_sch_params (line 350) | def get_default_tb_sch_params(self, tb_type):
class DesignManager (line 380) | class DesignManager(object):
method __init__ (line 395) | def __init__(self, prj, spec_file):
method load_state (line 412) | def load_state(cls, prj, root_dir):
method get_measurement_name (line 418) | def get_measurement_name(cls, dsn_name, meas_type):
method get_wrapper_name (line 437) | def get_wrapper_name(cls, dut_name, wrapper_name):
method specs (line 443) | def specs(self):
method swp_var_list (line 449) | def swp_var_list(self):
method extract_design (line 453) | async def extract_design(self, lib_name: str, dsn_name: str,
method verify_design (line 479) | async def verify_design(self, lib_name: str, dsn_name: str,
method main_task (line 530) | async def main_task(self, lib_name: str, dsn_name: str,
method characterize_designs (line 541) | def characterize_designs(self, generate=True, measure=True, load_from_...
method get_result (line 576) | def get_result(self, dsn_name):
method test_layout (line 595) | def test_layout(self, gen_sch=True):
method create_designs (line 614) | def create_designs(self, create_layout):
method get_swp_var_values (line 645) | def get_swp_var_values(self, var):
method get_combinations_iter (line 661) | def get_combinations_iter(self):
method get_dsn_name_iter (line 674) | def get_dsn_name_iter(self):
method get_measurement_directory (line 685) | def get_measurement_directory(self, dsn_name, meas_type):
method make_tdb (line 689) | def make_tdb(self):
method get_layout_params (line 713) | def get_layout_params(self, val_list):
method get_schematic_params (line 722) | def get_schematic_params(self, val_list):
method create_dut_schematics (line 731) | def create_dut_schematics(self, sch_params_list, cell_name_list, gen_w...
method create_dut_layouts (line 759) | def create_dut_layouts(self, lay_params_list, cell_name_list, temp_db):
method get_design_name (line 779) | def get_design_name(self, combo_list):
FILE: bag/simulation/core_v2.py
class TestbenchManager (line 21) | class TestbenchManager(abc.ABC):
method __init__ (line 32) | def __init__(self, work_dir: Path) -> None:
method work_dir (line 38) | def work_dir(self) -> Path:
method specs (line 42) | def specs(self):
method sim_vars (line 46) | def sim_vars(self):
method pre_setup (line 50) | def pre_setup(self, tb_params: Optional[Dict[str, Any]]) -> Optional[D...
method setup (line 66) | def setup(self, bprj, impl_lib, impl_cell, sim_view_list, env_list,
method setup_and_simulate (line 140) | async def setup_and_simulate(self, bprj, impl_lib, impl_cell, sim_view...
method simulate (line 155) | def simulate(self, bprj, impl_lib, impl_cell, sim_view_list, env_list,...
method load_results (line 166) | def load_results(self, impl_cell, tb_dict):
class MeasurementManager (line 179) | class MeasurementManager(abc.ABC):
method __init__ (line 181) | def __init__(self, work_dir: Path, mm_specs: Dict[str, Any]) -> None:
method specs (line 197) | def specs(self):
method work_dir (line 201) | def work_dir(self):
method _prepare_tb_specs (line 204) | def _prepare_tb_specs(self) -> None:
method _prepare_tbm_dict (line 213) | def _prepare_tbm_dict(self, impl_cell, tbm_dict, extract):
method _wrapper_exists (line 233) | def _wrapper_exists(self, wrapper: ImmutableType) -> bool:
method run_tb (line 237) | def run_tb(self, bprj, impl_lib, impl_cell, tb_name, tbm_dict=None, ex...
method run_flow (line 268) | def run_flow(self, bprj: BagProject, impl_lib: str, impl_cell: str,
method measure (line 296) | def measure(self, bprj: BagProject, impl_lib: str, impl_cell: str, loa...
FILE: bag/tech/core.py
function _equal (line 23) | def _equal(a, b, rtol, atol):
function _equal_list (line 34) | def _equal_list(a, b, rtol, atol):
function _index_in_list (line 44) | def _index_in_list(item_list, item, rtol, atol):
function _in_list (line 52) | def _in_list(item_list, item, rtol, atol):
class CircuitCharacterization (line 57) | class CircuitCharacterization(SimulationManager, metaclass=abc.ABCMeta):
method __init__ (line 88) | def __init__(self, prj, spec_file, tb_type, compression='gzip'):
method record_results (line 95) | def record_results(self, data, tb_type, val_list):
method get_sim_results (line 129) | def get_sim_results(self, tb_type, val_list):
method _get_env_result (line 134) | def _get_env_result(self, sim_results, env):
class CharDB (line 179) | class CharDB(abc.ABC):
method __init__ (line 220) | def __init__(self, # type: CharDB
method _convert_hdf5_array (line 327) | def _convert_hdf5_array(arr):
method _load_sim_data (line 334) | def _load_sim_data(self, # type: CharDB
method __getitem__ (line 453) | def __getitem__(self, param):
method __setitem__ (line 469) | def __setitem__(self, key, value):
method get_config (line 498) | def get_config(self, name):
method set_config (line 514) | def set_config(self, name, value):
method env_list (line 530) | def env_list(self):
method env_list (line 536) | def env_list(self, new_env_list):
method get_sim_file (line 542) | def get_sim_file(cls, root_dir, constants):
method get_cache_file (line 561) | def get_cache_file(cls, root_dir, constants):
method post_process_data (line 580) | def post_process_data(cls, sim_data, sweep_params, sweep_values, const...
method derived_parameters (line 603) | def derived_parameters(cls):
method compute_derived_parameters (line 609) | def compute_derived_parameters(cls, fdict):
method _get_function_index (line 625) | def _get_function_index(self, **kwargs):
method _get_function_helper (line 656) | def _get_function_helper(self, name, fidx_list):
method get_function (line 700) | def get_function(self, name, env='', **kwargs):
method get_fun_sweep_params (line 737) | def get_fun_sweep_params(self):
method _get_fun_arg (line 750) | def _get_fun_arg(self, **kwargs):
method query (line 762) | def query(self, **kwargs):
method minimize (line 791) | def minimize(self, # type: CharDB
FILE: bag/tech/mos.py
class MosCharDB (line 14) | class MosCharDB(CharDB):
method __init__ (line 50) | def __init__(self, root_dir, mos_type, discrete_params, env_list,
method get_sim_file (line 58) | def get_sim_file(cls, root_dir, constants):
method get_cache_file (line 76) | def get_cache_file(cls, root_dir, constants):
method post_process_data (line 94) | def post_process_data(cls, sim_data, sweep_params, sweep_values, const...
method derived_parameters (line 145) | def derived_parameters(cls):
method compute_derived_parameters (line 150) | def compute_derived_parameters(cls, fdict):
class MosCharGDDB (line 175) | class MosCharGDDB(CharDB):
method __init__ (line 211) | def __init__(self, root_dir, mos_type, discrete_params, env_list,
method get_sim_file (line 219) | def get_sim_file(cls, root_dir, constants):
method get_cache_file (line 237) | def get_cache_file(cls, root_dir, constants):
method post_process_data (line 255) | def post_process_data(cls, sim_data, sweep_params, sweep_values, const...
method derived_parameters (line 298) | def derived_parameters(cls):
method compute_derived_parameters (line 303) | def compute_derived_parameters(cls, fdict):
FILE: bag/util/cache.py
function _get_unique_name (line 20) | def _get_unique_name(basename, *args):
class ClassImporter (line 72) | class ClassImporter(object):
method __init__ (line 82) | def __init__(self, lib_defs):
method append_library (line 105) | def append_library(self, lib_name, lib_path):
method get_library_path (line 120) | def get_library_path(self, lib_name):
method get_class (line 135) | def get_class(self, lib_name, cell_name):
class DesignMaster (line 163) | class DesignMaster(abc.ABC):
method __init__ (line 181) | def __init__(self, master_db, lib_name, params, used_names, **kwargs):
method update_master_info (line 206) | def update_master_info(self):
method populate_params (line 210) | def populate_params(self, table, params_info, default_params, **kwargs):
method to_immutable_id (line 228) | def to_immutable_id(cls, val):
method get_params_info (line 250) | def get_params_info(cls):
method get_default_param_values (line 262) | def get_default_param_values(cls):
method get_master_basename (line 279) | def get_master_basename(self):
method get_content (line 291) | def get_content(self, lib_name, rename_fun):
method master_db (line 310) | def master_db(self):
method lib_name (line 316) | def lib_name(self):
method cell_name (line 322) | def cell_name(self):
method key (line 328) | def key(self):
method finalized (line 334) | def finalized(self):
method prelim_key (line 340) | def prelim_key(self):
method _get_qualified_name (line 345) | def _get_qualified_name(self):
method finalize (line 354) | def finalize(self):
method compute_unique_key (line 360) | def compute_unique_key(self):
class MasterDB (line 375) | class MasterDB(abc.ABC):
method __init__ (line 393) | def __init__(self, lib_name, lib_defs='', name_prefix='', name_suffix=...
method clear (line 406) | def clear(self):
method create_master_instance (line 413) | def create_master_instance(self, gen_cls, lib_name, params, used_cell_...
method create_masters_in_db (line 440) | def create_masters_in_db(self, lib_name, content_list, debug=False):
method lib_name (line 456) | def lib_name(self):
method cell_prefix (line 462) | def cell_prefix(self):
method cell_prefix (line 468) | def cell_prefix(self, new_val):
method cell_suffix (line 474) | def cell_suffix(self):
method cell_suffix (line 480) | def cell_suffix(self, new_val):
method used_cell_names (line 486) | def used_cell_names(self):
method format_cell_name (line 490) | def format_cell_name(self, cell_name):
method append_library (line 507) | def append_library(self, lib_name, lib_path):
method get_library_path (line 523) | def get_library_path(self, lib_name):
method get_generator_class (line 543) | def get_generator_class(self, lib_name, cell_name):
method new_master (line 564) | def new_master(self, # type: MasterDB
method register_master (line 649) | def register_master(self, key, master):
method instantiate_masters (line 653) | def instantiate_masters(self,
method _instantiate_master_helper (line 733) | def _instantiate_master_helper(self, info_dict, master):
FILE: bag/util/immutable.py
function combine_hash (line 17) | def combine_hash(a: int, b: int) -> int:
class ImmutableList (line 36) | class ImmutableList(Hashable, Sequence, Generic[T]):
method __init__ (line 39) | def __init__(self, values: Optional[Sequence[T]] = None) -> None:
method sequence_equal (line 53) | def sequence_equal(cls, a: Sequence[T], b: Sequence[T]) -> bool:
method __repr__ (line 61) | def __repr__(self) -> str:
method __eq__ (line 64) | def __eq__(self, other: Any) -> bool:
method __hash__ (line 68) | def __hash__(self) -> int:
method __bool__ (line 71) | def __bool__(self) -> bool:
method __len__ (line 74) | def __len__(self) -> int:
method __iter__ (line 77) | def __iter__(self) -> Iterable[T]:
method __getitem__ (line 81) | def __getitem__(self, idx: int) -> T: ...
method __getitem__ (line 83) | def __getitem__(self, idx: slice) -> ImmutableList[T]: ...
method __getitem__ (line 85) | def __getitem__(self, idx) -> T:
method __contains__ (line 90) | def __contains__(self, val: Any) -> bool:
class ImmutableSortedDict (line 94) | class ImmutableSortedDict(Hashable, Mapping, Generic[T, U]):
method __init__ (line 97) | def __init__(self,
method __repr__ (line 113) | def __repr__(self) -> str:
method __eq__ (line 116) | def __eq__(self, other: Any) -> bool:
method __hash__ (line 122) | def __hash__(self) -> int:
method __bool__ (line 125) | def __bool__(self) -> bool:
method __len__ (line 128) | def __len__(self) -> int:
method __iter__ (line 131) | def __iter__(self) -> Iterable[T]:
method __contains__ (line 134) | def __contains__(self, item: Any) -> bool:
method __getitem__ (line 138) | def __getitem__(self, item: T) -> U:
method get (line 144) | def get(self, item: T, default: Optional[U] = None) -> Optional[U]:
method keys (line 150) | def keys(self) -> Iterable[T]:
method values (line 153) | def values(self) -> Iterable[U]:
method items (line 156) | def items(self) -> Iterable[Tuple[T, U]]:
method copy (line 159) | def copy(self, append: Optional[Dict[T, Any]] = None) -> ImmutableSort...
method to_dict (line 167) | def to_dict(self) -> Dict[T, U]:
function to_immutable (line 174) | def to_immutable(obj: Any) -> ImmutableType:
FILE: bag/util/interval.py
class IntervalSet (line 11) | class IntervalSet(object):
method __init__ (line 24) | def __init__(self, intv_list=None, val_list=None):
method __contains__ (line 39) | def __contains__(self, key):
method __getitem__ (line 56) | def __getitem__(self, intv):
method __setitem__ (line 77) | def __setitem__(self, intv, value):
method __iter__ (line 98) | def __iter__(self):
method __len__ (line 109) | def __len__(self):
method get_start (line 120) | def get_start(self):
method get_end (line 131) | def get_end(self):
method get_interval (line 142) | def get_interval(self, idx):
method copy (line 153) | def copy(self):
method _get_first_overlap_idx (line 165) | def _get_first_overlap_idx(self, intv, abut=False):
method _get_last_overlap_idx (line 206) | def _get_last_overlap_idx(self, intv, abut=False):
method has_overlap (line 239) | def has_overlap(self, intv):
method has_single_cover (line 255) | def has_single_cover(self, intv):
method remove (line 263) | def remove(self, intv):
method get_intersection (line 287) | def get_intersection(self, other):
method get_complement (line 323) | def get_complement(self, total_intv):
method complement_iter (line 342) | def complement_iter(self, total_intv):
method remove_all_overlaps (line 360) | def remove_all_overlaps(self, intv):
method add (line 376) | def add(self, intv, val=None, merge=False, abut=False):
method subtract (line 422) | def subtract(self, intv):
method items (line 459) | def items(self):
method intervals (line 474) | def intervals(self):
method values (line 487) | def values(self):
method overlap_items (line 500) | def overlap_items(self, intv):
method overlap_intervals (line 522) | def overlap_intervals(self, intv):
method overlap_values (line 542) | def overlap_values(self, intv):
method get_first_overlap_item (line 562) | def get_first_overlap_item(self, intv):
method transform (line 570) | def transform(self, scale=1, shift=0):
FILE: bag/util/parse.py
class ExprVarScanner (line 9) | class ExprVarScanner(ast.NodeVisitor):
method __init__ (line 15) | def __init__(self):
method visit_Name (line 19) | def visit_Name(self, node):
method visit_Call (line 23) | def visit_Call(self, node):
method visit_Attribute (line 30) | def visit_Attribute(self, node):
function get_variables (line 35) | def get_variables(expr):
FILE: bag/util/search.py
class BinaryIterator (line 13) | class BinaryIterator(object):
method __init__ (line 29) | def __init__(self, low, high, step=1):
method set_current (line 58) | def set_current(self, val):
method has_next (line 65) | def has_next(self):
method get_next (line 70) | def get_next(self):
method up (line 75) | def up(self):
method down (line 88) | def down(self):
method save (line 94) | def save(self):
method save_info (line 99) | def save_info(self, info):
method get_last_save (line 105) | def get_last_save(self):
method get_last_save_info (line 112) | def get_last_save_info(self):
class FloatBinaryIterator (line 118) | class FloatBinaryIterator(object):
method __init__ (line 138) | def __init__(self, low, high, tol=1.0, search_step=1.0):
method has_next (line 157) | def has_next(self):
method get_next (line 162) | def get_next(self):
method up (line 167) | def up(self):
method down (line 180) | def down(self):
method save (line 186) | def save(self):
method save_info (line 191) | def save_info(self, info):
method get_last_save (line 197) | def get_last_save(self):
method get_last_save_info (line 204) | def get_last_save_info(self):
function minimize_cost_binary (line 210) | def minimize_cost_binary(f, vmin, start=0, stop=None, step=1, save=None,...
function minimize_cost_golden (line 262) | def minimize_cost_golden(f, vmin, offset=0, step=1, maxiter=1000):
function minimize_cost_binary_float (line 364) | def minimize_cost_binary_float(f, vmin, start, stop, tol=1e-8, save=None...
function minimize_cost_golden_float (line 416) | def minimize_cost_golden_float(f, vmin, start, stop, tol=1e-8, maxiter=1...
FILE: bag/verification/__init__.py
function make_checker (line 15) | def make_checker(checker_cls, tmp_dir, **kwargs):
FILE: bag/verification/base.py
class Checker (line 16) | class Checker(abc.ABC):
method __init__ (line 24) | def __init__(self, tmp_dir):
method get_rcx_netlists (line 30) | def get_rcx_netlists(self, lib_name, cell_name):
method async_run_lvs (line 49) | async def async_run_lvs(self, lib_name, cell_name, sch_view='schematic',
method async_run_rcx (line 82) | async def async_run_rcx(self, lib_name, cell_name, sch_view='schematic',
method async_export_layout (line 115) | async def async_export_layout(self, lib_name, cell_name, out_file,
method async_export_schematic (line 141) | async def async_export_schematic(self, lib_name, cell_name, out_file,
method render_file_template (line 166) | def render_file_template(self, temp_name, params):
method render_string_template (line 172) | def render_string_template(self, content, params):
class SubProcessChecker (line 179) | class SubProcessChecker(Checker, abc.ABC):
method __init__ (line 192) | def __init__(self, tmp_dir, max_workers, cancel_timeout):
method setup_lvs_flow (line 198) | def setup_lvs_flow(self, lib_name, cell_name, sch_view='schematic',
method setup_rcx_flow (line 242) | def setup_rcx_flow(self, lib_name, cell_name, sch_view='schematic',
method setup_export_layout (line 285) | def setup_export_layout(self, lib_name, cell_name, out_file, view_name...
method setup_export_schematic (line 316) | def setup_export_schematic(self, lib_name, cell_name, out_file,
method async_run_lvs (line 347) | async def async_run_lvs(self, lib_name: str, cell_name: str,
method async_run_rcx (line 357) | async def async_run_rcx(self, lib_name: str, cell_name: str,
method async_export_layout (line 366) | async def async_export_layout(self, lib_name: str, cell_name: str,
method async_export_schematic (line 373) | async def async_export_schematic(self, lib_name: str, cell_name: str,
FILE: bag/verification/calibre.py
function _all_pass (line 20) | def _all_pass(retcode, log_file):
function lvs_passed (line 25) | def lvs_passed(retcode, log_file):
function query_passed (line 54) | def query_passed(retcode, log_file):
class Calibre (line 82) | class Calibre(VirtuosoChecker):
method __init__ (line 106) | def __init__(self, tmp_dir, lvs_run_dir, lvs_runset, rcx_run_dir, rcx_...
method get_rcx_netlists (line 131) | def get_rcx_netlists(self, lib_name, cell_name):
method setup_lvs_flow (line 156) | def setup_lvs_flow(self, lib_name, cell_name, sch_view='schematic', la...
method setup_rcx_flow (line 208) | def setup_rcx_flow(self, lib_name, cell_name, sch_view='schematic', la...
method _get_lay_sch_files (line 354) | def _get_lay_sch_files(cls, run_dir):
method modify_lvs_runset (line 359) | def modify_lvs_runset(self, run_dir, lib_name, cell_name, lay_view, gd...
method modify_pex_runset (line 415) | def modify_pex_runset(self, run_dir, lib_name, cell_name, lay_view, gd...
method modify_xact_rules (line 478) | def modify_xact_rules(self, run_dir, cell_name, gds_file, netlist, xac...
method modify_starrc_cmd (line 520) | def modify_starrc_cmd(self, run_dir, lib_name, cell_name, starrc_param...
method modify_qrc_cmd (line 567) | def modify_qrc_cmd(self, run_dir, cell_name, qrc_params, sch_file):
FILE: bag/verification/icv.py
function _all_pass (line 19) | def _all_pass(retcode, log_file):
function lvs_passed (line 24) | def lvs_passed(retcode, log_file):
class ICV (line 62) | class ICV(VirtuosoChecker):
method __init__ (line 84) | def __init__(self, tmp_dir, lvs_run_dir, lvs_runset, rcx_run_dir, rcx_...
method get_rcx_netlists (line 111) | def get_rcx_netlists(self, lib_name, cell_name):
method setup_lvs_flow (line 133) | def setup_lvs_flow(self, lib_name, cell_name, sch_view='schematic', la...
method setup_rcx_flow (line 182) | def setup_rcx_flow(self, lib_name, cell_name, sch_view='schematic', la...
method _get_lay_sch_files (line 284) | def _get_lay_sch_files(cls, run_dir):
method modify_starrc_cmd (line 289) | def modify_starrc_cmd(self, run_dir, lib_name, cell_name, starrc_param...
FILE: bag/verification/pvs.py
function _all_pass (line 20) | def _all_pass(retcode, log_file):
function lvs_passed (line 25) | def lvs_passed(retcode, log_file):
function rcx_passed (line 54) | def rcx_passed(retcode, log_file):
class PVS (line 84) | class PVS(VirtuosoChecker):
method __init__ (line 104) | def __init__(self, tmp_dir, lvs_run_dir, lvs_runset, lvs_rule_file, rc...
method get_rcx_netlists (line 121) | def get_rcx_netlists(self, lib_name, cell_name):
method setup_lvs_flow (line 126) | def setup_lvs_flow(self, lib_name, cell_name, sch_view='schematic', la...
method setup_rcx_flow (line 185) | def setup_rcx_flow(self, lib_name, cell_name, sch_view='schematic', la...
method modify_lvs_runset (line 215) | def modify_lvs_runset(self, run_dir, cell_name, lvs_params):
method modify_rcx_runset (line 260) | def modify_rcx_runset(self, run_dir, lib_name, cell_name, lay_view, rc...
FILE: bag/verification/virtuoso.py
class VirtuosoChecker (line 18) | class VirtuosoChecker(SubProcessChecker, ABC):
method __init__ (line 35) | def __init__(self, tmp_dir, max_workers, cancel_timeout, source_added_...
method setup_export_layout (line 40) | def setup_export_layout(self, lib_name, cell_name, out_file, view_name...
method setup_export_schematic (line 69) | def setup_export_schematic(self, lib_name, cell_name, out_file, view_n...
FILE: bag/virtuoso.py
function run_skill_server (line 16) | def run_skill_server(args):
function parse_command_line_arguments (line 90) | def parse_command_line_arguments():
FILE: run_scripts/clean_cds_lib.py
function arg_parse (line 17) | def arg_parse() -> Namespace:
function run_main (line 28) | def run_main(args: Namespace):
FILE: run_scripts/gen_cell.py
function parse_args (line 14) | def parse_args() -> Namespace:
function run_main (line 44) | def run_main(prj: BagProject, args: Namespace):
FILE: run_scripts/generate_verilog.py
function run_main (line 8) | def run_main():
FILE: run_scripts/meas_cell.py
function parse_args (line 15) | def parse_args() -> Namespace:
function run_main (line 40) | def run_main(prj: BagProject, args: Namespace):
FILE: run_scripts/setup_submodules.py
function write_to_file (line 26) | def write_to_file(fname, lines):
function setup_python_path (line 32) | def setup_python_path(module_list):
function get_sch_libraries (line 48) | def get_sch_libraries(mod_name, mod_info):
function setup_libs_def (line 56) | def setup_libs_def(module_list):
function setup_cds_lib (line 67) | def setup_cds_lib(module_list):
function run_command (line 77) | def run_command(cmd):
function add_git_submodule (line 107) | def add_git_submodule(module_name, url):
function add_git_file (line 115) | def add_git_file(fname):
function link_submodule (line 119) | def link_submodule(repo_path, module_name):
function setup_git_submodules (line 131) | def setup_git_submodules(module_list):
function setup_submodule_links (line 138) | def setup_submodule_links(module_list, repo_path):
function run_main (line 144) | def run_main():
FILE: run_scripts/sim_cell.py
function parse_args (line 15) | def parse_args() -> Namespace:
function run_main (line 40) | def run_main(prj: BagProject, args: Namespace):
FILE: tests/layout/routing/test_fill.py
function check_disjoint_union (line 8) | def check_disjoint_union(outer_list, inner_list, start, stop):
function check_symmetric (line 33) | def check_symmetric(intv_list, start, stop):
function check_props (line 40) | def check_props(fill_list, space_list, num_diff_sp1, num_diff_sp2, n, to...
function test_fill_symmetric_non_cyclic (line 86) | def test_fill_symmetric_non_cyclic():
function test_fill_symmetric_cyclic_edge_fill (line 125) | def test_fill_symmetric_cyclic_edge_fill():
function test_fill_symmetric_cyclic_edge_space (line 166) | def test_fill_symmetric_cyclic_edge_space():
Condensed preview — 162 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,518K chars).
[
{
"path": ".gitignore",
"chars": 57,
"preview": "*~\n*.pyc\n.idea\nbuild\ndist\nbag.egg-info\n__pycache__\n*.swp\n"
},
{
"path": ".gitmodules",
"chars": 90,
"preview": "[submodule \"cybag_oa\"]\n\tpath = cybag_oa\n url = https://github.com/ucb-art/cybag_oa.git\n"
},
{
"path": "LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "README.md",
"chars": 361,
"preview": "Berkeley Analog Generator (BAG) version 2.0 and later.\n\nBAG 2.0 is a complete rewrite of BAG 1.x (which is in pre-alpha "
},
{
"path": "bag/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/__init__.py",
"chars": 580,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This is the bag root package.\n\"\"\"\n\nimport signal\n\nfrom . import math\nfrom .math import float"
},
{
"path": "bag/concurrent/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/concurrent/__init__.py",
"chars": 105,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package define helper classes used to perform concurrent operations.\n\"\"\""
},
{
"path": "bag/concurrent/core.py",
"chars": 11053,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module define utility classes for performing concurrent operations.\n\"\"\"\n\nfrom typing im"
},
{
"path": "bag/core.py",
"chars": 56412,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This is the core bag module.\n\"\"\"\n\nfrom typing import TYPE_CHECKING, Dict, Any, Tuple, Option"
},
{
"path": "bag/data/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/data/__init__.py",
"chars": 319,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package defines methods and classes useful for data post-processing.\n\"\"\"\n\n# compatibili"
},
{
"path": "bag/data/core.py",
"chars": 11281,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines core data post-processing classes.\n\"\"\"\n\nimport numpy as np\nimport scipy."
},
{
"path": "bag/data/dc.py",
"chars": 8114,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines classes for computing DC operating point.\n\"\"\"\n\nfrom typing import Union,"
},
{
"path": "bag/data/digital.py",
"chars": 7802,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines functions useful for digital verification/postprocessing.\n\"\"\"\n\nfrom typi"
},
{
"path": "bag/data/lti.py",
"chars": 30576,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines functions and classes useful for characterizing linear time-invariant ci"
},
{
"path": "bag/data/ltv.py",
"chars": 17833,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines functions and classes for linear time-varying circuits data post-process"
},
{
"path": "bag/data/mos.py",
"chars": 2940,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines classes for computing DC operating point.\n\"\"\"\n\nfrom typing import Dict\n\n"
},
{
"path": "bag/data/plot.py",
"chars": 21053,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module contains utilities to improve waveform plotting in python.\n\"\"\"\n\nimport numpy as "
},
{
"path": "bag/design/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/design/__init__.py",
"chars": 292,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package defines design template classes.\n\"\"\"\n\nfrom .module import Module, ModuleDB, Sch"
},
{
"path": "bag/design/module.py",
"chars": 38109,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines base design module class and primitive design classes.\n\"\"\"\n\nimport os\nim"
},
{
"path": "bag/interface/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/interface/__init__.py",
"chars": 250,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This packages defines classes to interface with CAD database and circuit simulators.\n\"\"\"\n\nfr"
},
{
"path": "bag/interface/base.py",
"chars": 663,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines the base of all interface classes.\n\"\"\"\n\nfrom typing import Dict, Any\n\nfr"
},
{
"path": "bag/interface/database.py",
"chars": 21388,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines DbAccess, the base class for CAD database manipulation.\n\"\"\"\n\nfrom typing"
},
{
"path": "bag/interface/ocean.py",
"chars": 6686,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module implements bag's interaction with an ocean simulator.\n\"\"\"\n\nfrom typing import TY"
},
{
"path": "bag/interface/server.py",
"chars": 9212,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This class defines SkillOceanServer, a server that handles skill/ocean requests.\n\nThe SkillO"
},
{
"path": "bag/interface/simulator.py",
"chars": 7833,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module handles high level simulation routines.\n\nThis module defines SimAccess, which pr"
},
{
"path": "bag/interface/skill.py",
"chars": 22736,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module implements all CAD database manipulations using skill commands.\n\"\"\"\n\nfrom typing"
},
{
"path": "bag/interface/templates/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/interface/templates/Module.pyi",
"chars": 1557,
"preview": "# -*- coding: utf-8 -*-\n\nfrom typing import Dict\n\nimport os\nimport pkg_resources\n\nfrom bag.design.module import Module\n\n"
},
{
"path": "bag/interface/templates/PrimModule.pyi",
"chars": 650,
"preview": "# -*- coding: utf-8 -*-\n\nimport os\nimport pkg_resources\n\nfrom bag.design.module import {{ module_name }}\n\n\n# noinspectio"
},
{
"path": "bag/interface/templates/calibreview_setup.txt",
"chars": 575,
"preview": "calibre_view_netlist_file : {{ netlist_file }}\noutput_library : {{ lib_name }}\nschematic_library : {{ lib_name }}\ncell_n"
},
{
"path": "bag/interface/templates/load_results.ocn",
"chars": 6839,
"preview": "lib = \"{{ lib }}\"\ncell = \"{{ cell }}\"\nview = \"{{ view }}\"\ninit_file = \"{{ init_file }}\"\nsave_dir = \"{{ save_dir }}\"\nprec"
},
{
"path": "bag/interface/templates/run_simulation.ocn",
"chars": 7176,
"preview": "lib = \"{{ lib }}\"\ncell = \"{{ cell }}\"\nview = \"{{ view }}\"\nstate = \"{{ state }}\"\ninit_file = \"{{ init_file }}\"\nsave_dir ="
},
{
"path": "bag/interface/zmqwrapper.py",
"chars": 9367,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines various wrapper around ZMQ sockets.\"\"\"\n\nfrom datetime import datetime\nim"
},
{
"path": "bag/io/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/io/__init__.py",
"chars": 972,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package provides all IO related functionalities for BAG.\n\nMost importantly, this module"
},
{
"path": "bag/io/common.py",
"chars": 2269,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module contains some commonly used IO functions.\n\nIn particular, this module keeps trac"
},
{
"path": "bag/io/file.py",
"chars": 5207,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module handles file related IO.\n\"\"\"\nfrom typing import Dict, Any\n\nimport os\nimport temp"
},
{
"path": "bag/io/gui.py",
"chars": 7366,
"preview": "# -*- coding: utf-8 -*-\n\nimport os\nimport sys\nimport subprocess\nimport json\nimport select\n\nimport PyQt5.QtWidgets as QtW"
},
{
"path": "bag/io/process.py",
"chars": 12961,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module provides functions to help you run external processes.\n\"\"\"\n\nimport os\nimport sys"
},
{
"path": "bag/io/sim_data.py",
"chars": 8592,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module handles simulation data related IO.\n\nNote : when reading data files, we use Nump"
},
{
"path": "bag/io/template.py",
"chars": 616,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines methods to create files from templates.\n\"\"\"\n\nfrom jinja2 import Environm"
},
{
"path": "bag/layout/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/layout/__init__.py",
"chars": 313,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package contains code for templated based layout.\n\"\"\"\n\nfrom .core import BagLayout, Tec"
},
{
"path": "bag/layout/core.py",
"chars": 64120,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines the base template class.\n\"\"\"\n\nfrom typing import Dict, List, Iterator, T"
},
{
"path": "bag/layout/digital.py",
"chars": 19858,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines layout template classes for digital standard cells.\n\"\"\"\n\nfrom typing imp"
},
{
"path": "bag/layout/objects.py",
"chars": 81527,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines various layout objects one can add and manipulate in a template.\n\"\"\"\nfro"
},
{
"path": "bag/layout/routing/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/layout/routing/__init__.py",
"chars": 187,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package provide routing classes.\n\"\"\"\n\nfrom .base import TrackID, WireArray, Port, Track"
},
{
"path": "bag/layout/routing/base.py",
"chars": 33583,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module provides basic routing classes.\n\"\"\"\n\nfrom typing import Tuple, Union, Generator,"
},
{
"path": "bag/layout/routing/fill.py",
"chars": 38386,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines classes that provides automatic fill utility on a grid.\n\"\"\"\n\nfrom typing"
},
{
"path": "bag/layout/routing/grid.py",
"chars": 69959,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines the RoutingGrid class.\n\"\"\"\n\nfrom typing import TYPE_CHECKING, Sequence, "
},
{
"path": "bag/layout/tech.py",
"chars": 11020,
"preview": "# -*- coding: utf-8 -*-\n\nfrom typing import List, Tuple, Union, Optional, Callable, TYPE_CHECKING\n\nimport abc\n\nfrom .cor"
},
{
"path": "bag/layout/template.py",
"chars": 183914,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines layout template classes.\n\"\"\"\n\nfrom typing import TYPE_CHECKING, Union, D"
},
{
"path": "bag/layout/util.py",
"chars": 31740,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module contains utility classes used for layout\n\"\"\"\n\nfrom typing import Iterator, Union"
},
{
"path": "bag/math/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/math/__init__.py",
"chars": 2385,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package defines design template classes.\n\"\"\"\n\nfrom typing import Iterable\n\nimport numpy"
},
{
"path": "bag/math/dfun.py",
"chars": 20893,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines the differentiable function class.\"\"\"\n\nfrom typing import Union, List, O"
},
{
"path": "bag/math/interpolate.py",
"chars": 19665,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines various interpolation classes.\n\"\"\"\n\nfrom typing import List, Tuple, Unio"
},
{
"path": "bag/mdao/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/mdao/__init__.py",
"chars": 87,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package contains various openmdao related modules.\n\"\"\""
},
{
"path": "bag/mdao/components.py",
"chars": 4736,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines various OpenMDAO component classes.\n\"\"\"\n\nimport numpy as np\nimport openm"
},
{
"path": "bag/mdao/core.py",
"chars": 9381,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines core BAG openmdao classes.\"\"\"\n\nimport numpy as np\nimport networkx as nx\n"
},
{
"path": "bag/simulation/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/simulation/__init__.py",
"chars": 126,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package defines various utility classes for running simulations and data post-processin"
},
{
"path": "bag/simulation/core.py",
"chars": 29600,
"preview": "# -*- coding: utf-8 -*-\n\nfrom typing import TYPE_CHECKING, Optional, Dict, Any, Tuple, List, Iterable, Sequence\n\nimport "
},
{
"path": "bag/simulation/core_v2.py",
"chars": 11844,
"preview": "from __future__ import annotations\nfrom typing import (\n TYPE_CHECKING, Optional, Dict, Any, Type, cast, List\n)\n\nimpo"
},
{
"path": "bag/tech/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/tech/__init__.py",
"chars": 128,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package contains various technology related utilities, such as transistor characterizat"
},
{
"path": "bag/tech/core.py",
"chars": 35160,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module contains commonly used technology related classes and functions.\n\"\"\"\n\nimport os\n"
},
{
"path": "bag/tech/mos.py",
"chars": 10656,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module contains transistor characterization and optimization related classes.\n\"\"\"\n\nimpo"
},
{
"path": "bag/util/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/util/__init__.py",
"chars": 79,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package defines various utilities classes.\n\"\"\""
},
{
"path": "bag/util/cache.py",
"chars": 25251,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines classes used to cache existing design masters\n\"\"\"\n\nfrom typing import Se"
},
{
"path": "bag/util/immutable.py",
"chars": 5950,
"preview": "\"\"\"This module defines various immutable and hashable data types.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom typing i"
},
{
"path": "bag/util/interval.py",
"chars": 19824,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module provides data structure that keeps track of intervals.\n\"\"\"\n\nfrom typing import L"
},
{
"path": "bag/util/parse.py",
"chars": 1238,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines parsing utility methods.\n\"\"\"\n\nimport ast\n\n\nclass ExprVarScanner(ast.Node"
},
{
"path": "bag/util/search.py",
"chars": 18344,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module provides search related utilities.\n\"\"\"\n\nfrom typing import Optional, Callable, A"
},
{
"path": "bag/verification/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/verification/__init__.py",
"chars": 793,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This package contains LVS/RCX related verification methods.\n\"\"\"\n\nfrom typing import Any\n\nimp"
},
{
"path": "bag/verification/base.py",
"chars": 13412,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module defines Checker, an abstract base class that handles LVS/RCX.\"\"\"\n\nfrom typing im"
},
{
"path": "bag/verification/calibre.py",
"chars": 23792,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module implements LVS/RCX using Calibre and stream out from Virtuoso.\n\"\"\"\n\nfrom typing "
},
{
"path": "bag/verification/icv.py",
"chars": 12655,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module implements LVS/RCX using ICV and stream out from Virtuoso.\n\"\"\"\n\nfrom typing impo"
},
{
"path": "bag/verification/pvs.py",
"chars": 11239,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module implements LVS/RCX using PVS/QRC and stream out from Virtuoso.\n\"\"\"\n\nfrom typing "
},
{
"path": "bag/verification/templates/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "bag/verification/templates/layout_export_config.txt",
"chars": 1641,
"preview": "case \"preserve\"\ncellListFile \"\"\ncellMap \""
},
{
"path": "bag/verification/templates/si_env.txt",
"chars": 659,
"preview": "simStopList = '(\"auCdl\")\nsimViewList = '(\"auCdl\" \"schematic\")\nglobalGndSig = \"\"\nglobalPowerSig = \"\"\nshrinkFACTOR = 0\nche"
},
{
"path": "bag/verification/virtuoso.py",
"chars": 3657,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module handles exporting schematic/layout from Virtuoso.\n\"\"\"\n\nfrom typing import TYPE_C"
},
{
"path": "bag/virtuoso.py",
"chars": 3891,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"This module provides functions needed to get Virtuoso to work with BAG.\n\"\"\"\n\nimport os\nimpor"
},
{
"path": "docs/.gitignore",
"chars": 6,
"preview": "build\n"
},
{
"path": "docs/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/Makefile",
"chars": 8061,
"preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHINXBUILD "
},
{
"path": "docs/README",
"chars": 219,
"preview": "To build/update documentation:\n\n1. make sure BAG Python's bin folder is in your path.\n\n2. run: \n\n ./refresh_api.sh\n "
},
{
"path": "docs/refresh_api.sh",
"chars": 74,
"preview": "#!/usr/bin/env tcsh\n\nsphinx-apidoc --force --output-dir=source/api ../bag\n"
},
{
"path": "docs/source/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/api/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/api/bag.data.rst",
"chars": 1085,
"preview": "bag.data package\n================\n\nSubmodules\n----------\n\nbag.data.core module\n--------------------\n\n.. automodule:: bag"
},
{
"path": "docs/source/api/bag.design.rst",
"chars": 472,
"preview": "bag.design package\n==================\n\nSubmodules\n----------\n\nbag.design.database module\n--------------------------\n\n.. "
},
{
"path": "docs/source/api/bag.interface.rst",
"chars": 1122,
"preview": "bag.interface package\n=====================\n\nSubmodules\n----------\n\nbag.interface.database module\n----------------------"
},
{
"path": "docs/source/api/bag.io.rst",
"chars": 817,
"preview": "bag.io package\n==============\n\nSubmodules\n----------\n\nbag.io.common module\n--------------------\n\n.. automodule:: bag.io."
},
{
"path": "docs/source/api/bag.layout.routing.rst",
"chars": 687,
"preview": "bag.layout.routing package\n==========================\n\nSubmodules\n----------\n\nbag.layout.routing.base module\n-----------"
},
{
"path": "docs/source/api/bag.layout.rst",
"chars": 1113,
"preview": "bag.layout package\n==================\n\nSubpackages\n-----------\n\n.. toctree::\n\n bag.layout.routing\n\nSubmodules\n-------"
},
{
"path": "docs/source/api/bag.math.rst",
"chars": 457,
"preview": "bag.math package\n================\n\nSubmodules\n----------\n\nbag.math.dfun module\n--------------------\n\n.. automodule:: bag"
},
{
"path": "docs/source/api/bag.mdao.rst",
"chars": 454,
"preview": "bag.mdao package\n================\n\nSubmodules\n----------\n\nbag.mdao.components module\n--------------------------\n\n.. auto"
},
{
"path": "docs/source/api/bag.rst",
"chars": 588,
"preview": "bag package\n===========\n\nSubpackages\n-----------\n\n.. toctree::\n\n bag.data\n bag.design\n bag.interface\n bag.io"
},
{
"path": "docs/source/api/bag.tech.rst",
"chars": 433,
"preview": "bag.tech package\n================\n\nSubmodules\n----------\n\nbag.tech.core module\n--------------------\n\n.. automodule:: bag"
},
{
"path": "docs/source/api/bag.util.rst",
"chars": 734,
"preview": "bag.util package\n================\n\nSubmodules\n----------\n\nbag.util.interval module\n------------------------\n\n.. automodu"
},
{
"path": "docs/source/api/bag.verification.rst",
"chars": 857,
"preview": "bag.verification package\n========================\n\nSubmodules\n----------\n\nbag.verification.base module\n-----------------"
},
{
"path": "docs/source/api/modules.rst",
"chars": 46,
"preview": "bag\n===\n\n.. toctree::\n :maxdepth: 4\n\n bag\n"
},
{
"path": "docs/source/conf.py",
"chars": 10043,
"preview": "# -*- coding: utf-8 -*-\n#\n# BAG documentation build configuration file, created by\n# sphinx-quickstart on Fri May 27 15:"
},
{
"path": "docs/source/developer/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/developer/developer.rst",
"chars": 53,
"preview": "Developer Guide\n===============\n\nNothing here yet...\n"
},
{
"path": "docs/source/index.rst",
"chars": 508,
"preview": ".. BAG documentation master file, created by\n sphinx-quickstart on Fri May 27 15:45:44 2016.\n You can adapt this fil"
},
{
"path": "docs/source/overview/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/overview/design.rst",
"chars": 5222,
"preview": "Design Module\n=============\n\nA design module is a Python class that generates new schematics. It computes all parameter"
},
{
"path": "docs/source/overview/overview.rst",
"chars": 2066,
"preview": "Overview\n========\n\n.. figure:: ./figures/bag_flow.png\n :align: center\n :figclass: align-center\n\n BAG design flo"
},
{
"path": "docs/source/overview/schematic.rst",
"chars": 2195,
"preview": "Schematic Generator\n===================\n\nA schematic generator is a schematic in your CAD program that tells BAG all the"
},
{
"path": "docs/source/overview/testbench.rst",
"chars": 2464,
"preview": "Testbench Generator\n===================\n\nA testbench generator is just a normal testbench with schematic and adexl view."
},
{
"path": "docs/source/setup/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/setup/bag_config/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/setup/bag_config/bag_config.rst",
"chars": 329,
"preview": "BAG Configuration File\n======================\n\nBAG configuration file is written in YAML format. This document describe"
},
{
"path": "docs/source/setup/bag_config/database/database.rst",
"chars": 5613,
"preview": "database\n========\n\nThis entry defines all settings related to Virtuoso.\n\n\ndata.class\n----------\n\nThe Python class that h"
},
{
"path": "docs/source/setup/bag_config/misc.rst",
"chars": 988,
"preview": "class\n=====\n\nThe subclass of :ref:\n\n\n.. _bag_lib_defs:\n\nlib_defs\n========\n\nLocation of the BAG design module libraries d"
},
{
"path": "docs/source/setup/bag_config/simulation/simulation.rst",
"chars": 1651,
"preview": "simulation\n==========\n\nThis entry defines all settings related to Ocean.\n\nsimulation.class\n----------------\n\nThe Python "
},
{
"path": "docs/source/setup/bag_config/socket/socket.rst",
"chars": 1079,
"preview": "socket\n======\n\nThis entry defines socket settings for BAG to communicate with Virtuoso.\n\nsocket.host\n-----------\n\nThe ho"
},
{
"path": "docs/source/setup/config_summary.rst",
"chars": 1639,
"preview": "Configuration Files Summary\n===========================\n\nAlthough BAG has many configuration settings, most of them do n"
},
{
"path": "docs/source/setup/install_python.rst",
"chars": 2648,
"preview": "Installing Python for BAG\n==========================\n\nThis section describes how to install Python for running BAG.\n\nIns"
},
{
"path": "docs/source/setup/new_pdk.rst",
"chars": 1309,
"preview": "Setting up New PDK\n==================\n\nThis section describes how to get BAG 2.0 to work with a new PDK.\n\n#. Create a ne"
},
{
"path": "docs/source/setup/pyoptsparse.rst",
"chars": 58,
"preview": "Building Pyoptsparse\n====================\n\nTo be written.\n"
},
{
"path": "docs/source/setup/setup.rst",
"chars": 491,
"preview": "BAG Setup Procedure\n===================\n\nThis document describes how to install Python for BAG and the various configura"
},
{
"path": "docs/source/setup/tech_config/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/setup/tech_config/layout/layout.rst",
"chars": 213,
"preview": "layout\n======\n\nThis entry defines all layout specific settings.\n\n\nlayout.em_temp\n--------------\n\nThe temperature used to"
},
{
"path": "docs/source/setup/tech_config/misc.rst",
"chars": 253,
"preview": ".. _tech_config_path:\n\nclass\n=====\n\nThe subclass of :class:`bag.layout.core.TechInfo` for this process technology.\nIf th"
},
{
"path": "docs/source/setup/tech_config/mos/mos.rst",
"chars": 386,
"preview": "mos\n===\n\nThis entry defines all MOS transistor settings.\n\n\nmos.width_resolution\n--------------------\n\nThe transistor wid"
},
{
"path": "docs/source/setup/tech_config/tech_config.rst",
"chars": 321,
"preview": "Technology Configuration File\n=============================\n\nTechnology configuration file is written in YAML format. T"
},
{
"path": "docs/source/tutorial/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/tutorial/figures/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "docs/source/tutorial/tutorial.rst",
"chars": 594,
"preview": "Tutorial\n========\n\nThis section contains several simple tutorials for you to get an idea of the BAG workflow.\n\nIn these "
},
{
"path": "run_scripts/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "run_scripts/clean_cds_lib.py",
"chars": 2241,
"preview": "\"\"\"\nThis script removes the '#Removed by ddDeleteObj' items in cds.lib.\nIt is also capable of taking a list of patterns "
},
{
"path": "run_scripts/compile_verilog.il",
"chars": 653,
"preview": "\nprocedure( compile_netlist_views(fname \"t\")\n let( (p line info_list lib cell view obj cv)\n unless( p = infile"
},
{
"path": "run_scripts/gen_cell.py",
"chars": 2839,
"preview": "import argparse\nfrom argparse import Namespace\nfrom pathlib import Path\n\nfrom bag.io.file import Pickle, Yaml\nfrom bag.c"
},
{
"path": "run_scripts/generate_verilog.py",
"chars": 1004,
"preview": "\nimport os\n\nimport yaml\nfrom jinja2 import Environment, FileSystemLoader\n\n\ndef run_main():\n verilog_dir = 'verilog_mo"
},
{
"path": "run_scripts/meas_cell.py",
"chars": 2668,
"preview": "import argparse\nfrom argparse import Namespace\nfrom pathlib import Path\nimport pdb\n\nfrom bag.io.file import Pickle, Yaml"
},
{
"path": "run_scripts/run_bag.sh",
"chars": 66,
"preview": "#!/usr/bin/env bash\n\nsource .bashrc_pypath\n\nexec ${BAG_PYTHON} $@\n"
},
{
"path": "run_scripts/setup_submodules.py",
"chars": 5329,
"preview": "#!/usr/bin/env bash\n\n# crazy black magic from:\n# https://unix.stackexchange.com/questions/20880/how-can-i-use-environmen"
},
{
"path": "run_scripts/sim_cell.py",
"chars": 2675,
"preview": "import argparse\nfrom argparse import Namespace\nfrom pathlib import Path\nimport pdb\n\nfrom bag.io.file import Pickle, Yaml"
},
{
"path": "run_scripts/start_bag.il",
"chars": 81422,
"preview": "/* Note:\n\nDue to licensing reasons, this skill script is missing the function \nCCSinvokeCdfCallbacks() from Cadence sol"
},
{
"path": "run_scripts/start_bag.sh",
"chars": 137,
"preview": "#!/usr/bin/env bash\n\nexport PYTHONPATH=\"\"\n\n# disable QT session manager warnings\nunset SESSION_MANAGER\n\nexec ${BAG_PYTHO"
},
{
"path": "run_scripts/start_bag_ICADV12d3.il",
"chars": 81699,
"preview": "/* Note:\n\nDue to licensing reasons, this skill script is missing the function \nCCSinvokeCdfCallbacks() from Cadence sol"
},
{
"path": "run_scripts/virt_server.sh",
"chars": 305,
"preview": "#!/usr/bin/env bash\n\nexport PYTHONPATH=\"${BAG_FRAMEWORK}\"\n\nexport cmd=\"-m bag.virtuoso run_skill_server\"\nexport min_port"
},
{
"path": "setup.py",
"chars": 1139,
"preview": "# -*- coding: utf-8 -*-\n\nfrom setuptools import setup, find_packages\n\n\nsetup(\n name='bag',\n version='2.0',\n des"
},
{
"path": "tests/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/layout/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "tests/layout/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/layout/routing/LICENSE",
"chars": 1539,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, Regents of the University of California\nAll rights reserved.\n\nRedistribution a"
},
{
"path": "tests/layout/routing/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/layout/routing/test_fill.py",
"chars": 11014,
"preview": "from itertools import product\n\nimport pytest\n\nfrom bag.layout.routing.fill import fill_symmetric_helper\n\n\ndef check_disj"
}
]
About this extraction
This page contains the full source code of the ucb-art/BAG_framework GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 162 files (1.4 MB), approximately 339.6k tokens, and a symbol index with 1515 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.