# SPDX-License-Identifier: BSD-3-Clause AND Apache-2.0
# Copyright 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.
# Copyright 2019 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module defines the design database class.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, Mapping, Optional, Any, Sequence, Type, Tuple
import importlib
from pathlib import Path
from jinja2 import Template
from pybag.enum import DesignOutput, LogLevel
from ..util.cache import MasterDB, Param
from ..io.template import new_template_env_fs
from .module import Module
if TYPE_CHECKING:
from ..core import BagProject
from ..layout.tech import TechInfo
[docs]ModuleType = TypeVar('ModuleType', bound=Module)
[docs]class ModuleDB(MasterDB):
"""A database of all modules.
This class is a subclass of MasterDB that defines some extra properties/function
aliases to make creating schematics easier.
Parameters
----------
tech_info : TechInfo
the TechInfo instance.
lib_name : str
the cadence library to put all generated templates in.
log_file: str
the log file path.
prj : Optional[BagProject]
the BagProject instance.
name_prefix : str
generated schematic name prefix.
name_suffix : str
generated schematic name suffix.
log_level : LogLevel
the logging level.
"""
def __init__(self, tech_info: TechInfo, lib_name: str, log_file: str, prj: Optional[BagProject] = None,
name_prefix: str = '', name_suffix: str = '', log_level: LogLevel = LogLevel.DEBUG) -> None:
MasterDB.__init__(self, lib_name, log_file, prj=prj, name_prefix=name_prefix, name_suffix=name_suffix,
log_level=log_level)
self._tech_info = tech_info
self._temp_env = new_template_env_fs()
@classmethod
[docs] def get_schematic_class(cls, lib_name: str, cell_name: str) -> Type[Module]:
"""Get the Python class object for the given schematic.
Parameters
----------
lib_name : str
schematic library name.
cell_name : str
schematic cell name.
Returns
-------
sch_cls : Type[Module]
the schematic class.
"""
module_name = lib_name + '.schematic.' + cell_name
try:
sch_module = importlib.import_module(module_name)
except ImportError:
raise ImportError('Cannot find Python module {} for schematic generator {}__{}. '
'Is it on your PYTHONPATH?'.format(module_name, lib_name, cell_name))
cls_name = lib_name + '__' + cell_name
if not hasattr(sch_module, cls_name):
raise ImportError('Cannot find schematic generator class {} '
'in module {}'.format(cls_name, module_name))
return getattr(sch_module, cls_name)
@property
[docs] def tech_info(self) -> TechInfo:
"""the :class:`~bag.layout.core.TechInfo` instance."""
return self._tech_info
[docs] def get_model_netlist_template(self, fpath: Path) -> Template:
return self._temp_env.get_template(str(fpath))
[docs] def instantiate_schematic(self, design: Module, top_cell_name: str = '',
output: DesignOutput = DesignOutput.SCHEMATIC,
**kwargs: Any) -> None:
"""Alias for instantiate_master(), with default output type of SCHEMATIC.
"""
self.instantiate_master(output, design, top_cell_name, **kwargs)
[docs] def batch_schematic(self, info_list: Sequence[Tuple[Module, str]],
output: DesignOutput = DesignOutput.SCHEMATIC,
**kwargs: Any) -> None:
"""Alias for batch_output(), with default output type of SCHEMATIC.
"""
self.batch_output(output, info_list, **kwargs)
[docs] def new_model(self, master: Module, model_params: Param, **kwargs: Any) -> Module:
"""Create a new schematic master instance with behavioral model information
Parameters
----------
master : Module
the schematic master instance.
model_params : Param
model parameters.
**kwargs : Any
optional arguments
Returns
-------
master : Module
the new master instance.
"""
debug = kwargs.get('debug', False)
new_params = master.params.copy(append=dict(model_params=model_params))
key = master.compute_unique_key(new_params)
test = self.find_master(key)
if test is not None:
if debug:
print('model master cached')
return test
if debug:
print('generating model master')
new_master = master.get_copy_with(new_params)
new_master.design_model(key)
self.register_master(key, new_master)
return new_master
[docs] def instantiate_model(self, design: Module, model_params: Param, top_cell_name: str = '',
**kwargs: Any) -> None:
self.batch_model([(design, top_cell_name, model_params)], **kwargs)
[docs] def batch_model(self, info_list: Sequence[Tuple[Module, str, Mapping[str, Any]]],
output: DesignOutput = DesignOutput.SYSVERILOG,
**kwargs: Any) -> Sequence[Tuple[Module, str]]:
new_info_list = [(self.new_model(m, Param(m_params)), name)
for m, name, m_params in info_list]
self.batch_output(output, new_info_list, **kwargs)
return new_info_list