Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Resladder annotation #16

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added OA/bag3_analog/drv_shunt_peak/data.dm
Binary file not shown.
Binary file added OA/bag3_analog/drv_shunt_peak/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/bag3_analog/drv_shunt_peak/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/bag3_analog/drv_shunt_peak/schematic/sch.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/bag3_analog/drv_shunt_peak/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/bag3_analog/drv_shunt_peak/symbol/symbol.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/bag3_analog/gm_stage/data.dm
Binary file not shown.
Binary file added OA/bag3_analog/gm_stage/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/bag3_analog/gm_stage/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/bag3_analog/gm_stage/schematic/sch.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/bag3_analog/gm_stage/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/bag3_analog/gm_stage/symbol/symbol.oa
Binary file not shown.
Binary file added OA/bag3_analog/gm_stage/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OA/bag3_analog/res_diff/data.dm
Binary file not shown.
Binary file added OA/bag3_analog/res_diff/schematic/data.dm
Binary file not shown.
2 changes: 2 additions & 0 deletions OA/bag3_analog/res_diff/schematic/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
sch.oa
Binary file added OA/bag3_analog/res_diff/schematic/sch.oa
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions OA/bag3_analog/res_diff/symbol/master.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Master.tag File, Rev:1.0
symbol.oa
Binary file added OA/bag3_analog/res_diff/symbol/symbol.oa
Binary file not shown.
Binary file added OA/bag3_analog/res_diff/symbol/thumbnail_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 134 additions & 0 deletions src/bag3_analog/design/drv_shunt_peak.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from typing import Mapping, Any, Dict, Union, List, Type
import numpy as np
from copy import deepcopy

from bag.util.immutable import Param
from bag.io.sim_data import load_sim_file, save_sim_results
from bag.concurrent.util import GatherHelper
from bag.simulation.cache import DesignInstance
from bag.simulation.measure import MeasurementManager

from bag3_testbenches.design.optimize.base import OptDesigner, OptimizationError

from ..measurement.drv_shunt_peak import DrvShuntPeakTranMeas


class DrvShuntPeakDesigner(OptDesigner):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

@classmethod
def get_meas_var_list(cls):
return ['width', 'height', 'i_avg', 'fom']

async def async_design(self, **kwargs: Any) -> Mapping[str, Any]:
await self.characterize_designs()
fn_table, swp_order = self.make_models()
opt_specs = self._dsn_specs['opt_specs']
spec_constraints = {k: tuple(v) for k, v in opt_specs['spec_constraints'].items()}

self.log(f'Performing eye_area optimization...')
try:
opt_x, opt_y, spec_vals = self.optimize('height', fn_table, swp_order, maximize=True, reduce_fn=np.max,
spec_constraints=spec_constraints)
print('--------------------------')
print(f'opt_x = {opt_x}')
print(f'opt_y = {opt_y}')
print(f'spec_vals = {spec_vals}')
print('--------------------------')
except OptimizationError as e:
self.warn(f'Error occurred while running: {e}')

return fn_table

async def verify_design(self, dut: DesignInstance, dsn_params: Dict[str, Any],
sim_swp_params: Dict[str, Any]) -> Dict[str, Any]:
dsn_name = self.get_design_name(dsn_params)

gatherer = GatherHelper()
gatherer.append(self.run_sim('tran', DrvShuntPeakTranMeas, dut, dsn_name, dsn_params, sim_swp_params))
res_list = await gatherer.gather_err()
res = self.aggregate_results(res_list)
return res

async def run_sim(self, meas_name: str, mm_cls: Type[MeasurementManager], dut: DesignInstance, dsn_name: str,
dsn_params: Dict[str, Any], sim_swp_params: Dict[str, Any]) -> Dict[str, Any]:
sim_dir = self.get_meas_dir(dsn_name)
out_dir = self.get_data_dir(dsn_name)

res_fpath = out_dir / f'{meas_name}.hdf5'
run_meas = self.check_run_meas(res_fpath)

if not run_meas:
prev_res = load_sim_file(str(res_fpath))
self.reorder_data_swp(prev_res, self.sim_swp_order)
return prev_res

# setup measurement specs
mm_specs = deepcopy(self._dsn_specs['meas_params'])
mm_specs['sim_envs'] = sim_swp_params['corner']
mm_specs['v_incm_swp'] = sim_swp_params['v_incm']
mm_specs['v_tail_g_swp'] = sim_swp_params['v_tail_g']
mm_specs['ind_specs']['sp_file_specs']['shunt']['file_name'] = dsn_params['sp_file']

mm = self.make_mm(mm_cls, mm_specs)

data = (await self._sim_db.async_simulate_mm_obj(meas_name, sim_dir / meas_name, dut, mm)).data

res = self.postproc_tran(data, dsn_params)
res['sweep_params'] = {k: self.sim_swp_order for k in res}
res.update(sim_swp_params)

save_sim_results(res, str(res_fpath))
return res

@staticmethod
def postproc_tran(data: Mapping[str, Any], dsn_params: Dict[str, Any]) -> Dict[str, Any]:
radius: int = int(dsn_params['radius'])
height: float = data['height']
i_avg: float = data['i_avg']
return dict(
width=data['width'],
height=height,
i_avg=i_avg,
fom=height / (np.sqrt(i_avg) * np.sqrt(radius)),
)

@staticmethod
def aggregate_results(res_list: List[Dict[str, Any]]) -> Dict[str, Any]:
ans = {}
for res in res_list:
for k, v in res.items():
if k == 'sweep_params':
if k not in ans:
ans[k] = {}
ans[k].update(v)
elif k not in ans:
ans[k] = v
elif isinstance(v, np.ndarray):
assert np.all(ans[k] == v)
else:
assert ans[k] == v
return ans

@classmethod
def get_dut_gen_specs(cls, is_lay: bool, base_gen_specs: Param,
gen_params: Mapping[str, Any]) -> Union[Param, Dict[str, Any]]:
base_gen_specs = base_gen_specs.to_yaml()
base_gen_specs['lay_mode'] = 'EXT'
base_gen_specs['gm_params']['seg_dict']['tail'] = int(gen_params['seg_tail'])
base_gen_specs['gm_params']['seg_dict']['gm'] = int(gen_params['seg_gm'])
base_gen_specs['ind_sh_params']['radius_x'] = int(gen_params['radius'])
base_gen_specs['ind_sh_params']['radius_y'] = int(gen_params['radius'])
return base_gen_specs

@classmethod
def get_em_dut_gen_specs(cls, base_gen_specs: Param,
gen_params: Mapping[str, Any]) -> Union[Param, Dict[str, Any]]:
base_gen_specs = base_gen_specs.to_yaml()
base_gen_specs['lay_mode'] = 'EM'
base_gen_specs['gm_params']['seg_dict']['tail'] = int(gen_params['seg_tail'])
base_gen_specs['gm_params']['seg_dict']['gm'] = int(gen_params['seg_gm'])
base_gen_specs['ind_sh_params']['radius_x'] = int(gen_params['radius'])
base_gen_specs['ind_sh_params']['radius_y'] = int(gen_params['radius'])
return base_gen_specs
196 changes: 196 additions & 0 deletions src/bag3_analog/layout/drv_shunt_peak.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
from typing import Mapping, Any, Optional, Type, Union

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB, TemplateBase
from bag.layout.routing.base import TrackManager, WDictType, SpDictType

from pybag.enum import RoundMode, MinLenMode, Orientation
from pybag.core import Transform, BBox

from xbase.layout.mos.top import GenericWrapper
from xbase.layout.array.top import ArrayBaseWrapper

from bag3_magnetics.layout.inductor.ind_diff_wrap import IndDiffWrap

from .gm_stage import GmStageGR, GmStage
from .res_diff import ResDiff

from ..schematic.drv_shunt_peak import bag3_analog__drv_shunt_peak, LayMode


class DrvShuntPeak(TemplateBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
TemplateBase.__init__(self, temp_db, params, **kwargs)
tr_widths: WDictType = self.params['tr_widths']
tr_spaces: SpDictType = self.params['tr_spaces']
self._tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)

@classmethod
def get_schematic_class(cls) -> Optional[Type[Module]]:
return bag3_analog__drv_shunt_peak

@classmethod
def get_params_info(cls) -> Mapping[str, str]:
return dict(
tr_widths='Track width dictionary for TrackManager',
tr_spaces='Track spaces dictionary for TrackManager',
gm_params='Parameters for gm cells',
res_params='Parameters for differential resistors',
ind_sh_params='Parameters for shunt differential inductor',
ind_v_sp='Vertical spacing between resistor and inductor',
lay_mode='Layout mode, TOP by default.',
)

@classmethod
def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(lay_mode=LayMode.TOP, ind_v_sp=0)

def draw_layout(self) -> None:
# make masters
gm_params: Mapping[str, Any] = self.params['gm_params']
gm_cls = GmStageGR if self.has_guard_ring else GmStage
gm_master = self.new_template(GenericWrapper, params=dict(cls_name=gm_cls.get_qualified_name(),
params=gm_params, export_hidden=True))
gm_bbox = gm_master.bound_box

res_params: Mapping[str, Any] = self.params['res_params']
res_master = self.new_template(ArrayBaseWrapper, params=dict(cls_name=ResDiff.get_qualified_name(),
params=res_params, export_hidden=True))
res_bbox = res_master.bound_box

ind_sh_params: Mapping[str, Any] = self.params['ind_sh_params']
ind_sh_master: IndDiffWrap = self.new_template(IndDiffWrap, params=ind_sh_params)
ind_sh_bbox = ind_sh_master.actual_bbox
ind_layer: int = ind_sh_params['lay_id']

lay_mode: Union[str, LayMode] = self.params['lay_mode']
if isinstance(lay_mode, str):
lay_mode = LayMode[lay_mode]
gen_gm = gen_res = lay_mode is LayMode.TOP or lay_mode is LayMode.EXT
gen_ind = lay_mode is LayMode.TOP or lay_mode is LayMode.EM

# --- Placement --- #
w_tot = max(gm_bbox.w, res_bbox.w, ind_sh_bbox.w)

x_gm = (w_tot - gm_bbox.w) // 2
y_gm = gm_bbox.h
gm = self.add_instance(gm_master, xform=Transform(dx=x_gm, dy=y_gm, mode=Orientation.MX), commit=gen_gm)

x_res = (w_tot + res_bbox.w) // 2
y_res = y_gm
res = self.add_instance(res_master, xform=Transform(dx=x_res, dy=y_res, mode=Orientation.MY), commit=gen_res)

ind_v_sp: int = self.params['ind_v_sp']
x_ind = (w_tot + ind_sh_bbox.w) // 2
y_ind = y_res + res_bbox.h + ind_v_sp
ind = self.add_instance(ind_sh_master, xform=Transform(dx=x_ind, dy=y_ind, mode=Orientation.MY), commit=gen_ind)

h_tot = ind.bound_box.yh
self.set_size_from_bound_box(ind_layer, BBox(0, 0, w_tot, h_tot), round_up=True)

# --- Routing --- #
# gm cell
if gen_gm:
for pin in ('v_inp', 'v_inm', 'v_tail_g', 'v_tail'):
self.reexport(gm.get_port(pin))

self.reexport(gm.get_port('VSS'), connect=True)
if gm.has_port('VDD'):
# TODO: routing supply
self.reexport(gm.get_port('VDD'), connect=True)

# res_diff
if gen_res:
for pin in ('VDD', 'VSS'):
if res.has_port(pin):
self.reexport(res.get_port(pin), connect=True)

# routing from gm cell to res_diff
i_outp = gm.get_pin('i_outp')
i_outm = gm.get_pin('i_outm')
gm_top_layer = i_outp.layer_id

p_in = res.get_pin('p_in')
p_out = res.get_pin('p_out')
m_in = res.get_pin('m_in')
m_out = res.get_pin('m_out')

if gm_top_layer < p_in.layer_id:
raise NotImplementedError
elif gm_top_layer > p_in.layer_id:
_tidx0 = self.grid.coord_to_track(gm_top_layer, p_in.bound_box.ym, RoundMode.NEAREST)
_tidx1 = self.grid.coord_to_track(gm_top_layer, p_out.bound_box.ym, RoundMode.NEAREST)
if self._tr_manager.get_next_track(gm_top_layer, _tidx0, 'sig_hs', 'sig_hs', 2) > _tidx1:
# compute new _tidx0 and _tidx1
_, _locs = self._tr_manager.place_wires(gm_top_layer, ['sig_hs', 'sig_hs', 'sig_hs'],
center_coord=(p_in.bound_box.ym + p_out.bound_box.ym) // 2)
_tidx0, _tidx1 = _locs[0], _locs[-1]
alternate_o = True
else:
alternate_o = False
_coord0 = self.grid.track_to_coord(gm_top_layer, _tidx0)
_coord1 = self.grid.track_to_coord(gm_top_layer, _tidx1)
p_0, p_1 = p_in.lower, p_in.upper
m_0, m_1 = m_in.lower, m_in.upper
p_in = self.connect_via_stack(self._tr_manager, p_in, gm_top_layer, 'sig_hs',
coord_list_p_override=[_coord0], alignment_o=1)
p_in = self.extend_wires(p_in, lower=p_0, upper=p_1)[0]
m_in = self.connect_via_stack(self._tr_manager, m_in, gm_top_layer, 'sig_hs',
coord_list_p_override=[_coord0], alignment_o=-1)
m_in = self.extend_wires(m_in, lower=m_0, upper=m_1)[0]
p_out = self.connect_via_stack(self._tr_manager, p_out, gm_top_layer, 'sig_hs',
coord_list_p_override=[_coord1], alternate_o=alternate_o, alignment_o=1)
p_out = self.extend_wires(p_out, lower=p_0, upper=p_1)[0]
m_out = self.connect_via_stack(self._tr_manager, m_out, gm_top_layer, 'sig_hs',
coord_list_p_override=[_coord1], alternate_o=alternate_o, alignment_o=-1)
m_out = self.extend_wires(m_out, lower=m_0, upper=m_1)[0]

# now i_outp and p_in are on the same layer
_conn_layer = gm_top_layer + 1
p_in = self.connect_via_stack(self._tr_manager, p_in, _conn_layer, 'sig_hs',
mlm_dict={_conn_layer: MinLenMode.LOWER})
m_in = self.connect_via_stack(self._tr_manager, m_in, _conn_layer, 'sig_hs',
mlm_dict={_conn_layer: MinLenMode.LOWER})
i_outp = self.connect_to_track_wires(i_outp, p_in)
i_outm = self.connect_to_track_wires(i_outm, m_in)
if gen_gm and gen_res:
self.add_pin('i_outp', i_outp)
self.add_pin('i_outm', i_outm)

# routing from res_diff to inductors
_tidx = self.grid.coord_to_track(_conn_layer + 1, p_out.bound_box.ym, RoundMode.GREATER)
_coord = self.grid.track_to_coord(_conn_layer + 1, _tidx)
p_out = self.connect_via_stack(self._tr_manager, p_out, _conn_layer + 1, 'sig_hs',
coord_list_p_override=[_coord], mlm_dict={_conn_layer: MinLenMode.UPPER})
m_out = self.connect_via_stack(self._tr_manager, m_out, _conn_layer + 1, 'sig_hs',
coord_list_p_override=[_coord], mlm_dict={_conn_layer: MinLenMode.UPPER})
ind_p: BBox = ind.get_pin('P1')
ind_m: BBox = ind.get_pin('P3')
ind_lp = self.grid.tech_info.get_lay_purp_list(ind_layer)[0]
if _conn_layer + 1 == ind_layer:
self.add_rect(ind_lp, BBox(ind_p.xl, p_out.bound_box.yl, ind_p.xh, ind_p.yh))
self.add_rect(ind_lp, BBox(ind_m.xl, m_out.bound_box.yl, ind_m.xh, ind_m.yh))
else:
raise NotImplementedError

# ind
if gen_res:
self.reexport(ind.get_port('P1'), net_name='ind_p')
self.reexport(ind.get_port('P3'), net_name='ind_m')
if gen_ind:
if lay_mode is LayMode.TOP:
for pin in ('P13_R', 'P2_R', 'P2'):
# TODO: routing supplies
self.reexport(ind.get_port(pin), net_name='VDD', connect=True)
else:
for pin in ('P13_R', 'P2_R', 'P2', 'P1', 'P3'):
self.reexport(ind.get_port(pin))

# get schematic parameters
self.sch_params = dict(
gm=gm_master.sch_params,
res=res_master.sch_params,
ind=ind_sh_master.sch_params,
lay_mode=lay_mode,
)
Loading