"""This module contains layout generators for the RDAC row and column decoders"""
from typing import Mapping, Any, Optional, Type, Union, Sequence
from pybag.enum import MinLenMode, RoundMode, PinMode
from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB
from bag.layout.routing.base import TrackID, WireArray
from bag.layout.enum import DrawTaps
from xbase.layout.enum import MOSWireType
from xbase.layout.mos.base import MOSBasePlaceInfo, MOSBase
from bag3_digital.layout.stdcells.gates import InvCore, PassGateCore
# from bag3_digital.layout.stdcells.and_complex import AndComplexRow, AndComplexCol
from bag3_digital.layout.stdcells.and_complex import AndComplexRow
from bag3_digital.layout.stdcells.and_complex import AndComplexColTall as AndComplexCol
from ..schematic.rdac_decoder_row_col import bag3_analog__rdac_decoder_row_col
[docs]class RDACDecoderRow(MOSBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
MOSBase.__init__(self, temp_db, params, **kwargs)
self._pg_tile0 = 0
@property
[docs] def pg_tile0(self) -> int:
# return the tile_idx of bottom-most passgate tile
return self._pg_tile0
@classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]:
return bag3_analog__rdac_decoder_row_col
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]:
return dict(
pinfo='The MOSBasePlaceInfo object.',
seg_dict='Dictionary of segments of sub cell components',
num_sel='Number of select inputs',
draw_taps='"BOTH" or "LEFT" or "RIGHT" or "NONE"',
)
@classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]:
return dict(draw_taps=DrawTaps.BOTH)
[docs] def draw_layout(self) -> None:
pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
self.draw_base(pinfo)
seg_dict: Mapping[str, Any] = self.params['seg_dict']
num_sel: int = self.params['num_sel']
num_in = 1 << num_sel
draw_taps: Union[DrawTaps, str] = self.params['draw_taps']
seg_tap = 4
if isinstance(draw_taps, str):
draw_taps = DrawTaps[draw_taps]
# make masters
pd0_tidx = self.get_track_index(1, MOSWireType.DS, 'sig', 0)
pg_tidx = self.get_track_index(1, MOSWireType.G, 'sig', 0)
nd1_tidx = self.get_track_index(0, MOSWireType.DS, 'sig', -1)
inv_params_e = dict(pinfo=pinfo, seg=seg_dict['inv'], vertical_out=False)
inv_params_o = dict(pinfo=pinfo, seg=seg_dict['inv'], vertical_out=False,
sig_locs={'pout': pd0_tidx, 'nout': nd1_tidx, 'nin': pg_tidx})
inv_master_e = self.new_template(InvCore, params=inv_params_e)
inv_master_o = self.new_template(InvCore, params=inv_params_o)
inv_ncols = inv_master_e.num_cols
pg_params = dict(pinfo=pinfo, seg=seg_dict['pg'], vertical_out=False)
pg_master = self.new_template(PassGateCore, params=pg_params)
pg_ncols = pg_master.num_cols
and_params = dict(pinfo=pinfo, seg_dict=seg_dict['and'], num_in=num_sel)
and_master: AndComplexRow = self.new_template(AndComplexRow, params=and_params)
and_ncols = and_master.num_cols
tap_ncols = self.get_tap_ncol(seg_tap)
tot_ncols = max(and_ncols + self.min_sep_col + pg_ncols,
num_sel * inv_ncols + (num_sel - 1) * self.min_sep_col) + self.min_sep_col
if draw_taps.has_left:
tot_ncols += tap_ncols + self.sub_sep_col
start_col = tap_ncols + self.sub_sep_col + self.min_sep_col // 2
else:
start_col = self.min_sep_col // 2
if draw_taps.has_right:
tot_ncols += tap_ncols + self.sub_sep_col
hm_layer = self.conn_layer + 1
vm_layer = hm_layer + 1
xm_layer = vm_layer + 1
ym_layer = xm_layer + 1
# --- Placement --- #
vdd_hm_list, vss_hm_list = [], []
# tile 1 and above: place left tap, and_complex, passgate, right tap
self._pg_tile0 = 1
w_sig_vm = self.tr_manager.get_width(vm_layer, 'sig')
w_sig_xm = self.tr_manager.get_width(xm_layer, 'sig')
w_sig_ym = self.tr_manager.get_width(ym_layer, 'sig')
sel_vm_locs, selb_vm_locs = [], []
sel_hm_list = [[] for _ in range(num_sel)]
selb_hm_list = [[] for _ in range(num_sel)]
pg_vm_locs, pg_ym_locs = [], []
pg_out_vm_list, pg_out_ym_list = [], []
and_in_list = and_master.nand_in_list
for idx in range(num_in):
vdd_tap_list, vss_tap_list = [], []
tile_idx = idx + 1
if draw_taps.has_left:
self.add_tap(0, vdd_tap_list, vss_tap_list, tile_idx=tile_idx, seg=seg_tap)
cur_col = start_col
if draw_taps.has_right:
self.add_tap(tot_ncols, vdd_tap_list, vss_tap_list, tile_idx=tile_idx, flip_lr=True, seg=seg_tap)
_and = self.add_tile(and_master, tile_idx, cur_col)
cur_col += and_ncols + self.min_sep_col
_pg = self.add_tile(pg_master, tile_idx, cur_col)
# supply
vdd_hm_list.append(self.connect_wires([_and.get_pin('VDD'), _pg.get_pin('VDD')])[0])
self.connect_to_track_wires(vdd_tap_list, vdd_hm_list[-1])
vss_hm_list.append(self.connect_wires([_and.get_pin('VSS'), _pg.get_pin('VSS')])[0])
self.connect_to_track_wires(vss_tap_list, vss_hm_list[-1])
# pg enable
self.connect_wires([_and.get_pin('out'), _pg.get_pin('en')])
self.connect_wires([_and.get_pin('outb'), _pg.get_pin('enb')])
# pg input and output
pg_d = [_pg.get_pin('nd'), _pg.get_pin('pd')]
if len(pg_vm_locs) == 0:
_, pg_vm_locs = self.tr_manager.place_wires(vm_layer, ['sig', 'sig'],
center_coord=pg_d[0].bound_box.xm)
_, pg_ym_locs = self.tr_manager.place_wires(ym_layer, ['sig', 'sig'],
center_coord=pg_d[0].bound_box.xm)
_ym = (pg_d[0].bound_box.ym + pg_d[1].bound_box.ym) // 2
_, pg_xm_locs = self.tr_manager.place_wires(xm_layer, ['sig', 'sig', 'sig'], center_coord=_ym)
pg_s_vm = self.connect_to_tracks(_pg.get_pin('s'), TrackID(vm_layer, pg_vm_locs[0], w_sig_vm),
min_len_mode=MinLenMode.MIDDLE)
pg_s_xm = self.connect_to_tracks(pg_s_vm, TrackID(xm_layer, pg_xm_locs[1], w_sig_xm),
min_len_mode=MinLenMode.MIDDLE)
pg_s_ym = self.connect_to_tracks(pg_s_xm, TrackID(ym_layer, pg_ym_locs[0], w_sig_ym),
min_len_mode=MinLenMode.MIDDLE)
self.connect_to_tracks(pg_d, TrackID(vm_layer, pg_vm_locs[-1], w_sig_vm))
# passgate: s is output and d is input in the row decoder
self.add_pin(f'nin<{idx}>', pg_d[0], label=f'in<{idx}>')
self.add_pin(f'pin<{idx}>', pg_d[1], label=f'in<{idx}>')
pg_out_vm_list.append(pg_s_vm)
pg_out_ym_list.append(pg_s_ym)
# sel and selb
if len(sel_vm_locs) == 0:
for nand_idx, nand_in in enumerate(and_in_list):
_nand_out = _and.get_pin(f'nand_out{nand_idx}')
_, _vm_locs = self.tr_manager.place_wires(vm_layer, ['sig'] * (2 * nand_in + 1),
_nand_out.track_id.base_index, -1)
sel_vm_locs.extend(_vm_locs[0:-1:2])
selb_vm_locs.extend(_vm_locs[1:-1:2])
bin_idx = f'{idx:0b}'.zfill(num_sel)
for char_idx, bin_char in enumerate(bin_idx):
sel_idx = num_sel - 1 - char_idx
if bin_char == '1':
sel_hm_list[sel_idx].append(_and.get_pin(f'in<{sel_idx}>'))
else:
selb_hm_list[sel_idx].append(_and.get_pin(f'in<{sel_idx}>'))
self.set_mos_size(num_cols=tot_ncols, num_tiles=1 + num_in)
# output
self.connect_wires(pg_out_vm_list)
out_ym = self.connect_wires(pg_out_ym_list, upper=self.bound_box.yh)[0]
self.add_pin('out', out_ym, mode=PinMode.UPPER)
# tile 0: left tap, inverters, right tap
vdd_tap_list, vss_tap_list = [], []
vdd_hm_list0, vss_hm_list0 = [], []
if draw_taps.has_left:
self.add_tap(0, vdd_tap_list, vss_tap_list, tile_idx=0, seg=seg_tap)
if draw_taps.has_right:
self.add_tap(tot_ncols, vdd_tap_list, vss_tap_list, tile_idx=0, flip_lr=True, seg=seg_tap)
cur_col = start_col
for idx in range(num_sel):
_master = inv_master_o if (idx & 1) else inv_master_e
_inv = self.add_tile(_master, 0, cur_col)
vdd_hm_list0.append(_inv.get_pin('VDD'))
vss_hm_list0.append(_inv.get_pin('VSS'))
sel_hm_list[idx].append(_inv.get_pin('nin'))
sel_vm = self.connect_to_tracks(sel_hm_list[idx], TrackID(vm_layer, sel_vm_locs[idx], w_sig_vm),
track_lower=0, track_upper=self.bound_box.yh)
self.add_pin(f'sel<{idx}>', sel_vm, mode=PinMode.LOWER)
selb_hm_list[idx].extend([_inv.get_pin('pout'), _inv.get_pin('nout')])
self.connect_to_tracks(selb_hm_list[idx], TrackID(vm_layer, selb_vm_locs[idx], w_sig_vm),
track_lower=0, track_upper=self.bound_box.yh)
cur_col += inv_ncols + self.min_sep_col
vss_hm_list.append(self.connect_wires(vss_hm_list0)[0])
self.connect_to_track_wires(vss_tap_list, vss_hm_list[-1])
vdd_hm_list.append(self.connect_wires(vdd_hm_list0)[0])
self.connect_to_track_wires(vdd_tap_list, vdd_hm_list[-1])
# --- Routing --- #
# supply
route_supplies(self, vdd_hm_list, vss_hm_list, self.bound_box.xh, draw_taps)
self.sch_params = dict(
inv_params=inv_master_e.sch_params,
and_params=and_master.sch_params,
pg_params=pg_master.sch_params,
num_sel=num_sel,
decoder_type='row',
)
[docs]class RDACDecoderCol(MOSBase):
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None:
MOSBase.__init__(self, temp_db, params, **kwargs)
self._pg_tile0 = 0
@property
[docs] def pg_tile0(self) -> int:
# return the tile_idx of bottom-most passgate tile
return self._pg_tile0
@classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]:
return bag3_analog__rdac_decoder_row_col
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]:
return dict(
pinfo='The MOSBasePlaceInfo object.',
seg_dict='Dictionary of segments of sub cell components',
num_sel='Number of select inputs',
num_rows='Number of passgate rows',
)
[docs] def draw_layout(self) -> None:
pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
self.draw_base(pinfo)
seg_dict: Mapping[str, Any] = self.params['seg_dict']
num_sel: int = self.params['num_sel']
num_cols = 1 << num_sel
num_rows: int = self.params['num_rows']
seg_tap = 4
# make masters
pd0_tidx = self.get_track_index(1, MOSWireType.DS, 'sig', 0)
pg_tidx = self.get_track_index(1, MOSWireType.G, 'sig', 0)
nd1_tidx = self.get_track_index(0, MOSWireType.DS, 'sig', -1)
inv_params_e = dict(pinfo=pinfo, seg=seg_dict['inv'], vertical_out=False)
inv_params_o = dict(pinfo=pinfo, seg=seg_dict['inv'], vertical_out=False,
sig_locs={'pout': pd0_tidx, 'nout': nd1_tidx, 'nin': pg_tidx})
inv_master_e = self.new_template(InvCore, params=inv_params_e)
inv_master_o = self.new_template(InvCore, params=inv_params_o)
inv_ncols = inv_master_e.num_cols
pg_params = dict(pinfo=pinfo, seg=seg_dict['pg'], vertical_out=False)
pg_master = self.new_template(PassGateCore, params=pg_params)
pg_ncols = pg_master.num_cols
and_params = dict(pinfo=pinfo, seg_dict=seg_dict['and'], num_in=num_sel)
and_master: AndComplexCol = self.new_template(AndComplexCol, params=and_params)
and_ncols = and_master.num_cols
and_ntiles = and_master.num_tile_rows
tot_ntiles = and_ntiles + num_rows
self._pg_tile0 = and_ntiles
tap_ncols = self.get_tap_ncol(seg_tap)
hm_layer = self.conn_layer + 1
vm_layer = hm_layer + 1
xm_layer = vm_layer + 1
# --- Placement --- #
vdd_tap_list = [[] for _ in range(tot_ntiles)]
vss_tap_list = [[] for _ in range(tot_ntiles)]
vdd_hm_list = [[] for _ in range(tot_ntiles)]
vss_hm_list = [[] for _ in range(tot_ntiles)]
# left tap
for tile_idx in range(tot_ntiles):
self.add_tap(0, vdd_tap_list[tile_idx], vss_tap_list[tile_idx], tile_idx=tile_idx, seg=seg_tap)
# column: and_col with passgates
cur_col = tap_ncols + self.sub_sep_col + self.min_sep_col // 2
sel_vm_list = [[] for _ in range(num_sel)]
selb_vm_list = [[] for _ in range(num_sel)]
pg_nd_list = [[] for _ in range(num_rows)]
pg_pd_list = [[] for _ in range(num_rows)]
for col_idx in range(num_cols):
_and = self.add_tile(and_master, 0, cur_col)
# and_complex supplies
_and_vdd = _and.get_all_port_pins('VDD')
_and_vss = _and.get_all_port_pins('VSS')
for _tidx in range(and_ntiles):
vdd_hm_list[_tidx].append(_and_vdd[_tidx])
vss_hm_list[_tidx].append(_and_vss[_tidx])
# sel and selb
bin_idx = f'{col_idx:0b}'.zfill(num_sel)
for char_idx, bin_char in enumerate(bin_idx):
sel_idx = num_sel - 1 - char_idx
if bin_char == '1':
sel_vm_list[sel_idx].append(_and.get_pin(f'in<{sel_idx}>'))
else:
selb_vm_list[sel_idx].append(_and.get_pin(f'in<{sel_idx}>'))
# and_complex outputs
_en = _and.get_pin('out')
_enb = _and.get_pin('outb')
en_list, enb_list = [], []
for row_idx in range(num_rows):
_tidx = and_ntiles + row_idx
_pg = self.add_tile(pg_master, _tidx, cur_col)
# passgate supplies
vdd_hm_list[_tidx].append(_pg.get_pin('VDD'))
vss_hm_list[_tidx].append(_pg.get_pin('VSS'))
# passgate outputs
pg_nd_list[row_idx].append(_pg.get_pin('nd'))
pg_pd_list[row_idx].append(_pg.get_pin('pd'))
# passgate en and enb
en_list.append(_pg.get_pin('en'))
enb_list.append(_pg.get_pin('enb'))
# passgate input
ref_tidx = min(_en.track_id.base_index, _enb.track_id.base_index)
_vm_tidx = self.tr_manager.get_next_track(vm_layer, ref_tidx, 'sig', 'sig', -1)
_vm_tid = TrackID(vm_layer, _vm_tidx, _en.track_id.width)
_in_vm = self.connect_to_tracks(_pg.get_pin('s'), _vm_tid, min_len_mode=MinLenMode.MIDDLE)
self.add_pin(f'in<{row_idx * num_cols + col_idx}>', _in_vm)
self.connect_to_track_wires(en_list, _en)
self.connect_to_track_wires(enb_list, _enb)
cur_col += max(and_ncols, pg_ncols) + self.min_sep_col
# vm_locs for inverters
and_in_list = and_master.nand_in_list
vm_tidx0 = self.grid.coord_to_track(vm_layer, cur_col * self.sd_pitch, RoundMode.NEAREST)
_, inv_vm_locs = self.tr_manager.place_wires(vm_layer, ['sig'] * (num_sel + 1), vm_tidx0)
vm_col = self.grid.track_to_coord(vm_layer, inv_vm_locs[-1]) // self.sd_pitch
# place inverters
cur_col1 = cur_col
w_sig_vm = self.tr_manager.get_width(vm_layer, 'sig')
w_sig_xm = self.tr_manager.get_width(xm_layer, 'sig')
sel_idx = 0
inv_col = cur_col
_selb_tidx = None
_sel_tidx = None
for tile_idx, and_in in enumerate(and_in_list):
xm_locs = []
_and_idx = tile_idx
for _in_idx in range(and_in):
tile_idx = sum(and_in_list[0:_and_idx + 1]) - _in_idx - 1
_master = inv_master_o if (_in_idx & 1) else inv_master_e
_inv = self.add_tile(_master, tile_idx, inv_col)
# supplies
vdd_hm_list[tile_idx].append(_inv.get_pin('VDD'))
vss_hm_list[tile_idx].append(_inv.get_pin('VSS'))
# get xm_layer wires
if len(xm_locs) == 0:
for _tile_idx in range(num_sel):
vdd_tidx = self.get_track_index(-1, MOSWireType.DS, 'sup', 0, tile_idx=_tile_idx)
vss_tidx = self.get_track_index(0, MOSWireType.DS, 'sup', 0, tile_idx=_tile_idx)
vdd_ym = self.grid.track_to_coord(hm_layer, vdd_tidx)
vss_ym = self.grid.track_to_coord(hm_layer, vss_tidx)
tmp = self.tr_manager.place_wires(xm_layer, ['sig'] * 2, center_coord=(vss_ym + vdd_ym) // 2)
xm_locs.extend(tmp[1])
_sel_idx = sel_idx + and_in - _in_idx - 1
# output
if not _selb_tidx:
_selb_tidx = self.grid.coord_to_track(vm_layer, _inv.bound_box.xl, RoundMode.LESS_EQ)
_ref_tidx = _selb_tidx if not _sel_tidx else _sel_tidx
_sel_tidx = self.tr_manager.get_next_track(vm_layer, _ref_tidx, 'sig', 'sig', 1)
_selb = self.connect_to_tracks([_inv.get_pin('pout'), _inv.get_pin('nout')],
TrackID(vm_layer, _selb_tidx, w_sig_vm))
selb_vm_list[_sel_idx].append(_selb)
self.connect_to_tracks(selb_vm_list[_sel_idx], TrackID(xm_layer, xm_locs[_sel_idx * 2], w_sig_xm))
# input
_sel = self.connect_to_tracks(_inv.get_pin('nin'),
TrackID(vm_layer, _sel_tidx, w_sig_vm),
track_lower=0)
sel_vm_list[_sel_idx].append(_sel)
self.connect_to_tracks(sel_vm_list[_sel_idx], TrackID(xm_layer, xm_locs[_sel_idx * 2 + 1], w_sig_xm))
self.add_pin(f'sel<{_sel_idx}>', _sel, mode=PinMode.LOWER)
cur_col1 = max(cur_col1, inv_col)
sel_idx += and_in
tot_ncols = max(cur_col1 - self.min_sep_col // 2, vm_col) + self.sub_sep_col + tap_ncols
# right tap
for tile_idx in range(tot_ntiles):
self.add_tap(tot_ncols, vdd_tap_list[tile_idx], vss_tap_list[tile_idx], tile_idx=tile_idx, flip_lr=True,
seg=seg_tap)
self.set_mos_size()
# --- Routing --- #
# passgate outputs
for row_idx in range(num_rows):
self.add_pin(f'nout<{row_idx}>', self.connect_wires(pg_nd_list[row_idx])[0], label=f'out<{row_idx}>',
connect=True, mode=PinMode.UPPER)
self.add_pin(f'pout<{row_idx}>', self.connect_wires(pg_pd_list[row_idx])[0], label=f'out<{row_idx}>',
connect=True, mode=PinMode.UPPER)
# supply
vdd_hm, vss_hm = [], []
for _tidx in range(tot_ntiles):
vss_hm.append(self.connect_wires(vss_hm_list[_tidx])[0])
self.connect_to_track_wires(vss_tap_list[_tidx], vss_hm[-1])
vdd_hm.append(self.connect_wires(vdd_hm_list[_tidx])[0])
self.connect_to_track_wires(vdd_tap_list[_tidx], vdd_hm[-1])
route_supplies(self, vdd_hm, vss_hm, self.bound_box.xh)
self.sch_params = dict(
inv_params=inv_master_e.sch_params,
and_params=and_master.sch_params,
pg_params=pg_master.sch_params,
num_sel=num_sel,
num_rows=num_rows,
decoder_type='column',
)
[docs]def route_supplies(cls: MOSBase, vdd_hm_list: Sequence[WireArray], vss_hm_list: Sequence[WireArray], xh: int,
draw_taps: DrawTaps = DrawTaps.BOTH) -> None:
vdd_hm = cls.connect_wires(vdd_hm_list, lower=0, upper=xh)[0]
vss_hm = cls.connect_wires(vss_hm_list, lower=0, upper=xh)[0]
vdd_pin_list = [vdd_hm]
vss_pin_list = [vss_hm]
hm_layer = cls.conn_layer + 1
vm_layer = hm_layer + 1
xm_layer = vm_layer + 1
ym_layer = xm_layer + 1
xxm_layer = ym_layer + 1
for _hm_layer in (xm_layer, xxm_layer):
_vm_layer = _hm_layer - 1
vss_vm_list, vdd_vm_list = [], []
if draw_taps.has_left:
vss_vm_list.append(cls.grid.coord_to_track(_vm_layer, vss_hm.lower, RoundMode.GREATER_EQ))
vdd_vm_list.append(cls.tr_manager.get_next_track(_vm_layer, vss_vm_list[-1], 'sup', 'sup', up=1))
if draw_taps.has_right:
vss_vm_list.append(cls.grid.coord_to_track(_vm_layer, vss_hm.upper, RoundMode.LESS_EQ))
vdd_vm_list.append(cls.tr_manager.get_next_track(_vm_layer, vss_vm_list[-1], 'sup', 'sup', up=-1))
w_sup_vm = cls.tr_manager.get_width(_vm_layer, 'sup')
vdd_vm = cls.connect_to_tracks(vdd_hm, TrackID(_vm_layer, vdd_vm_list[0], w_sup_vm, len(vdd_vm_list),
vdd_vm_list[-1] - vdd_vm_list[0]))
vss_vm = cls.connect_to_tracks(vss_hm, TrackID(_vm_layer, vss_vm_list[0], w_sup_vm, len(vss_vm_list),
vss_vm_list[-1] - vss_vm_list[0]))
vdd_hm_l = cls.grid.coord_to_track(_hm_layer, vdd_hm[0].bound_box.ym, RoundMode.NEAREST)
vdd_hm_l1 = cls.grid.coord_to_track(_hm_layer, vdd_hm[1].bound_box.ym, RoundMode.NEAREST)
w_sup_hm = cls.tr_manager.get_width(_hm_layer, 'sup')
vdd_hm = cls.connect_to_tracks(vdd_vm, TrackID(_hm_layer, vdd_hm_l, w_sup_hm, vdd_hm.track_id.num,
vdd_hm_l1 - vdd_hm_l), track_lower=0, track_upper=xh)
vdd_pin_list.append(vdd_hm)
vss_hm_l = cls.grid.coord_to_track(_hm_layer, vss_hm[0].bound_box.ym, RoundMode.NEAREST)
vss_hm_l1 = cls.grid.coord_to_track(_hm_layer, vss_hm[1].bound_box.ym, RoundMode.NEAREST)
vss_hm = cls.connect_to_tracks(vss_vm, TrackID(_hm_layer, vss_hm_l, w_sup_hm, vss_hm.track_id.num,
vss_hm_l1 - vss_hm_l), track_lower=0, track_upper=xh)
vss_pin_list.append(vss_hm)
cls.add_pin('VDD', vdd_pin_list)
cls.add_pin('VSS', vss_pin_list)