def draw_layout(self): lch = self.params['lch'] guard_ring_nf = self.params['guard_ring_nf'] layout_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf) bot_inst, top_inst, col_idx_dict = self.place(layout_info) self.connect(layout_info, bot_inst, top_inst, col_idx_dict) self._col_idx_dict = col_idx_dict
def __init__(self, grid, lch, guard_ring_nf, top_layer=None, end_mode=15, min_fg_sep=0, fg_tot=None): # type: (RoutingGrid, float, int, Optional[int], int, int, Optional[int]) -> None AnalogBaseInfo.__init__(self, grid, lch, guard_ring_nf, top_layer=top_layer, end_mode=end_mode, min_fg_sep=min_fg_sep, fg_tot=fg_tot)
def find_fg_tot(self, res, lch, width, larger_mode=False, unit_mode=True): # type: (float, float, Union[float, int], bool, bool) -> int """ find track width just larger than given width will be done by eric in future Parameters ------------- res: float the layout grid resolution. layer: int metal layer id width: float width of metal layer larger_mode: bool find larger track or smaller track unit_mode: bool True if width and points are given as resolution units instead of layout units. Return ------------- track width """ layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) if unit_mode is False: width = round(width / res) width_try = 0 i = 0 while width >= width_try: i += 1 width_try = layout_info.get_total_width(i) if larger_mode is True: return i else: return i - 1
def connect(self, inst_list, col_idx_dict): lch = self.params['lch'] guard_ring_nf = self.params['guard_ring_nf'] layout_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf) hm_layer_id = layout_info.mconn_port_layer + 1 vm_layer_id = hm_layer_id + 1 diff_space = self.params['diff_space'] # connect inputs of even and odd paths route_col_intv = col_idx_dict['integ'] ptr_idx = layout_info.get_center_tracks(vm_layer_id, 2 + diff_space, route_col_intv) ntr_idx = ptr_idx + diff_space + 1 p_list = [] n_list = [] for inst in inst_list: p_list += inst.get_port('integ_inp').get_pins(hm_layer_id) n_list += inst.get_port('integ_inn').get_pins(hm_layer_id) inp, inn = self.connect_differential_tracks(p_list, n_list, vm_layer_id, ptr_idx, ntr_idx) self.add_pin('inp', inp, show=True) self.add_pin('inn', inn, show=True)
def draw_layout(self): """Draw the layout of a dynamic latch chain. """ # type: () -> None lch = self.params['lch'] ptap_w = self.params['ptap_w'] ntap_w = self.params['ntap_w'] w_dict = self.params['w_dict'] th_dict = self.params['th_dict'] seg_dict = self.params['seg_dict'] stack_dict = self.params['stack_dict'] ndum = self.params['ndum'] tr_widths = self.params['tr_widths'] tr_spaces = self.params['tr_spaces'] show_pins = self.params['show_pins'] guard_ring_nf = self.params['guard_ring_nf'] top_layer = self.params['top_layer'] ana_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf, top_layer=top_layer) min_fg_sep = ana_info.min_fg_sep # calculate total number of fingers seg_tail1 = seg_dict['tail1'] seg_tail2 = seg_dict['tail2'] seg_tailcm = seg_dict['tailcm'] seg_in = seg_dict['in'] seg_ref = seg_dict['ref'] seg_diode1 = seg_dict['diode1'] seg_ngm1 = seg_dict['ngm1'] seg_diode2 = seg_dict['diode2'] seg_ngm2 = seg_dict['ngm2'] stack_tail = stack_dict['tail'] stack_in = stack_dict['in'] stack_diode = stack_dict['diode'] stack_ngm = stack_dict['ngm'] fg_tail1 = seg_tail1 * stack_tail fg_tail2 = seg_tail2 * stack_tail fg_tailcm = seg_tailcm * stack_tail fg_in = seg_in * stack_in fg_diode1 = seg_diode1 * stack_diode fg_ngm1 = seg_ngm1 * stack_ngm fg_diode2 = seg_diode2 * stack_diode fg_ngm2 = seg_ngm2 * stack_ngm fg_ref = seg_ref * stack_in fg_load = fg_diode1 + fg_ngm1 fg_in2 = fg_diode2 + fg_ngm2 fg_bias2 = fg_tail2 + fg_tailcm # error checking if fg_tail1 != fg_in: raise ValueError('This template assumes fg_tail = fg_in') if stack_tail % stack_in != 0 and stack_in % stack_tail != 0: raise ValueError('one of stack_tail/stack_in must divide the other.') if stack_ngm % stack_in != 0 and stack_in % stack_ngm != 0: raise ValueError('one of stack_ngm/stack_in must divide the other.') fg_single1 = max(fg_in, fg_load) fg_single2 = max(fg_bias2, fg_in2) fg_tot = 2 * (fg_single1 + fg_single2 + ndum) + 4 * min_fg_sep + fg_ref # get width/threshold/orientation info nw_list = [w_dict['load']] nth_list = [th_dict['load']] n_orientations = ['MX'] pw_list = [w_dict['in'], w_dict['tail']] pth_list = [th_dict['in'], th_dict['tail']] p_orientations = ['MX', 'MX'] # get tracks information tr_manager = TrackManager(self.grid, tr_widths, tr_spaces) hm_layer = self.get_mos_conn_layer(self.grid.tech_info) + 1 vm_layer = hm_layer + 1 # allocate tracks wire_names = dict( nch=[ dict(ds=[], g=['out', 'out']), ], pch=[ dict(ds=['bias', 'tail'], g=['in', 'in', 'in', 'in']), dict(ds=['tail'], g=['bias', 'bias']), ], ) # draw base self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, tr_manager=tr_manager, wire_names=wire_names, n_orientations=n_orientations, p_orientations=p_orientations, guard_ring_nf=guard_ring_nf, top_layer=top_layer) # draw stage1 transistors col_left = ndum + fg_single2 + fg_single1 + min_fg_sep col_right = col_left + 2 * min_fg_sep + fg_ref diode1l = self.draw_mos_conn('nch', 0, col_left - fg_load, fg_diode1, 2, 0, stack=stack_diode, s_net='midn', d_net='') ngm1l = self.draw_mos_conn('nch', 0, col_left - fg_ngm1, fg_ngm1, 2, 0, stack=stack_ngm, s_net='midn', d_net='') ngm1r = self.draw_mos_conn('nch', 0, col_right, fg_ngm1, 2, 0, stack=stack_ngm, s_net='midp', d_net='') diode1r = self.draw_mos_conn('nch', 0, col_right + fg_ngm1, fg_diode1, 2, 0, stack=stack_diode, s_net='midp', d_net='') inl = self.draw_mos_conn('pch', 0, col_left - fg_in, fg_in, 0, 2, stack=stack_in, s_net='midn', d_net='tail') inm = self.draw_mos_conn('pch', 0, col_left + min_fg_sep, fg_ref, 0, 2, stack=stack_in, s_net='bias', d_net='tail_ref') inr = self.draw_mos_conn('pch', 0, col_right, fg_in, 0, 2, stack=stack_in, s_net='midp', d_net='tail') bias1l = self.draw_mos_conn('pch', 1, col_left - fg_tail1, fg_tail1, 2, 0, stack=stack_tail, s_net='', d_net='tail') biasm = self.draw_mos_conn('pch', 1, col_left + min_fg_sep, fg_ref, 2, 0, stack=stack_tail, s_net='', d_net='tail_ref') bias1r = self.draw_mos_conn('pch', 1, col_right, fg_tail1, 2, 0, stack=stack_tail, s_net='', d_net='tail') # draw stage2 transistors col_left = ndum + fg_single2 col_right += fg_single1 + min_fg_sep diode2l = self.draw_mos_conn('nch', 0, col_left - fg_in2, fg_diode2, 0, 2, stack=stack_diode, s_net='', d_net='outp') ngm2l = self.draw_mos_conn('nch', 0, col_left - fg_ngm2, fg_ngm2, 0, 2, stack=stack_ngm, s_net='', d_net='outp') ngm2r = self.draw_mos_conn('nch', 0, col_right, fg_ngm2, 0, 2, stack=stack_ngm, s_net='', d_net='outn') diode2r = self.draw_mos_conn('nch', 0, col_right + fg_ngm2, fg_diode2, 0, 2, stack=stack_diode, s_net='', d_net='outn') cm2l = self.draw_mos_conn('pch', 1, col_left - fg_bias2, fg_tailcm, 2, 0, stack=stack_tail, s_net='', d_net='outp') bias2l = self.draw_mos_conn('pch', 1, col_left - fg_tail2, fg_tail2, 2, 0, stack=stack_tail, s_net='', d_net='outp') bias2r = self.draw_mos_conn('pch', 1, col_right, fg_tail2, 2, 0, stack=stack_tail, s_net='', d_net='outn') cm2r = self.draw_mos_conn('pch', 1, col_right + fg_tail2, fg_tailcm, 2, 0, stack=stack_tail, s_net='', d_net='outn') # get track locations midp_tid = self.get_wire_id('nch', 0, 'g', wire_idx=1) midn_tid = self.get_wire_id('nch', 0, 'g', wire_idx=0) tail2_tid = self.get_wire_id('pch', 0, 'ds', wire_name='tail') bias2_tid = self.get_wire_id('pch', 0, 'ds', wire_name='bias') inc1_tid = self.get_wire_id('pch', 0, 'g', wire_idx=3) inp_tid = self.get_wire_id('pch', 0, 'g', wire_idx=2) inn_tid = self.get_wire_id('pch', 0, 'g', wire_idx=1) inc2_tid = self.get_wire_id('pch', 0, 'g', wire_idx=0) tail1_tid = self.get_wire_id('pch', 1, 'ds', wire_name='tail') cm_tid = self.get_wire_id('pch', 1, 'g', wire_idx=1) bias1_tid = self.get_wire_id('pch', 1, 'g', wire_idx=0) w_bias = cm_tid.width w_tail = tail1_tid.width w_out = midp_tid.width w_in = inp_tid.width # draw connections # connect VDD/VSS self.connect_to_substrate('ntap', [bias1l['s'], biasm['s'], bias1r['s'], cm2l['s'], cm2r['s'], bias2l['s'], bias2r['s']]) self.connect_to_substrate('ptap', [diode1l['d'], ngm1l['d'], ngm1r['d'], diode1r['d'], diode2l['s'], ngm2l['s'], ngm2r['s'], diode2r['s']]) # connect bias/tail wires self.connect_differential_tracks([inl['d'], inr['d'], bias1l['d'], bias1r['d']], [biasm['d'], inm['d']], hm_layer, tail2_tid.base_index, tail1_tid.base_index, width=w_tail) bias2 = self.connect_to_tracks(inm['s'], bias2_tid) bias1_warrs = [bias1l['g'], biasm['g'], bias1r['g'], bias2l['g'], bias2r['g']] cm_warrs = [cm2l['g'], cm2r['g']] bias1, cmbias = self.connect_differential_tracks(bias1_warrs, cm_warrs, hm_layer, bias1_tid.base_index, cm_tid.base_index, width=w_bias) mid_tid = self.grid.coord_to_nearest_track(vm_layer, bias1.middle) bias_vtid = TrackID(vm_layer, mid_tid, width=tr_manager.get_width(vm_layer, 'bias')) bias = self.connect_to_tracks([bias1, bias2], bias_vtid) # connect middle wires midp_warrs = [inr['s'], ngm1r['s'], diode1r['s'], diode1r['g'], ngm1l['g'], diode2r['g'], ngm2r['g']] midn_warrs = [inl['s'], ngm1l['s'], diode1l['s'], diode1l['g'], ngm1r['g'], diode2l['g'], ngm2l['g']] midp, midn = self.connect_differential_tracks(midp_warrs, midn_warrs, hm_layer, midp_tid.base_index, midn_tid.base_index, width=w_out) # connect inputs inc1_warrs = inc2_warrs = inm['g'] inp_warrs = inl['g'] inn_warrs = inr['g'] inp_tidx, inn_tidx = inp_tid.base_index, inn_tid.base_index inc1, inp, inn, inc2 = self.connect_matching_tracks( [inc1_warrs, inp_warrs, inn_warrs, inc2_warrs], hm_layer, [inc1_tid.base_index, inp_tidx, inn_tidx, inc2_tid.base_index], width=w_in) # connect outputs out_tidx = self.grid.get_middle_track(inp_tidx, inn_tidx) outp = self.connect_to_tracks([diode2l['d'], ngm2l['d'], bias2l['d'], cm2l['d']], TrackID(hm_layer, out_tidx, width=w_out)) outn = self.connect_to_tracks([diode2r['d'], ngm2r['d'], bias2r['d'], cm2r['d']], TrackID(hm_layer, out_tidx, width=w_out)) # fill dummies sup_width = tr_manager.get_width(hm_layer, 'sup') vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=sup_width, vss_width=sup_width) # add pins self.add_pin('ref', [inc1, inc2], show=show_pins) self.add_pin('inp', inp, show=show_pins) self.add_pin('inn', inn, show=show_pins) self.add_pin('bias', bias, show=show_pins) self.add_pin('cmbias', cmbias, show=show_pins) self.add_pin('midp', midp, show=show_pins) self.add_pin('midn', midn, show=show_pins) self.add_pin('outp', outp, show=show_pins) self.add_pin('outn', outn, show=show_pins) self.add_pin('VSS', vss_warrs, show=show_pins) self.add_pin('VDD', vdd_warrs, show=show_pins) # compute schematic parameters self._sch_params = dict( lch=lch, w_dict=w_dict, th_dict=th_dict, seg_dict=seg_dict, stack_dict=stack_dict, dum_info=self.get_sch_dummy_info(), )
def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, g_space, ds_space, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, show_pins, power_width_ntr, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # get resolution res = self.grid.resolution # make sure all fingers are even number if nfn % 2 != 0 or nfp % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side * 2 + ndum + max(nfn, nfp) * 2 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr + g_sp_ntr + g_space] pg_tracks = [g_width_ntr + g_sp_ntr + g_space] nds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space] pds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1) pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1) nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1) pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) # nor nor_n0_ports = self.draw_mos_conn('nch', 0, ndum_side, nfn, 1, 1, s_net='VSS', d_net='O') nor_p0_ports = self.draw_mos_conn('pch', 0, ndum_side, nfp, 1, 1, s_net='VDD', d_net='ps') col_idx = ndum_side + max(nfn, nfp) + ndum nor_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn, 1, 1, s_net='VSS', d_net='O') nor_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp, 1, 1, s_net='ps', d_net='O') # connect nor nor_gn0_warr = self.connect_to_tracks(nor_n0_ports['g'], ngate_id, min_len_mode=0) nor_gp0_warr = self.connect_to_tracks(nor_p0_ports['g'], pgate_id, min_len_mode=0) nor_g0_idx = self.grid.coord_to_nearest_track( nor_gn0_warr.layer_id + 1, nor_gn0_warr.middle) nor_g0_tid = TrackID(nor_gn0_warr.layer_id + 1, nor_g0_idx) nor_g0 = self.connect_to_tracks([nor_gn0_warr, nor_gp0_warr], nor_g0_tid, min_len_mode=0) nor_gn1_warr = self.connect_to_tracks(nor_n1_ports['g'], ngate_id, min_len_mode=0) nor_gp1_warr = self.connect_to_tracks(nor_p1_ports['g'], pgate_id, min_len_mode=0) nor_g1_idx = self.grid.coord_to_nearest_track( nor_gn0_warr.layer_id + 1, nor_gn1_warr.middle) nor_g1_tid = TrackID(nor_gn0_warr.layer_id + 1, nor_g1_idx) nor_g1 = self.connect_to_tracks([nor_gn1_warr, nor_gp1_warr], nor_g1_tid, min_len_mode=0) # connect nor_n0 and nor_n1 self.connect_to_tracks([nor_p0_ports['d'], nor_p1_ports['s']], pdrain_id, min_len_mode=0) self.connect_to_substrate('ptap', [nor_n0_ports['s'], nor_n1_ports['s']]) self.connect_to_substrate('ntap', nor_p0_ports['s']) # connect drain to output o = self.connect_to_tracks( [nor_n0_ports['d'], nor_n1_ports['d'], nor_p1_ports['d']], nout_id, min_len_mode=0) # add pins self.add_pin('A', nor_g0, show=show_pins) self.add_pin('B', nor_g1, show=show_pins) self.add_pin('O', o, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.set_size_from_array_box(m5v_layer) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nfn=nfn, nfp=nfp, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_inv1, nf_inv2, nf_inv3, nf_tinv0_0, nf_tinv0_1, nf_tinv1_0, nf_tinv1_1, nf_tinv2_0, nf_tinv2_1, nf_tinv3_0, nf_tinv3_1, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, show_pins, g_space, ds_space, power_width_ntr, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # TODO: assumption1 -- all nmos/pmos have same finger number # TODO: assumption2 -- all nmos/pmos finger number are even # get resolution res = self.grid.resolution # make sure all fingers are even number if nf_inv0%2 != 0 or nf_inv1%2 != 0 or nf_inv2%2 != 0 or nf_inv3%2 != 0 or \ nf_tinv0_0%2 != 0 or nf_tinv1_0%2 != 0 or nf_tinv2_0%2 != 0 or nf_tinv3_0%2 != 0 or \ nf_tinv0_1%2 != 0 or nf_tinv1_1%2 != 0 or nf_tinv2_1%2 != 0 or nf_tinv3_1%2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side*2 + ndum*11 + nf_inv0 + nf_inv1 + nf_inv2 + nf_inv3 + \ nf_tinv0_0 + nf_tinv1_0 + nf_tinv2_0 + nf_tinv3_0 + \ nf_tinv0_1 + nf_tinv1_1 + nf_tinv2_1 + nf_tinv3_1 + 2 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr * 2 + g_sp_ntr + g_space] pg_tracks = [g_width_ntr * 2 + g_sp_ntr + g_space] nds_tracks = [ds_width_ntr * 2 + ds_sp_ntr + ds_space] pds_tracks = [ds_width_ntr * 2 + ds_sp_ntr + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index ck_id = self.make_track_id('nch', 0, 'g', 0, width=1) ckb_id = self.make_track_id('pch', 0, 'g', 0, width=1) ngate_id = self.make_track_id('nch', 0, 'g', 1, width=1) pgate_id = self.make_track_id('pch', 0, 'g', 1, width=1) nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1) pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) # Step1: connect inverter # group transistors # inv2 inv2_n_ports = self.draw_mos_conn('nch', 0, ndum_side, nf_inv2, 1, 1, s_net='VSS', d_net='iclkb') inv2_p_ports = self.draw_mos_conn('pch', 0, ndum_side, nf_inv2, 1, 1, s_net='VDD', d_net='iclkb') # inv3 inv3_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum + nf_inv2, nf_inv3, 1, 1, s_net='VSS', d_net='iclk') inv3_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum + nf_inv2, nf_inv3, 1, 1, s_net='VDD', d_net='iclk') # tinv0 tinv0_n0_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 2 + nf_inv2 + nf_inv3, nf_tinv0_0, 1, 1, s_net='VSS', d_net='tinv0_ns') tinv0_p0_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 2 + nf_inv2 + nf_inv3, nf_tinv0_0, 1, 1, s_net='VDD', d_net='tinv0_ps') col_idx = ndum_side + ndum * 3 + nf_inv2 + nf_inv3 + nf_tinv0_0 + 2 tinv0_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv0_1, 1, 1, s_net='tinv0_ns', d_net='mem1') tinv0_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv0_1, 1, 1, s_net='tinv0_ps', d_net='mem1') # inv0 col_idx = ndum_side + ndum * 4 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + 2 inv0_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv0, 1, 1, s_net='VSS', d_net='latch') inv0_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv0, 1, 1, s_net='VDD', d_net='latch') # tinv1 col_idx = ndum_side + ndum * 5 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + 2 tinv1_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv1_0, 1, 1, s_net='VSS', d_net='tinv1_ns') tinv1_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv1_0, 1, 1, s_net='VDD', d_net='tinv1_ps') col_idx = ndum_side + ndum * 6 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 +\ nf_tinv1_0 + 2 tinv1_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv1_1, 1, 1, s_net='tinv1_ns', d_net='mem1') tinv1_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv1_1, 1, 1, s_net='tinv1_ps', d_net='mem1') # tinv2 col_idx = ndum_side + ndum * 7 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \ nf_tinv1_0 + nf_tinv1_1 + 2 tinv2_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv2_0, 1, 1, s_net='VSS', d_net='tinv2_ns') tinv2_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv2_0, 1, 1, s_net='VDD', d_net='tinv2_ps') col_idx = ndum_side + ndum * 8 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \ nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + 2 tinv2_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv2_1, 1, 1, s_net='tinv2_ns', d_net='mem2') tinv2_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv2_1, 1, 1, s_net='tinv2_ps', d_net='mem2') # inv1 col_idx = ndum_side + ndum * 9 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \ nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + 2 inv1_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv1, 1, 1, s_net='VSS', d_net='o') inv1_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv1, 1, 1, s_net='VDD', d_net='o') # tinv3 col_idx = ndum_side + ndum * 10 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \ nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + nf_inv1 + 2 tinv3_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv3_0, 1, 1, s_net='VSS', d_net='tinv3_ns') tinv3_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv3_0, 1, 1, s_net='VDD', d_net='tinv3_ps') col_idx = ndum_side + ndum * 11 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \ nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + nf_inv1 + nf_tinv3_0 + 2 tinv3_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv3_1, 1, 1, s_net='tinv3_ns', d_net='mem2') tinv3_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv3_1, 1, 1, s_net='tinv3_ps', d_net='mem2') # connect inv2, inv3 (clock buffers) # inv2 inv2_n_warr = self.connect_to_tracks(inv2_n_ports['g'], ngate_id, min_len_mode=0) inv2_p_warr = self.connect_to_tracks(inv2_p_ports['g'], pgate_id, min_len_mode=0) inv2_idx = self.grid.coord_to_nearest_track(inv2_n_warr.layer_id + 1, inv2_n_warr.middle) inv2_tid = TrackID(inv2_n_warr.layer_id + 1, inv2_idx) clk = self.connect_to_tracks([inv2_n_warr, inv2_p_warr], inv2_tid) self.connect_to_substrate('ptap', inv2_n_ports['s']) self.connect_to_substrate('ntap', inv2_p_ports['s']) # inv3 inv3_n_warr = self.connect_to_tracks(inv3_n_ports['g'], ngate_id, min_len_mode=0) inv3_p_warr = self.connect_to_tracks(inv3_p_ports['g'], pgate_id, min_len_mode=0) inv3_idx = self.grid.coord_to_nearest_track(inv3_n_warr.layer_id + 1, inv3_n_warr.middle) inv3_tid = TrackID(inv3_n_warr.layer_id + 1, inv3_idx) inv3_g_wire = self.connect_to_tracks([inv3_n_warr, inv3_p_warr], inv3_tid) self.connect_to_tracks( [inv2_n_ports['d'], inv2_p_ports['d'], inv3_g_wire], pout_id) iclkb = inv3_g_wire self.connect_to_substrate('ptap', inv3_n_ports['s']) self.connect_to_substrate('ntap', inv3_p_ports['s']) inv3_d_wire = self.connect_to_tracks( [inv3_n_ports['d'], inv3_p_ports['d']], nout_id, min_len_mode=0) iclk_idx = self.grid.coord_to_nearest_track(inv3_d_wire.layer_id + 1, inv3_d_wire.lower) iclk_tid = TrackID(inv3_d_wire.layer_id + 1, iclk_idx) iclk = self.connect_to_tracks(inv3_d_wire, iclk_tid) # tinv0 i_n_warr = self.connect_to_tracks(tinv0_n0_ports['g'], ngate_id, min_len_mode=0) i_p_warr = self.connect_to_tracks(tinv0_p0_ports['g'], pgate_id, min_len_mode=0) i_idx = self.grid.coord_to_nearest_track(i_n_warr.layer_id + 1, i_n_warr.middle) i_tid = TrackID(i_n_warr.layer_id + 1, i_idx) i = self.connect_to_tracks([i_n_warr, i_p_warr], i_tid) self.connect_to_substrate('ptap', tinv0_n0_ports['s']) self.connect_to_substrate('ntap', tinv0_p0_ports['s']) self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']], pdrain_id) # inv0 inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'], ngate_id, min_len_mode=0) inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'], pgate_id, min_len_mode=0) inv0_g_idx = self.grid.coord_to_nearest_track( inv0_gn_warr.layer_id + 1, inv0_gn_warr.middle) inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx) inv0_g = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr], inv0_g_tid) # mem1 = self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], inv0_g], nout_id) self.connect_to_substrate('ptap', inv0_n_ports['s']) self.connect_to_substrate('ntap', inv0_p_ports['s']) # tinv1 tinv1_gn_warr = self.connect_to_tracks(tinv1_n0_ports['g'], ngate_id, min_len_mode=0) tinv1_gp_warr = self.connect_to_tracks(tinv1_p0_ports['g'], pgate_id, min_len_mode=0) tinv1_g_idx = self.grid.coord_to_nearest_track( tinv1_gn_warr.layer_id + 1, tinv1_gn_warr.middle) tinv1_g_tid = TrackID(tinv1_gn_warr.layer_id + 1, tinv1_g_idx) tinv1_g = self.connect_to_tracks([tinv1_gn_warr, tinv1_gp_warr], tinv1_g_tid) # latch = self.connect_to_tracks([inv0_n_ports['d'], inv0_p_ports['d'], tinv1_g], nout_id) self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']], pdrain_id) self.connect_to_substrate('ptap', tinv1_n0_ports['s']) self.connect_to_substrate('ntap', tinv1_p0_ports['s']) mem1 = self.connect_to_tracks([ tinv0_n1_ports['d'], tinv0_p1_ports['d'], inv0_g, tinv1_n1_ports['d'], tinv1_p1_ports['d'] ], pout_id) # tinv2 tinv2_gn_warr = self.connect_to_tracks(tinv2_n0_ports['g'], ngate_id, min_len_mode=0) tinv2_gp_warr = self.connect_to_tracks(tinv2_p0_ports['g'], pgate_id, min_len_mode=0) tinv2_g_idx = self.grid.coord_to_nearest_track( tinv2_gn_warr.layer_id + 1, tinv2_gn_warr.middle) tinv2_g_tid = TrackID(tinv2_gn_warr.layer_id + 1, tinv2_g_idx) tinv2_g = self.connect_to_tracks([tinv2_gn_warr, tinv2_gp_warr], tinv2_g_tid) latch = self.connect_to_tracks( [inv0_n_ports['d'], inv0_p_ports['d'], tinv1_g, tinv2_g], nout_id) self.connect_to_substrate('ptap', tinv2_n0_ports['s']) self.connect_to_substrate('ntap', tinv2_p0_ports['s']) self.connect_to_tracks([tinv2_n0_ports['d'], tinv2_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv2_p0_ports['d'], tinv2_p1_ports['s']], pdrain_id) # inv1 inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'], ngate_id, min_len_mode=0) inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'], pgate_id, min_len_mode=0) inv1_g_idx = self.grid.coord_to_nearest_track( inv1_gn_warr.layer_id + 1, inv1_gn_warr.middle) inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx) inv1_g = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr], inv1_g_tid) self.connect_to_substrate('ptap', inv1_n_ports['s']) self.connect_to_substrate('ntap', inv1_p_ports['s']) # tinv3 tinv3_gn_warr = self.connect_to_tracks(tinv3_n0_ports['g'], ngate_id, min_len_mode=0) tinv3_gp_warr = self.connect_to_tracks(tinv3_p0_ports['g'], pgate_id, min_len_mode=0) tinv3_g_idx = self.grid.coord_to_nearest_track( tinv3_gn_warr.layer_id + 1, tinv3_gn_warr.middle) tinv3_g_tid = TrackID(tinv3_gn_warr.layer_id + 1, tinv3_g_idx) tinv3_g = self.connect_to_tracks([tinv3_gn_warr, tinv3_gp_warr], tinv3_g_tid) self.connect_to_tracks([inv1_n_ports['d'], inv1_p_ports['d'], tinv3_g], nout_id) o = tinv3_g self.connect_to_tracks([tinv3_n0_ports['d'], tinv3_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv3_p0_ports['d'], tinv3_p1_ports['s']], pdrain_id) self.connect_to_substrate('ptap', tinv3_n0_ports['s']) self.connect_to_substrate('ntap', tinv3_p0_ports['s']) mem2 = self.connect_to_tracks([ tinv2_n1_ports['d'], tinv2_p1_ports['d'], inv1_g, tinv3_n1_ports['d'], tinv3_p1_ports['d'] ], pout_id) # connect iclk, iclkb tinv0_gn1 = self.connect_to_tracks(tinv0_n1_ports['g'], ngate_id, min_len_mode=0) tinv0_gn1_idx = self.grid.coord_to_nearest_track( tinv0_gn1.layer_id + 1, tinv0_gn1.lower) tinv0_gn1_tid = TrackID(tinv0_gn1.layer_id + 1, tinv0_gn1_idx) tinv0_gn1 = self.connect_to_tracks(tinv0_gn1, tinv0_gn1_tid) tinv0_gp1 = self.connect_to_tracks(tinv0_p1_ports['g'], pgate_id, min_len_mode=0) tinv0_gp1_idx = self.grid.coord_to_nearest_track( tinv0_gp1.layer_id + 1, tinv0_gp1.upper) tinv0_gp1_tid = TrackID(tinv0_gp1.layer_id + 1, tinv0_gp1_idx) tinv0_gp1 = self.connect_to_tracks(tinv0_gp1, tinv0_gp1_tid) tinv1_gn1 = self.connect_to_tracks(tinv1_n1_ports['g'], ngate_id, min_len_mode=0) tinv1_gn1_idx = self.grid.coord_to_nearest_track( tinv1_gn1.layer_id + 1, tinv1_gn1.middle) tinv1_gn1_tid = TrackID(tinv1_gn1.layer_id + 1, tinv1_gn1_idx) tinv1_gn1 = self.connect_to_tracks(tinv1_gn1, tinv1_gn1_tid) tinv1_gp1 = self.connect_to_tracks(tinv1_p1_ports['g'], pgate_id, min_len_mode=0) tinv1_gp1_idx = self.grid.coord_to_nearest_track( tinv1_gp1.layer_id + 1, tinv1_gp1.upper) tinv1_gp1_tid = TrackID(tinv1_gp1.layer_id + 1, tinv1_gp1_idx) tinv1_gp1 = self.connect_to_tracks(tinv1_gp1, tinv1_gp1_tid) tinv2_gn1 = self.connect_to_tracks(tinv2_n1_ports['g'], ngate_id, min_len_mode=0) tinv2_gn1_idx = self.grid.coord_to_nearest_track( tinv2_gn1.layer_id + 1, tinv2_gn1.middle) tinv2_gn1_tid = TrackID(tinv2_gn1.layer_id + 1, tinv2_gn1_idx) tinv2_gn1 = self.connect_to_tracks(tinv2_gn1, tinv2_gn1_tid) tinv2_gp1 = self.connect_to_tracks(tinv2_p1_ports['g'], pgate_id, min_len_mode=0) tinv2_gp1_idx = self.grid.coord_to_nearest_track( tinv2_gp1.layer_id + 1, tinv2_gp1.upper) tinv2_gp1_tid = TrackID(tinv2_gp1.layer_id + 1, tinv2_gp1_idx) tinv2_gp1 = self.connect_to_tracks(tinv2_gp1, tinv2_gp1_tid) tinv3_gn1 = self.connect_to_tracks(tinv3_n1_ports['g'], ngate_id, min_len_mode=0) tinv3_gn1_idx = self.grid.coord_to_nearest_track( tinv3_gn1.layer_id + 1, tinv3_gn1.middle) tinv3_gn1_tid = TrackID(tinv3_gn1.layer_id + 1, tinv3_gn1_idx) tinv3_gn1 = self.connect_to_tracks(tinv3_gn1, tinv3_gn1_tid) tinv3_gp1 = self.connect_to_tracks(tinv3_p1_ports['g'], pgate_id, min_len_mode=0) tinv3_gp1_idx = self.grid.coord_to_nearest_track( tinv3_gp1.layer_id + 1, tinv3_gp1.upper) tinv3_gp1_tid = TrackID(tinv3_gp1.layer_id + 1, tinv3_gp1_idx + 1) # to avoid short tinv3_gp1 = self.connect_to_tracks(tinv3_gp1, tinv3_gp1_tid) self.connect_to_tracks( [tinv0_gp1, tinv1_gn1, tinv2_gn1, tinv3_gp1, iclk], ck_id) self.connect_to_tracks( [tinv0_gn1, tinv1_gp1, tinv2_gp1, tinv3_gn1, iclkb], ckb_id) # add pins self.add_pin('CLK', clk, show=show_pins) self.add_pin('I', i, show=show_pins) self.add_pin('O', o, show=show_pins) if debug is True: self.add_pin('latch', latch, show=show_pins) self.add_pin('iclk', iclk, show=show_pins) self.add_pin('iclkb', iclkb, show=show_pins) self.add_pin('mem1', mem1, show=show_pins) self.add_pin('mem2', mem2, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.grid.get_size_tuple(m5v_layer, width=self.bound_box.width, height=self.bound_box.height, round_up=True) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nf_inv0=nf_inv0, nf_inv1=nf_inv1, nf_inv2=nf_inv2, nf_inv3=nf_inv3, nf_tinv0_0=nf_tinv0_0, nf_tinv0_1=nf_tinv0_1, nf_tinv1_0=nf_tinv1_0, nf_tinv1_1=nf_tinv1_1, nf_tinv2_0=nf_tinv2_0, nf_tinv2_1=nf_tinv2_1, nf_tinv3_0=nf_tinv3_0, nf_tinv3_1=nf_tinv3_1, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_inv1, nf_inv2, nf_inv3, nf_tinv0_0, nf_tinv0_1, nf_tinv1_0, nf_tinv1_1, nfn_nand0, nfp_nand0, nfn_nand1, nfp_nand1, nfn_nand2, nfp_nand2, nfn_nand3, nfp_nand3, nf_tgate0, nf_tgate1, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, show_pins, power_width_ntr, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # TODO: assumption1 -- all nmos/pmos have same finger number # TODO: assumption2 -- all nmos/pmos finger number are even # get resolution res = self.grid.resolution # make sure all fingers are even number if nf_inv0%2 != 0 or nf_inv1%2 != 0 or nf_inv2%2 != 0 or nf_inv3%2 != 0 or \ nf_tinv0_0%2 != 0 or nf_tinv1_0%2 != 0 or nf_tinv0_1%2 != 0 or nf_tinv1_1%2 != 0 or\ nfn_nand0%2 != 0 or nfp_nand0%2 != 0 or nfn_nand1%2 != 0 or nfp_nand1%2 != 0 or\ nfn_nand2%2 != 0 or nfp_nand2%2 != 0 or nfn_nand3%2 != 0 or nfp_nand3%2 != 0 or\ nf_tgate0%2 != 0 or nf_tgate1%2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side*2 + ndum*17 + nf_inv0 + nf_inv1 + nf_inv2 + nf_inv3 + \ nf_tinv0_0 + nf_tinv0_1 + nf_tinv1_0 + nf_tinv1_1 + \ max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ max(nfn_nand2, nfp_nand2) * 2 + max(nfn_nand3, nfp_nand3) * 2 + \ nf_tgate0 + nf_tgate1 + 2 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr * 3 + g_sp_ntr * 2] pg_tracks = [g_width_ntr * 3 + g_sp_ntr * 2] nds_tracks = [ds_width_ntr * 2 + ds_sp_ntr] pds_tracks = [ds_width_ntr * 2 + ds_sp_ntr] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index ck_id = self.make_track_id('nch', 0, 'g', 1, width=1) ckb_id = self.make_track_id('pch', 0, 'g', 1, width=1) ngate_id = self.make_track_id('nch', 0, 'g', 2, width=1) pgate_id = self.make_track_id('pch', 0, 'g', 2, width=1) nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1) pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) st_id = self.make_track_id('nch', 0, 'g', 0, width=1) rst_id = self.make_track_id('pch', 0, 'g', 0, width=1) # Step1: connect inverter # group transistors # inv2 inv2_n_ports = self.draw_mos_conn('nch', 0, ndum_side, nf_inv2, 1, 1, s_net='VSS', d_net='stb') inv2_p_ports = self.draw_mos_conn('pch', 0, ndum_side, nf_inv2, 1, 1, s_net='VDD', d_net='stb') # inv3 inv3_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum + nf_inv2, nf_inv3, 1, 1, s_net='VSS', d_net='rstb') inv3_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum + nf_inv2, nf_inv3, 1, 1, s_net='VDD', d_net='rstb') # inv0 col_idx = ndum_side + ndum * 2 + nf_inv2 + nf_inv3 inv0_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv0, 1, 1, s_net='VSS', d_net='iclkb') inv0_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv0, 1, 1, s_net='VDD', d_net='iclkb') # inv1 col_idx = ndum_side + ndum * 3 + nf_inv2 + nf_inv3 + nf_inv0 inv1_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv1, 1, 1, s_net='VSS', d_net='iclk') inv1_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv1, 1, 1, s_net='VDD', d_net='iclk') # tinv0 col_idx = ndum_side + ndum * 4 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 tinv0_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv0_0, 1, 1, s_net='VSS', d_net='tinv0_ns') tinv0_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv0_0, 1, 1, s_net='VDD', d_net='tinv0_ps') col_idx = ndum_side + ndum * 5 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + 2 # for drc tinv0_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv0_1, 1, 1, s_net='tinv0_ns', d_net='mem1') tinv0_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv0_1, 1, 1, s_net='tinv0_ps', d_net='mem1') # nand0 col_idx = ndum_side + ndum * 6 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + 2 nand0_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand0, 1, 1, s_net='VSS', d_net='nand0_ns') nand0_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand0, 1, 1, s_net='VDD', d_net='latch') col_idx = ndum_side + ndum * 7 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) + 2 nand0_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand0, 1, 1, s_net='nand0_ns', d_net='latch') nand0_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand0, 1, 1, s_net='VDD', d_net='latch') # nand1 col_idx = ndum_side + ndum * 8 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + 2 nand1_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand1, 1, 1, s_net='VSS', d_net='nand1_ns') nand1_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand1, 1, 1, s_net='VDD', d_net='rstm1') col_idx = ndum_side + ndum * 9 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) + 2 nand1_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand1, 1, 1, s_net='nand1_ns', d_net='rstm1') nand1_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand1, 1, 1, s_net='VDD', d_net='rstm1') # tgate0 col_idx = ndum_side + ndum * 10 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + 2 tgate0_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tgate0, 1, 1, s_net='rstm1', d_net='mem1') tgate0_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tgate0, 1, 1, s_net='rstm1', d_net='mem1') # tinv1 col_idx = ndum_side + ndum * 11 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + 2 tinv1_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv1_0, 1, 1, s_net='VSS', d_net='tinv1_ns') tinv1_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv1_0, 1, 1, s_net='VDD', d_net='tinv1_ps') col_idx = ndum_side + ndum * 12 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + 2 tinv1_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv1_1, 1, 1, s_net='tinv1_ns', d_net='mem2') tinv1_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv1_1, 1, 1, s_net='tinv1_ps', d_net='mem2') # nand2 col_idx = ndum_side + ndum * 13 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + 2 nand2_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand2, 1, 1, s_net='VSS', d_net='nand2_ns') nand2_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand2, 1, 1, s_net='VDD', d_net='O') col_idx = ndum_side + ndum * 14 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) + 2 nand2_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand2, 1, 1, s_net='nand2_ns', d_net='O') nand2_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand2, 1, 1, s_net='VDD', d_net='O') # nand3 col_idx = ndum_side + ndum * 15 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 + 2 nand3_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand3, 1, 1, s_net='VSS', d_net='nand3_ns') nand3_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand3, 1, 1, s_net='VDD', d_net='rstm2') col_idx = ndum_side + ndum * 16 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 +\ max(nfn_nand3, nfp_nand3) + 2 nand3_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn_nand3, 1, 1, s_net='nand3_ns', d_net='rstm2') nand3_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp_nand3, 1, 1, s_net='VDD', d_net='rstm2') # tgate1 col_idx = ndum_side + ndum * 17 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \ nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \ nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 + \ max(nfn_nand3, nfp_nand3) * 2 + 2 tgate1_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tgate1, 1, 1, s_net='rstm2', d_net='mem2') tgate1_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tgate1, 1, 1, s_net='rstm2', d_net='mem2') # connect inv2, inv3 (rst, st buffers) # inv2 inv2_n_warr = self.connect_to_tracks(inv2_n_ports['g'], ngate_id, min_len_mode=0) inv2_p_warr = self.connect_to_tracks(inv2_p_ports['g'], pgate_id, min_len_mode=0) inv2_idx = self.grid.coord_to_nearest_track(inv2_n_warr.layer_id + 1, inv2_n_warr.middle) inv2_tid = TrackID(inv2_n_warr.layer_id + 1, inv2_idx) st = self.connect_to_tracks([inv2_n_warr, inv2_p_warr], inv2_tid) self.connect_to_substrate('ptap', inv2_n_ports['s']) self.connect_to_substrate('ntap', inv2_p_ports['s']) inv2_d_wire = self.connect_to_tracks( [inv2_n_ports['d'], inv2_p_ports['d']], nout_id, min_len_mode=0) stb_idx = self.grid.coord_to_nearest_track(inv2_d_wire.layer_id + 1, inv2_d_wire.lower) stb_tid = TrackID(inv2_d_wire.layer_id + 1, stb_idx) stb = self.connect_to_tracks(inv2_d_wire, stb_tid, min_len_mode=0) # inv3 inv3_n_warr = self.connect_to_tracks(inv3_n_ports['g'], ngate_id, min_len_mode=0) inv3_p_warr = self.connect_to_tracks(inv3_p_ports['g'], pgate_id, min_len_mode=0) inv3_idx = self.grid.coord_to_nearest_track(inv3_n_warr.layer_id + 1, inv3_n_warr.middle) inv3_tid = TrackID(inv3_n_warr.layer_id + 1, inv3_idx) rst = self.connect_to_tracks([inv3_n_warr, inv3_p_warr], inv3_tid) self.connect_to_substrate('ptap', inv3_n_ports['s']) self.connect_to_substrate('ntap', inv3_p_ports['s']) inv3_d_wire = self.connect_to_tracks( [inv3_n_ports['d'], inv3_p_ports['d']], nout_id) rstb_idx = self.grid.coord_to_nearest_track(inv3_d_wire.layer_id + 1, inv3_d_wire.upper) rstb_tid = TrackID(inv3_d_wire.layer_id + 1, rstb_idx + 1) rstb = self.connect_to_tracks(inv3_d_wire, rstb_tid) # connect inv0, inv1 (clock buffer) # inv0 inv0_n_warr = self.connect_to_tracks(inv0_n_ports['g'], ngate_id, min_len_mode=0) inv0_p_warr = self.connect_to_tracks(inv0_p_ports['g'], pgate_id, min_len_mode=0) inv0_idx = self.grid.coord_to_nearest_track(inv0_n_warr.layer_id + 1, inv0_n_warr.middle) inv0_tid = TrackID(inv0_n_warr.layer_id + 1, inv0_idx) clk = self.connect_to_tracks([inv0_n_warr, inv0_p_warr], inv0_tid) self.connect_to_substrate('ptap', inv0_n_ports['s']) self.connect_to_substrate('ntap', inv0_p_ports['s']) # inv1 inv1_n_warr = self.connect_to_tracks(inv1_n_ports['g'], ngate_id, min_len_mode=0) inv1_p_warr = self.connect_to_tracks(inv1_p_ports['g'], pgate_id, min_len_mode=0) inv1_idx = self.grid.coord_to_nearest_track(inv1_n_warr.layer_id + 1, inv1_n_warr.middle) inv1_tid = TrackID(inv1_n_warr.layer_id + 1, inv1_idx) inv1_g_wire = self.connect_to_tracks([inv1_n_warr, inv1_p_warr], inv1_tid) self.connect_to_tracks( [inv0_n_ports['d'], inv0_p_ports['d'], inv1_g_wire], pout_id) iclkb = inv1_g_wire self.connect_to_substrate('ptap', inv1_n_ports['s']) self.connect_to_substrate('ntap', inv1_p_ports['s']) inv1_d_wire = self.connect_to_tracks( [inv1_n_ports['d'], inv1_p_ports['d']], nout_id) iclk_idx = self.grid.coord_to_nearest_track(inv1_d_wire.layer_id + 1, inv1_d_wire.upper) iclk_tid = TrackID(inv1_d_wire.layer_id + 1, iclk_idx + 1) iclk = self.connect_to_tracks(inv1_d_wire, iclk_tid) # tinv0 i_n_warr = self.connect_to_tracks(tinv0_n0_ports['g'], ngate_id, min_len_mode=0) i_p_warr = self.connect_to_tracks(tinv0_p0_ports['g'], pgate_id, min_len_mode=0) i_idx = self.grid.coord_to_nearest_track(i_n_warr.layer_id + 1, i_n_warr.middle) i_tid = TrackID(i_n_warr.layer_id + 1, i_idx) i = self.connect_to_tracks([i_n_warr, i_p_warr], i_tid) self.connect_to_substrate('ptap', tinv0_n0_ports['s']) self.connect_to_substrate('ntap', tinv0_p0_ports['s']) self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']], pdrain_id) # nand0 nand0_gn0_warr = self.connect_to_tracks(nand0_n0_ports['g'], ngate_id, min_len_mode=0) nand0_gp0_warr = self.connect_to_tracks(nand0_p0_ports['g'], pgate_id, min_len_mode=0) nand0_g0_idx = self.grid.coord_to_nearest_track( nand0_gn0_warr.layer_id + 1, nand0_gn0_warr.middle) nand0_g0_tid = TrackID(nand0_gn0_warr.layer_id + 1, nand0_g0_idx) nand0_g0 = self.connect_to_tracks([nand0_gn0_warr, nand0_gp0_warr], nand0_g0_tid) # # connect nand0_g0 # self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], nand0_g0], nout_id) # connect nand_n0 and nand_n1 self.connect_to_tracks([nand0_n0_ports['d'], nand0_n1_ports['s']], ndrain_id) self.connect_to_substrate('ptap', nand0_n0_ports['s']) self.connect_to_substrate('ntap', [nand0_p0_ports['s'], nand0_p1_ports['s']]) # # connect drain to output # self.connect_to_tracks([nand0_p0_ports['d'], nand0_p1_ports['d'], nand0_n1_ports['d']], nout_id) # nand1 nand1_gn0_warr = self.connect_to_tracks(nand1_n0_ports['g'], ngate_id, min_len_mode=0) nand1_gp0_warr = self.connect_to_tracks(nand1_p0_ports['g'], pgate_id, min_len_mode=0) nand1_g0_idx = self.grid.coord_to_nearest_track( nand1_gn0_warr.layer_id + 1, nand1_gn0_warr.middle) nand1_g0_tid = TrackID(nand1_gn0_warr.layer_id + 1, nand1_g0_idx) nand1_g0 = self.connect_to_tracks([nand1_gn0_warr, nand1_gp0_warr], nand1_g0_tid) # connect nand_n0 and nand_n1 self.connect_to_tracks([nand1_n0_ports['d'], nand1_n1_ports['s']], ndrain_id) self.connect_to_substrate('ptap', nand1_n0_ports['s']) self.connect_to_substrate('ntap', [nand1_p0_ports['s'], nand1_p1_ports['s']]) # tgate0 # connect nand1 drain to tgage drain rstm1 = self.connect_to_tracks([ nand1_p0_ports['d'], nand1_p1_ports['d'], nand1_n1_ports['d'], tgate0_n_ports['s'], tgate0_p_ports['s'] ], pdrain_id) # connect tgate0 drain, tinv0_n1/p1 drain and nand mem1 = self.connect_to_tracks([ tgate0_n_ports['d'], tgate0_p_ports['d'], tinv0_n1_ports['d'], tinv0_p1_ports['d'], nand0_g0 ], nout_id) # tinv1 tinv1_ng0_warr = self.connect_to_tracks(tinv1_n0_ports['g'], ngate_id, min_len_mode=0) tinv1_pg0_warr = self.connect_to_tracks(tinv1_p0_ports['g'], pgate_id, min_len_mode=0) tinv1_g0_idx = self.grid.coord_to_nearest_track( tinv1_ng0_warr.layer_id + 1, tinv1_ng0_warr.middle) tinv1_g0_tid = TrackID(tinv1_ng0_warr.layer_id + 1, tinv1_g0_idx) tinv1_g0 = self.connect_to_tracks([tinv1_ng0_warr, tinv1_pg0_warr], tinv1_g0_tid) latch = self.connect_to_tracks([ nand0_n1_ports['d'], nand0_p0_ports['d'], nand0_p1_ports['d'], nand1_g0, tinv1_g0 ], pout_id) self.connect_to_substrate('ptap', tinv1_n0_ports['s']) self.connect_to_substrate('ntap', tinv1_p0_ports['s']) self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']], pdrain_id) # nand2 nand2_gn0_warr = self.connect_to_tracks(nand2_n0_ports['g'], ngate_id, min_len_mode=0) nand2_gp0_warr = self.connect_to_tracks(nand2_p0_ports['g'], pgate_id, min_len_mode=0) nand2_g0_idx = self.grid.coord_to_nearest_track( nand2_gn0_warr.layer_id + 1, nand2_gn0_warr.middle) nand2_g0_tid = TrackID(nand2_gn0_warr.layer_id + 1, nand2_g0_idx) nand2_g0 = self.connect_to_tracks([nand2_gn0_warr, nand2_gp0_warr], nand2_g0_tid) # # connect nand2_g0 # self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], nand2_g0], nout_id) # connect nand_n0 and nand_n1 self.connect_to_tracks([nand2_n0_ports['d'], nand2_n1_ports['s']], ndrain_id) self.connect_to_substrate('ptap', nand2_n0_ports['s']) self.connect_to_substrate('ntap', [nand2_p0_ports['s'], nand2_p1_ports['s']]) # # connect drain to output # self.connect_to_tracks([nand0_p0_ports['d'], nand0_p1_ports['d'], nand0_n1_ports['d']], nout_id) # nand3 nand3_gn0_warr = self.connect_to_tracks(nand3_n0_ports['g'], ngate_id, min_len_mode=0) nand3_gp0_warr = self.connect_to_tracks(nand3_p0_ports['g'], pgate_id, min_len_mode=0) nand3_g0_idx = self.grid.coord_to_nearest_track( nand3_gn0_warr.layer_id + 1, nand3_gn0_warr.middle) nand3_g0_tid = TrackID(nand3_gn0_warr.layer_id + 1, nand3_g0_idx) nand3_g0 = self.connect_to_tracks([nand3_gn0_warr, nand3_gp0_warr], nand3_g0_tid) # connect nand3_n0 and nand3_n1 self.connect_to_tracks([nand3_n0_ports['d'], nand3_n1_ports['s']], ndrain_id) self.connect_to_substrate('ptap', nand3_n0_ports['s']) self.connect_to_substrate('ntap', [nand3_p0_ports['s'], nand3_p1_ports['s']]) # tgate1 # connect nand3 drain to tgate drain rstm2 = self.connect_to_tracks([ nand3_p0_ports['d'], nand3_p1_ports['d'], nand3_n1_ports['d'], tgate1_n_ports['s'], tgate1_p_ports['s'] ], pdrain_id) # connect tgate1 drain, tinv1_n1/p1 drain and nand2 gate mem2 = self.connect_to_tracks([ tgate1_n_ports['d'], tgate1_p_ports['d'], tinv1_n1_ports['d'], tinv1_p1_ports['d'], nand2_g0 ], nout_id) # connect nand2 drain and nand3 gate o = self.connect_to_tracks([ nand2_n1_ports['d'], nand2_p0_ports['d'], nand2_p1_ports['d'], nand3_g0 ], pout_id) # connect stb, rstb nand0_gn1_warr = self.connect_to_tracks(nand0_n1_ports['g'], ngate_id, min_len_mode=0) nand0_gp1_warr = self.connect_to_tracks(nand0_p1_ports['g'], pgate_id, min_len_mode=0) nand0_g1_idx = self.grid.coord_to_nearest_track( nand0_gn1_warr.layer_id + 1, nand0_gn1_warr.middle) nand0_g1_tid = TrackID(nand0_gn1_warr.layer_id + 1, nand0_g1_idx) nand0_g1 = self.connect_to_tracks([nand0_gn1_warr, nand0_gp1_warr], nand0_g1_tid, min_len_mode=0) nand1_gn1_warr = self.connect_to_tracks(nand1_n1_ports['g'], ngate_id, min_len_mode=0) nand1_gp1_warr = self.connect_to_tracks(nand1_p1_ports['g'], pgate_id, min_len_mode=0) nand1_g1_idx = self.grid.coord_to_nearest_track( nand1_gn1_warr.layer_id + 1, nand1_gn1_warr.middle) nand1_g1_tid = TrackID(nand1_gn1_warr.layer_id + 1, nand1_g1_idx) nand1_g1 = self.connect_to_tracks([nand1_gn1_warr, nand1_gp1_warr], nand1_g1_tid, min_len_mode=0) nand2_gn1_warr = self.connect_to_tracks(nand2_n1_ports['g'], ngate_id, min_len_mode=0) nand2_gp1_warr = self.connect_to_tracks(nand2_p1_ports['g'], pgate_id, min_len_mode=0) nand2_g1_idx = self.grid.coord_to_nearest_track( nand2_gn1_warr.layer_id + 1, nand2_gn1_warr.middle) nand2_g1_tid = TrackID(nand2_gn1_warr.layer_id + 1, nand2_g1_idx) nand2_g1 = self.connect_to_tracks([nand2_gn1_warr, nand2_gp1_warr], nand2_g1_tid, min_len_mode=0) nand3_gn1_warr = self.connect_to_tracks(nand3_n1_ports['g'], ngate_id, min_len_mode=0) nand3_gp1_warr = self.connect_to_tracks(nand3_p1_ports['g'], pgate_id, min_len_mode=0) nand3_g1_idx = self.grid.coord_to_nearest_track( nand3_gn1_warr.layer_id + 1, nand3_gn1_warr.middle) nand3_g1_tid = TrackID(nand3_gn1_warr.layer_id + 1, nand3_g1_idx) nand3_g1 = self.connect_to_tracks([nand3_gn1_warr, nand3_gp1_warr], nand3_g1_tid, min_len_mode=0) stb = self.connect_to_tracks([nand0_g1, nand2_g1, stb], st_id) rstb = self.connect_to_tracks([nand1_g1, nand3_g1, rstb], rst_id) # connect iclk, iclkb tinv0_gn1 = self.connect_to_tracks(tinv0_n1_ports['g'], ngate_id, min_len_mode=0) tinv0_gn1_idx = self.grid.coord_to_nearest_track( tinv0_gn1.layer_id + 1, tinv0_gn1.lower) tinv0_gn1_tid = TrackID(tinv0_gn1.layer_id + 1, tinv0_gn1_idx) tinv0_gn1 = self.connect_to_tracks(tinv0_gn1, tinv0_gn1_tid) tinv0_gp1 = self.connect_to_tracks(tinv0_p1_ports['g'], pgate_id, min_len_mode=0) tinv0_gp1_idx = self.grid.coord_to_nearest_track( tinv0_gp1.layer_id + 1, tinv0_gp1.upper) tinv0_gp1_tid = TrackID(tinv0_gp1.layer_id + 1, tinv0_gp1_idx) tinv0_gp1 = self.connect_to_tracks(tinv0_gp1, tinv0_gp1_tid) tinv1_gn1 = self.connect_to_tracks(tinv1_n1_ports['g'], ngate_id, min_len_mode=0) tinv1_gn1_idx = self.grid.coord_to_nearest_track( tinv1_gn1.layer_id + 1, tinv1_gn1.middle) tinv1_gn1_tid = TrackID(tinv1_gn1.layer_id + 1, tinv1_gn1_idx) tinv1_gn1 = self.connect_to_tracks(tinv1_gn1, tinv1_gn1_tid) tinv1_gp1 = self.connect_to_tracks(tinv1_p1_ports['g'], pgate_id, min_len_mode=0) tinv1_gp1_idx = self.grid.coord_to_nearest_track( tinv1_gp1.layer_id + 1, tinv1_gp1.upper) tinv1_gp1_tid = TrackID(tinv1_gp1.layer_id + 1, tinv1_gp1_idx) tinv1_gp1 = self.connect_to_tracks(tinv1_gp1, tinv1_gp1_tid) # tgate0 tgate0_gn = self.connect_to_tracks(tgate0_n_ports['g'], ngate_id, min_len_mode=0) tgate0_gn_idx = self.grid.coord_to_nearest_track( tgate0_gn.layer_id + 1, tgate0_gn.middle) tgate0_gn_tid = TrackID(tgate0_gn.layer_id + 1, tgate0_gn_idx) tgate0_n = self.connect_to_tracks(tgate0_gn, tgate0_gn_tid) tgate0_gp = self.connect_to_tracks(tgate0_p_ports['g'], pgate_id, min_len_mode=0) tgate0_gp_idx = self.grid.coord_to_nearest_track( tgate0_gp.layer_id + 1, tgate0_gp.upper) tgate0_gp_tid = TrackID(tgate0_gp.layer_id + 1, tgate0_gp_idx) tgate0_p = self.connect_to_tracks(tgate0_gp, tgate0_gp_tid) # tgate1 tgate1_gn = self.connect_to_tracks([tgate1_n_ports['g']], ngate_id, min_len_mode=0) tgate1_gn_idx = self.grid.coord_to_nearest_track( tgate1_gn.layer_id + 1, tgate1_gn.middle) tgate1_gn_tid = TrackID(tgate1_gn.layer_id + 1, tgate1_gn_idx) tgate1_n = self.connect_to_tracks(tgate1_gn, tgate1_gn_tid) tgate1_gp = self.connect_to_tracks([tgate1_p_ports['g']], pgate_id, min_len_mode=0) tgate1_gp_idx = self.grid.coord_to_nearest_track( tgate1_gp.layer_id + 1, tgate1_gp.upper) tgate1_gp_tid = TrackID(tgate1_gp.layer_id + 1, tgate1_gp_idx + 1) tgate1_p = self.connect_to_tracks(tgate1_gp, tgate1_gp_tid) self.connect_to_tracks( [tinv0_gp1, tinv1_gn1, tgate0_n, tgate1_p, iclk], ck_id) self.connect_to_tracks( [tinv0_gn1, tinv1_gp1, tgate0_p, tgate1_n, iclkb], ckb_id) # add pins self.add_pin('CLK', clk, show=show_pins) self.add_pin('ST', st, show=show_pins) self.add_pin('RST', rst, show=show_pins) self.add_pin('I', i, show=show_pins) self.add_pin('O', [o, nand3_g0], show=show_pins) if debug is True: # test signals self.add_pin('latch', latch, show=show_pins) self.add_pin('mem1', mem1, show=show_pins) self.add_pin('mem2', mem2, show=show_pins) self.add_pin('rstm1', rstm1, show=show_pins) self.add_pin('rstm2', rstm2, show=show_pins) self.add_pin('iclk', iclk, show=show_pins) self.add_pin('iclkb', iclkb, show=show_pins) self.add_pin('stb', stb, show=show_pins) self.add_pin('rstb', rstb, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.grid.get_size_tuple(m5v_layer, width=self.bound_box.width, height=self.bound_box.height, round_up=True) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nf_inv0=nf_inv0, nf_inv1=nf_inv1, nf_inv2=nf_inv3, nf_inv3=nf_inv3, nf_tinv0_0=nf_tinv0_0, nf_tinv0_1=nf_tinv0_1, nf_tinv1_0=nf_tinv1_0, nf_tinv1_1=nf_tinv1_1, nfn_nand0=nfn_nand0, nfp_nand0=nfp_nand0, nfn_nand1=nfn_nand1, nfp_nand1=nfp_nand1, nfn_nand2=nfn_nand2, nfp_nand2=nfp_nand2, nfn_nand3=nfn_nand3, nfp_nand3=nfp_nand3, nf_tgate0=nf_tgate0, nf_tgate1=nf_tgate1, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ lch = self.params['lch'] wn = self.params['wn'] wp = self.params['wp'] nfn_inv = self.params['nfn_inv'] nfp_inv = self.params['nfp_inv'] nfn_tinv0 = self.params['nfn_tinv0'] nfp_tinv0 = self.params['nfp_tinv0'] nfn_tinv1 = self.params['nfn_tinv1'] nfp_tinv1 = self.params['nfp_tinv1'] ndum = self.params['ndum'] intent = self.params['intent'] ptap_w = self.params['ptap_w'] ntap_w = self.params['ntap_w'] g_width_ntr = self.params['g_width_ntr'] ds_width_ntr = self.params['ds_width_ntr'] show_pins = self.params['show_pins'] # get resolution res = self.grid.resolution # make sure all fingers are even number if nfn_inv%2 != 0 or nfp_inv%2 != 0 or nfn_tinv0%2 != 0 or nfn_tinv1%2 != 0 or\ nfp_tinv0%2 != 0 or nfp_tinv1%2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum * 4 + max(nfn_inv, nfp_inv) + max( nfn_tinv0, nfp_tinv0) + max(nfn_tinv1, nfp_tinv1) # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr] pg_tracks = [g_width_ntr] nds_tracks = [ds_width_ntr * 2] pds_tracks = [ds_width_ntr * 2] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr) pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr) out_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr) # Step1: connect inverter # group transistors inv_n_ports = self.draw_mos_conn('nch', 0, ndum, nfn_inv, 1, 1) inv_p_ports = self.draw_mos_conn('pch', 0, ndum, nfp_inv, 1, 1) # connect gate ng_inv_warr = self.connect_to_tracks(inv_n_ports['g'], ngate_id) pg_inv_warr = self.connect_to_tracks(inv_p_ports['g'], pgate_id) # connect gate vertically vgate_idx = self.grid.coord_to_nearest_track(m5v_layer, ng_inv_warr.lower) vgate_tid = TrackID(m5v_layer, vgate_idx) inv_in_warr = self.connect_to_tracks([ng_inv_warr, pg_inv_warr], vgate_tid) # connect drain inv_d_warr = self.connect_to_tracks( [inv_n_ports['d'], inv_p_ports['d']], out_id) # connect gate self.connect_to_substrate('ptap', inv_n_ports['s']) self.connect_to_substrate('ntap', inv_p_ports['s']) # Step2: connect tri-inverter nf_inv = max(nfn_inv, nfp_inv) nf_tinv0 = max(nfn_tinv0, nfp_tinv0) # group transistors tinv0_n_ports = self.draw_mos_conn('nch', 0, nf_inv + 2 * ndum, nfn_tinv0, 1, 1) tinv0_p_ports = self.draw_mos_conn('pch', 0, nf_inv + 2 * ndum, nfp_tinv0, 1, 1) tinv1_n_ports = self.draw_mos_conn('nch', 0, nf_tinv0 + nf_inv + 3 * ndum, nfn_tinv1, 1, 1) tinv1_p_ports = self.draw_mos_conn('pch', 0, nf_tinv0 + nf_inv + 3 * ndum, nfp_tinv1, 1, 1) # connect top/bottom MOSs # connect gate ng_tinv0_warr = self.connect_to_tracks(tinv0_n_ports['g'], ngate_id) pg_tinv0_warr = self.connect_to_tracks(tinv0_p_ports['g'], pgate_id) # connect gate vertically vgate_idx = self.grid.coord_to_nearest_track(m5v_layer, ng_tinv0_warr.lower) vgate_tid = TrackID(m5v_layer, vgate_idx) # also connect inverter drain tinv0_g_warr = self.connect_to_tracks( [inv_d_warr, ng_tinv0_warr, pg_tinv0_warr], vgate_tid) # connect middle MOSs ng_tinv1_warr = self.connect_to_tracks(tinv1_n_ports['g'], ngate_id) pg_tinv1_warr = self.connect_to_tracks(tinv1_p_ports['g'], pgate_id) # connect source ns_tinv0_warr = self.connect_to_tracks( [tinv0_n_ports['d'], tinv1_n_ports['s']], ndrain_id) ps_tinv0_warr = self.connect_to_tracks( [tinv0_p_ports['d'], tinv1_p_ports['s']], pdrain_id) # connect drain tinv_out_warr = self.connect_to_tracks( [tinv1_n_ports['d'], tinv1_p_ports['d']], out_id) # connect source self.connect_to_substrate('ptap', tinv0_n_ports['s']) self.connect_to_substrate('ntap', tinv0_p_ports['s']) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy() # add pins self.add_pin('clk_i', inv_in_warr) self.add_pin('clk_o', tinv_out_warr) self.add_pin('ctrl', ng_tinv1_warr) self.add_pin('ctrl_b', pg_tinv1_warr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.set_size_from_array_box(m5v_layer) # get schematic parameters dum_info = self.get_sch_dummy_info() dum_nmos = dum_info[0][1] dum_pmos = dum_info[1][1] print(dum_info) self._sch_params = dict( lch=self.params['lch'], wn=self.params['wn'], wp=self.params['wp'], nf_inv=self.params['nfn_inv'], nfp_inv=self.params['nfp_inv'], nfn_tinv0=self.params['nfn_tinv0'], nfp_tinv0=self.params['nfp_tinv0'], nfn_tinv1=self.params['nfn_tinv1'], nfp_tinv1=self.params['nfp_tinv1'], intent=self.params['intent'], dum_n0=dum_nmos - 2, dum_n1=2, dum_p0=dum_pmos - 2, dum_p1=2, )
def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_tinv_0, nf_tinv_1, nf_inv2, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, g_space, ds_space, show_pins, power_width_ntr, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # TODO: assumption1 -- all nmos/pmos have same finger number # TODO: assumption2 -- all nmos/pmos finger number are even # get resolution res = self.grid.resolution # make sure all fingers are even number if nf_inv0 % 2 != 0 or nf_tinv_0 % 2 != 0 or nf_tinv_1 % 2 != 0 or nf_inv2 % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side * 2 + ndum * 6 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 * 2 + nf_inv2 + 2 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr * 2 + g_space] pg_tracks = [g_width_ntr * 2 + g_space] nds_tracks = [ds_width_ntr * 2 + ds_space] pds_tracks = [ds_width_ntr * 2 + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index seli_id = self.make_track_id('nch', 0, 'g', 0, width=1) selib_id = self.make_track_id('pch', 0, 'g', 0, width=1) ngate_id = self.make_track_id('nch', 0, 'g', 1, width=1) pgate_id = self.make_track_id('pch', 0, 'g', 1, width=1) nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1) pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) # Step1: connect inverter # group transistors # inv0 inv0_n_ports = self.draw_mos_conn('nch', 0, ndum_side, nf_inv0, 1, 1, s_net='VSS', d_net='sel_ib') inv0_p_ports = self.draw_mos_conn('pch', 0, ndum_side, nf_inv0, 1, 1, s_net='VDD', d_net='sel_ib') # inv1 inv1_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum + nf_inv0, nf_inv0, 1, 1, s_net='VSS', d_net='sel_i') inv1_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum + nf_inv0, nf_inv0, 1, 1, s_net='VDD', d_net='sel_i') # xor logic tinv0_n0_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 2 + nf_inv0 * 2, nf_tinv_0, 1, 1, s_net='VSS', d_net='tinv0_ns') tinv0_p0_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 2 + nf_inv0 * 2, nf_tinv_0, 1, 1, s_net='VDD', d_net='tinv0_ps') tinv0_n1_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 3 + nf_inv0 * 2 + nf_tinv_0, nf_tinv_1, 1, 1, s_net='tinv0_ns', d_net='mux_b') tinv0_p1_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 3 + nf_inv0 * 2 + nf_tinv_0, nf_tinv_1, 1, 1, s_net='tinv0_ps', d_net='mxu_b') col_idx = ndum_side + ndum * 4 + nf_inv0 * 2 + nf_tinv_0 + nf_tinv_1 tinv1_n0_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv_0, 1, 1, s_net='VSS', d_net='tinv1_ns') tinv1_p0_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv_1, 1, 1, s_net='VDD', d_net='tinv1_ps') col_idx = ndum_side + ndum * 5 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 + 2 # 1 to pass drc tinv1_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nf_tinv_1, 1, 1, s_net='tinv1_ns', d_net='mux_b') tinv1_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nf_tinv_1, 1, 1, s_net='tinv1_ps', d_net='mux_b') col_idx = ndum_side + ndum * 6 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 * 2 + 2 inv2_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv2, 1, 1, s_net='VSS', d_net='o') inv2_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv2, 1, 1, s_net='VDD', d_net='o') # connect inv0, inv1 (buffers) # inv0 inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'], ngate_id, min_len_mode=0) inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'], pgate_id, min_len_mode=0) inv0_g_idx = self.grid.coord_to_nearest_track( inv0_gn_warr.layer_id + 1, inv0_gn_warr.lower) inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx) sel = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr], inv0_g_tid) # inv0 drain sel_ib = self.connect_to_tracks([inv0_n_ports['d'], inv0_p_ports['d']], nout_id) # inv0 source self.connect_to_substrate('ptap', inv0_n_ports['s']) self.connect_to_substrate('ntap', inv0_p_ports['s']) # inv1 inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'], ngate_id, min_len_mode=0) inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'], pgate_id, min_len_mode=0) inv1_g_idx = self.grid.coord_to_nearest_track( inv1_gn_warr.layer_id + 1, inv1_gn_warr.middle) inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx) # inv0 drain, inv1 gate sel_ib = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr, sel_ib], inv1_g_tid) # inv1 source self.connect_to_substrate('ptap', inv1_n_ports['s']) self.connect_to_substrate('ntap', inv1_p_ports['s']) # inv1 drain sel_i = self.connect_to_tracks([inv1_n_ports['d'], inv1_p_ports['d']], pout_id, min_len_mode=0) sel_i_idx = self.grid.coord_to_nearest_track(sel_i.layer_id + 1, sel_i.upper) sel_i_tid = TrackID(sel_i.layer_id + 1, sel_i_idx + 1) sel_i = self.connect_to_tracks(sel_i, sel_i_tid) # tinv0 MOSs # tinv0_0 gate tinv0_gn0_warr = self.connect_to_tracks(tinv0_n0_ports['g'], ngate_id, min_len_mode=0) tinv0_gp0_warr = self.connect_to_tracks(tinv0_p0_ports['g'], pgate_id, min_len_mode=0) tinv0_g0_idx = self.grid.coord_to_nearest_track( tinv0_gn0_warr.layer_id + 1, tinv0_gn0_warr.middle) tinv0_g0_tid = TrackID(tinv0_gn0_warr.layer_id + 1, tinv0_g0_idx) i0 = self.connect_to_tracks([tinv0_gn0_warr, tinv0_gp0_warr], tinv0_g0_tid) # tinv0_1 NMOS gate tinv0_gn1_warr = self.connect_to_tracks(tinv0_n1_ports['g'], ngate_id, min_len_mode=0) tinv0_gn1_idx = self.grid.coord_to_nearest_track( tinv0_gn1_warr.layer_id + 1, tinv0_gn1_warr.middle) tinv0_gn1_tid = TrackID(tinv0_gn1_warr.layer_id + 1, tinv0_gn1_idx) tinv0_gn1 = self.connect_to_tracks(tinv0_gn1_warr, tinv0_gn1_tid) # tinv0_1 PMOS gate tinv0_gp1_warr = self.connect_to_tracks(tinv0_p1_ports['g'], pgate_id, min_len_mode=0) tinv0_gp1_idx = self.grid.coord_to_nearest_track( tinv0_gp1_warr.layer_id + 1, tinv0_gp1_warr.upper) tinv0_gp1_tid = TrackID(tinv0_gp1_warr.layer_id + 1, tinv0_gp1_idx) tinv0_gp1 = self.connect_to_tracks(tinv0_gp1_warr, tinv0_gp1_tid) # tinv0_0 source self.connect_to_substrate('ptap', tinv0_n0_ports['s']) self.connect_to_substrate('ntap', tinv0_p0_ports['s']) # tinv0_0 drain and tinv0_1 source self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']], pdrain_id) # tinv0 output tinv0_d = self.connect_to_tracks( [tinv0_n1_ports['d'], tinv0_p1_ports['d']], nout_id) # tinv1 MOSs tinv1_gn0_warr = self.connect_to_tracks(tinv1_n0_ports['g'], ngate_id, min_len_mode=0) tinv1_gp0_warr = self.connect_to_tracks(tinv1_p0_ports['g'], pgate_id, min_len_mode=0) tinv1_g0_idx = self.grid.coord_to_nearest_track( tinv1_gn0_warr.layer_id + 1, tinv1_gn0_warr.middle) tinv1_g0_tid = TrackID(tinv1_gn0_warr.layer_id + 1, tinv1_g0_idx) i1 = self.connect_to_tracks([tinv1_gn0_warr, tinv1_gp0_warr], tinv1_g0_tid) # tinv1_1 NMOS gate tinv1_gn1_warr = self.connect_to_tracks(tinv1_n1_ports['g'], ngate_id, min_len_mode=0) tinv1_gn1_idx = self.grid.coord_to_nearest_track( tinv1_gn1_warr.layer_id + 1, tinv1_gn1_warr.lower) tinv1_gn1_tid = TrackID(tinv1_gn1_warr.layer_id + 1, tinv1_gn1_idx) tinv1_gn1 = self.connect_to_tracks(tinv1_gn1_warr, tinv1_gn1_tid) # tinv1_1 PMOS gate tinv1_gp1_warr = self.connect_to_tracks(tinv1_p1_ports['g'], pgate_id, min_len_mode=0) tinv1_gp1_idx = self.grid.coord_to_nearest_track( tinv1_gp1_warr.layer_id + 1, tinv1_gp1_warr.upper) tinv1_gp1_tid = TrackID(tinv1_gp1_warr.layer_id + 1, tinv1_gp1_idx) tinv1_gp1 = self.connect_to_tracks(tinv1_gp1_warr, tinv1_gp1_tid) # tinv1_0 source self.connect_to_substrate('ptap', tinv1_n0_ports['s']) self.connect_to_substrate('ntap', tinv1_p0_ports['s']) # tinv1_0 drain and tinv1_1 source self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']], ndrain_id) self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']], pdrain_id) # tinv1 output tinv1_d = self.connect_to_tracks( [tinv1_n1_ports['d'], tinv1_p1_ports['d']], nout_id) # inv2 inv2_gn_warr = self.connect_to_tracks(inv2_n_ports['g'], ngate_id, min_len_mode=0) inv2_gp_warr = self.connect_to_tracks(inv2_p_ports['g'], pgate_id, min_len_mode=0) inv2_g_idx = self.grid.coord_to_nearest_track( inv2_gn_warr.layer_id + 1, inv2_gn_warr.middle) inv2_g_tid = TrackID(inv2_gn_warr.layer_id + 1, inv2_g_idx) mux_b = self.connect_to_tracks( [inv2_gn_warr, inv2_gp_warr, tinv0_d, tinv1_d], inv2_g_tid) # inv2 source self.connect_to_substrate('ptap', inv2_n_ports['s']) self.connect_to_substrate('ntap', inv2_p_ports['s']) # inv2 drain o = self.connect_to_tracks([inv2_n_ports['d'], inv2_p_ports['d']], pout_id, min_len_mode=1) # connect mux control sel_i = self.connect_to_tracks([sel_i, tinv0_gp1, tinv1_gn1], selib_id) sel_ib = self.connect_to_tracks([sel_ib, tinv0_gn1, tinv1_gp1], seli_id) # # get upper metal index # self._upper_idx = seli_id.base_index # add pins self.add_pin('i0', i0, show=show_pins) self.add_pin('i1', i1, show=show_pins) self.add_pin('sel', sel, show=show_pins) self.add_pin('o', o, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.grid.get_size_tuple(m5v_layer, width=self.bound_box.width, height=self.bound_box.height, round_up=True) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nf_inv0=nf_inv0, nf_tinv_0=nf_tinv_0, nf_tinv_1=nf_tinv_1, nf_inv2=nf_inv2, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, lch, wn, wp, nf_inv, nf_xnor, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, g_space, ds_space, show_pins, power_width_ntr, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # TODO: assumption1 -- all nmos/pmos have same finger number # TODO: assumption2 -- all nmos/pmos finger number are even # get resolution res = self.grid.resolution # make sure all fingers are even number if nf_inv % 2 != 0 or nf_xnor % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side * 2 + ndum * 5 + nf_inv * 2 + nf_xnor * 4 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr * 3 + g_sp_ntr + g_space] pg_tracks = [g_width_ntr * 3 + g_sp_ntr + g_space] nds_tracks = [ds_width_ntr * 2 + ds_space] pds_tracks = [ds_width_ntr * 2 + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # get gate and drain index a_id = self.make_track_id('nch', 0, 'g', 0, width=1) ab_id = self.make_track_id('nch', 0, 'g', 1, width=1) b_id = self.make_track_id('pch', 0, 'g', 0, width=1) bb_id = self.make_track_id('pch', 0, 'g', 1, width=1) ngate_id = self.make_track_id('nch', 0, 'g', 2, width=1) pgate_id = self.make_track_id('pch', 0, 'g', 2, width=1) nout_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pout_id = self.make_track_id('pch', 0, 'ds', 0, width=1) out_id = self.make_track_id('nch', 0, 'ds', 1, width=1) # Step1: connect inverter # group transistors # inv0 inv0_n_ports = self.draw_mos_conn('nch', 0, ndum_side, nf_inv, 1, 1, s_net='VSS', d_net='a_b') inv0_p_ports = self.draw_mos_conn('pch', 0, ndum_side, nf_inv, 1, 1, s_net='VDD', d_net='a_b') # inv1 inv1_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum + nf_inv, nf_inv, 1, 1, s_net='VSS', d_net='b_b') inv1_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum + nf_inv, nf_inv, 1, 1, s_net='VDD', d_net='b_b') # xnor logic xnor0_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 2 + nf_inv * 2, nf_xnor, 1, 1, s_net='VSS', d_net='ns0') xnor0_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 2 + nf_inv * 2, nf_xnor, 1, 1, s_net='VDD', d_net='ps0') xnor1_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 3 + nf_inv * 2 + nf_xnor, nf_xnor, 1, 1, s_net='ns0', d_net='o') xnor1_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 3 + nf_inv * 2 + nf_xnor, nf_xnor, 1, 1, s_net='ps0', d_net='o') xnor2_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 4 + nf_inv * 2 + nf_xnor * 2, nf_xnor, 1, 1, s_net='VSS', d_net='ns1') xnor2_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 4 + nf_inv * 2 + nf_xnor * 2, nf_xnor, 1, 1, s_net='VDD', d_net='ps1') xnor3_n_ports = self.draw_mos_conn('nch', 0, ndum_side + ndum * 5 + nf_inv * 2 + nf_xnor * 3, nf_xnor, 1, 1, s_net='ns1', d_net='o') xnor3_p_ports = self.draw_mos_conn('pch', 0, ndum_side + ndum * 5 + nf_inv * 2 + nf_xnor * 3, nf_xnor, 1, 1, s_net='ps1', d_net='o') # connect inv2, inv3 (clock buffers) # inv0 inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'], ngate_id, min_len_mode=0) inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'], pgate_id, min_len_mode=0) inv0_g_idx = self.grid.coord_to_nearest_track( inv0_gn_warr.layer_id + 1, inv0_gn_warr.lower) inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx) a = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr], inv0_g_tid) inv0_dn_warr = self.connect_to_tracks(inv0_n_ports['d'], nout_id, min_len_mode=0) inv0_dp_warr = self.connect_to_tracks(inv0_p_ports['d'], pout_id, min_len_mode=0) inv0_d_idx = self.grid.coord_to_nearest_track( inv0_dn_warr.layer_id + 1, inv0_dn_warr.upper) inv0_d_tid = TrackID(inv0_dn_warr.layer_id + 1, inv0_d_idx) a_b = self.connect_to_tracks([inv0_dn_warr, inv0_dp_warr], inv0_d_tid) self.connect_to_substrate('ptap', inv0_n_ports['s']) self.connect_to_substrate('ntap', inv0_p_ports['s']) # inv1 inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'], ngate_id, min_len_mode=0) inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'], pgate_id, min_len_mode=0) inv1_g_idx = self.grid.coord_to_nearest_track( inv1_gn_warr.layer_id + 1, inv1_gn_warr.lower) inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx) b = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr], inv1_g_tid) inv1_dn_warr = self.connect_to_tracks(inv1_n_ports['d'], nout_id, min_len_mode=0) inv1_dp_warr = self.connect_to_tracks(inv1_p_ports['d'], pout_id, min_len_mode=0) inv1_d_idx = self.grid.coord_to_nearest_track( inv1_dn_warr.layer_id + 1, inv1_dn_warr.upper) inv1_d_tid = TrackID(inv1_dn_warr.layer_id + 1, inv1_d_idx) b_b = self.connect_to_tracks([inv1_dn_warr, inv1_dp_warr], inv1_d_tid) self.connect_to_substrate('ptap', inv1_n_ports['s']) self.connect_to_substrate('ntap', inv1_p_ports['s']) # xnor MOSs xnor0_gn_warr = self.connect_to_tracks(xnor0_n_ports['g'], ngate_id, min_len_mode=0) xnor0_gn_idx = self.grid.coord_to_nearest_track( xnor0_gn_warr.layer_id + 1, xnor0_gn_warr.lower) xnor0_gn_tid = TrackID(xnor0_gn_warr.layer_id + 1, xnor0_gn_idx) xnor0_n = self.connect_to_tracks(xnor0_gn_warr, xnor0_gn_tid) xnor0_gp_warr = self.connect_to_tracks(xnor0_p_ports['g'], pgate_id, min_len_mode=0) xnor0_gp_idx = self.grid.coord_to_nearest_track( xnor0_gp_warr.layer_id + 1, xnor0_gp_warr.upper) xnor0_gp_tid = TrackID(xnor0_gp_warr.layer_id + 1, xnor0_gp_idx) xnor0_p = self.connect_to_tracks(xnor0_gp_warr, xnor0_gp_tid) xnor1_gn_warr = self.connect_to_tracks(xnor1_n_ports['g'], ngate_id, min_len_mode=0) xnor1_gn_idx = self.grid.coord_to_nearest_track( xnor1_gn_warr.layer_id + 1, xnor1_gn_warr.lower) xnor1_gn_tid = TrackID(xnor1_gn_warr.layer_id + 1, xnor1_gn_idx) xnor1_n = self.connect_to_tracks(xnor1_gn_warr, xnor1_gn_tid) xnor1_gp_warr = self.connect_to_tracks(xnor1_p_ports['g'], pgate_id, min_len_mode=0) xnor1_gp_idx = self.grid.coord_to_nearest_track( xnor1_gp_warr.layer_id + 1, xnor1_gp_warr.upper) xnor1_gp_tid = TrackID(xnor1_gp_warr.layer_id + 1, xnor1_gp_idx) xnor1_p = self.connect_to_tracks(xnor1_gp_warr, xnor1_gp_tid) xnor2_gn_warr = self.connect_to_tracks(xnor2_n_ports['g'], ngate_id, min_len_mode=0) xnor2_gn_idx = self.grid.coord_to_nearest_track( xnor2_gn_warr.layer_id + 1, xnor2_gn_warr.lower) xnor2_gn_tid = TrackID(xnor2_gn_warr.layer_id + 1, xnor2_gn_idx) xnor2_n = self.connect_to_tracks(xnor2_gn_warr, xnor2_gn_tid) xnor2_gp_warr = self.connect_to_tracks(xnor2_p_ports['g'], pgate_id, min_len_mode=0) xnor2_gp_idx = self.grid.coord_to_nearest_track( xnor2_gp_warr.layer_id + 1, xnor2_gp_warr.upper) xnor2_gp_tid = TrackID(xnor2_gp_warr.layer_id + 1, xnor2_gp_idx) xnor2_p = self.connect_to_tracks(xnor2_gp_warr, xnor2_gp_tid) xnor3_gn_warr = self.connect_to_tracks(xnor3_n_ports['g'], ngate_id, min_len_mode=0) xnor3_gn_idx = self.grid.coord_to_nearest_track( xnor3_gn_warr.layer_id + 1, xnor3_gn_warr.lower) xnor3_gn_tid = TrackID(xnor3_gn_warr.layer_id + 1, xnor3_gn_idx) xnor3_n = self.connect_to_tracks(xnor3_gn_warr, xnor3_gn_tid) xnor3_gp_warr = self.connect_to_tracks(xnor3_p_ports['g'], pgate_id, min_len_mode=0) xnor3_gp_idx = self.grid.coord_to_nearest_track( xnor3_gp_warr.layer_id + 1, xnor3_gp_warr.upper) xnor3_gp_tid = TrackID(xnor3_gp_warr.layer_id + 1, xnor3_gp_idx) xnor3_p = self.connect_to_tracks(xnor3_gp_warr, xnor3_gp_tid) # connect a, a_b, b, b_b self.connect_to_tracks([a, xnor0_p, xnor2_n], a_id) self.connect_to_tracks([a_b, xnor1_n, xnor2_p], ab_id) self.connect_to_tracks([b, xnor1_p, xnor0_n], b_id) self.connect_to_tracks([b_b, xnor3_p, xnor3_n], bb_id) self.connect_to_tracks([xnor0_n_ports['d'], xnor1_n_ports['s']], nout_id) self.connect_to_tracks([xnor0_p_ports['d'], xnor1_p_ports['s']], pout_id) self.connect_to_tracks([xnor2_n_ports['d'], xnor3_n_ports['s']], nout_id) self.connect_to_tracks([xnor2_p_ports['d'], xnor3_p_ports['s']], pout_id) o = self.connect_to_tracks([ xnor1_n_ports['d'], xnor1_p_ports['d'], xnor3_n_ports['d'], xnor3_p_ports['d'] ], out_id) self.connect_to_substrate('ptap', [xnor0_n_ports['s'], xnor2_n_ports['s']]) self.connect_to_substrate('ntap', [xnor0_p_ports['s'], xnor2_p_ports['s']]) # add pins self.add_pin('A', a, show=show_pins) self.add_pin('B', b, show=show_pins) self.add_pin('O', o, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.grid.get_size_tuple(m5v_layer, width=self.bound_box.width, height=self.bound_box.height, round_up=True) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nf_inv=nf_inv, nf_xnor=nf_xnor, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, cbuf_params, clk_params): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # get resolution res = self.grid.resolution # get parameters lch = cbuf_params['lch'] wn = cbuf_params['w'] wp = cbuf_params['nfn'] intent = cbuf_params['intent'] ptap_w = cbuf_params['ptap_w'] ntap_w = cbuf_params['ntap_w'] g_width_ntr = cbuf_params['g_width_ntr'] ds_width_ntr = cbuf_params['ds_width_ntr'] # ndum # show_pins # buffer fingers nfn_inv0_buf = cbuf_params['nfn_inv0'] nfn_inv1_buf = cbuf_params['nfn_inv1'] nfp_inv0_buf = cbuf_params['nfp_inv0'] nfp_inv1_buf = cbuf_params['nfp_inv1'] # clk_cell fingers nfn_inv_clk = clk_params['nfn_inv'] nfp_inv_clk = clk_params['nfp_inv'] nfn_tinv0_clk = clk_params['nfn_tinv0'] nfn_tinv1_clk = clk_params['nfn_tinv1'] nfp_tinv0_clk = clk_params['nfp_tinv0'] nfp_tinv1_clk = clk_params['nfp_tinv1'] # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = round(self.find_fg_tot(res, lch, width) / 4) * 4 print(fg_tot) # some constant wm5_unit = 16 # check nfn if nfn % 4 != 0: raise ValueError( "To guarantee even finger number, need 'nfn' being divisible by 4!" ) nfn_cal = int( nfn / 2) # divide finger number by 2, as we will have even/odd rows # calculate row number and fingers per row fg_eff = int((fg_tot - ndum_min * 2 - ndum_cen * 2) / 2) # max effective finger numbers in a row row = math.ceil(nfn_cal / fg_eff) # row number avg = math.ceil(nfn_cal / row) # avg number per row if avg % 2 != 0: avg += 1 rem = nfn_cal - (row - 1) * avg # finger number in last row ndum1 = int((fg_tot - avg * 2 - ndum_cen * 2) / 2) # dummy finger number except last row ndum2 = int((fg_tot - rem * 2 - ndum_cen * 2) / 2) # dummy finger number for last row # draw transistor rows nw_list = [w, w] * row pw_list = [] nth_list = [intent, intent] * row pth_list = [] num_track_sep = 1 ng_tracks = [g_width_ntr + g_sp_ntr, 0] * row # ng_tracks = [g_width_ntr, 0] * row pg_tracks = [] # need have some gap for drain/source connection # also we try to share tracks for different row to make area smaller if row == 1: nds_tracks = [ ds_width_ntr * 2 + ds_sp_ntr, ds_width_ntr * 2 + ds_sp_ntr ] elif row == 2: nds_tracks = [ ds_width_ntr * 2 + ds_sp_ntr, ds_width_ntr, ds_width_ntr, ds_width_ntr * 2 + ds_sp_ntr ] else: nds_tracks = [ds_width_ntr*2 + ds_sp_ntr, ds_width_ntr+ds_sp_ntr] + \ [ds_width_ntr, ds_width_ntr+ds_sp_ntr] * (row-2) + \ [ds_width_ntr, ds_width_ntr*2 + ds_sp_ntr] pds_tracks = [] n_orientation = ['MX', 'R0'] * row self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, num_track_sep, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=[], ) # initial some list for metals gleft_warr = [] gright_warr = [] deven_warr = [] dodd_warr = [] seven_warr = [] sodd_warr = [] # vertical M5 width wm5 = math.ceil(min(avg, rem) / wm5_unit) for i in range(row): # get gate track ID gate_id = self.make_track_id('nch', 2 * i, 'g', 0, width=g_width_ntr) # get output track ID if i == 0: if row == 1: deven_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr) seven_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr) dodd_id = self.make_track_id('nch', 1, 'ds', 0, width=ds_width_ntr) sodd_id = self.make_track_id('nch', 1, 'ds', 1, width=ds_width_ntr) else: deven_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr) seven_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr) dodd_id = self.make_track_id('nch', 1, 'ds', 0, width=ds_width_ntr) sodd_id = self.make_track_id('nch', 2, 'ds', 0, width=ds_width_ntr) elif i == row - 1: deven_id = self.make_track_id('nch', 2 * i - 1, 'ds', 0, width=ds_width_ntr) seven_id = self.make_track_id('nch', 2 * i, 'ds', 0, width=ds_width_ntr) dodd_id = self.make_track_id('nch', 2 * i + 1, 'ds', 0, width=ds_width_ntr) sodd_id = self.make_track_id('nch', 2 * i + 1, 'ds', 1, width=ds_width_ntr) else: deven_id = self.make_track_id('nch', 2 * i - 1, 'ds', 0, width=ds_width_ntr) seven_id = self.make_track_id('nch', 2 * i, 'ds', 0, width=ds_width_ntr) dodd_id = self.make_track_id('nch', 2 * i + 1, 'ds', 0, width=ds_width_ntr) sodd_id = self.make_track_id('nch', 2 * i + 2, 'ds', 0, width=ds_width_ntr) if i == row - 1: # get ports leven_ports = self.draw_mos_conn('nch', 2 * i, ndum2, rem, 1, 1) reven_ports = self.draw_mos_conn('nch', 2 * i, ndum2 + rem + ndum_cen * 2, rem, 1, 1) lodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum2, rem, 1, 1) rodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum2 + rem + ndum_cen * 2, rem, 1, 1) else: # get ports leven_ports = self.draw_mos_conn('nch', 2 * i, ndum1, avg, 1, 1) reven_ports = self.draw_mos_conn('nch', 2 * i, ndum1 + avg + ndum_cen * 2, avg, 1, 1) lodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum1, avg, 1, 1) rodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum1 + avg + ndum_cen * 2, avg, 1, 1) # connect gates on both side gright_warr.append( self.connect_to_tracks([reven_ports['g']] + [rodd_ports['g']], gate_id)) gleft_warr.append( self.connect_to_tracks([leven_ports['g']] + [lodd_ports['g']], gate_id)) # connect drain/source deven_warr.append( self.connect_to_tracks([leven_ports['d'], reven_ports['d']], deven_id)) seven_warr.append( self.connect_to_tracks([leven_ports['s'], reven_ports['s']], seven_id)) dodd_warr.append( self.connect_to_tracks([lodd_ports['d'], rodd_ports['d']], dodd_id)) sodd_warr.append( self.connect_to_tracks([lodd_ports['s'], rodd_ports['s']], sodd_id)) # connect all vctrl vertically vctrl_idx = self.grid.coord_to_nearest_track(m5v_layer, self.bound_box.xc, half_track=True) vctrl_tid = TrackID(m5v_layer, vctrl_idx, width=1) # vctrl = self.connect_to_tracks(seven_warr, vctrl_tid) vctrl = self.connect_to_tracks( deven_warr + seven_warr + dodd_warr + sodd_warr, vctrl_tid) self.add_pin(self.get_pin_name('VCTRL'), vctrl, show=show_pins) # connect all output vertically for left side out_idx_left = self.grid.coord_to_nearest_track(m5v_layer, gleft_warr[-1].middle, half_track=True) out_tid_left = TrackID(m5v_layer, out_idx_left, width=wm5) out_left = self.connect_to_tracks(gleft_warr, out_tid_left) self.add_pin(self.get_pin_name('OUTP'), out_left, show=show_pins) # right side out_idx_right = self.grid.coord_to_nearest_track( m5v_layer, gright_warr[-1].middle, half_track=True) out_tid_right = TrackID(m5v_layer, out_idx_right, width=wm5) out_right = self.connect_to_tracks(gright_warr, out_tid_right) self.add_pin(self.get_pin_name('OUTN'), out_right, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size of block in resolution blk_w = self.bound_box.width_unit blk_h = self.bound_box.top_unit # blk_w, blk_h = self.grid.get_size_dimension(self.size, unit_mode=True) # get pitch of top 2 layers w_pitch, h_pitch = self.grid.get_size_pitch(m5v_layer, unit_mode=True) # print([w_pitch, h_pitch]) # get size rounded to top 2 layers pitch blk_w_new = -(-blk_w // w_pitch) blk_h_new = -(-blk_h // h_pitch) # get size and array box self.size = m5v_layer, blk_w_new, blk_h_new self.array_box = BBox(0, 0, blk_w, blk_h, res, unit_mode=True) # get fg_tot self._fg_tot = fg_tot self._sch_params = dict( lch=self.params['lch'], w=self.params['w'], nfn=self.params['nfn'], fg_wid=self._fg_tot, ndum_min=self.params['ndum_min'], ndum_cen=self.params['ndum_cen'], intent=self.params['intent'], )
def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, g_space, ds_space, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum_side, show_pins, power_width_ntr, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # get resolution res = self.grid.resolution # make sure all fingers are even number if nfn % 2 != 0 or nfp % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) fg_tot = ndum_side * 2 + max(nfn, nfp) # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr + g_sp_ntr + g_space] pg_tracks = [g_width_ntr + g_sp_ntr + g_space] nds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space] pds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, top_layer=m5v_layer) # get gate and drain index ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1) pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1) nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1) pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) # nor inv_n_ports = self.draw_mos_conn('nch', 0, ndum_side, nfn, 1, 1, s_net='VSS', d_net='VSS') inv_p_ports = self.draw_mos_conn('pch', 0, ndum_side, nfp, 1, 1, s_net='VDD', d_net='VSS') # connect inv inv_gn_warr = self.connect_to_tracks(inv_n_ports['g'], ngate_id, min_len_mode=0) inv_gp_warr = self.connect_to_tracks(inv_p_ports['g'], pgate_id, min_len_mode=0) inv_g_idx = self.grid.coord_to_nearest_track(inv_gn_warr.layer_id + 1, inv_gn_warr.lower) inv_g_tid = TrackID(inv_gn_warr.layer_id + 1, inv_g_idx) inv_g = self.connect_to_tracks([inv_gn_warr, inv_gp_warr], inv_g_tid) inv_dn_warr = self.connect_to_tracks(inv_n_ports['d'], nout_id, min_len_mode=0) inv_dp_warr = self.connect_to_tracks(inv_p_ports['d'], pout_id, min_len_mode=0) # connect source self.connect_to_substrate('ptap', inv_n_ports['s']) self.connect_to_substrate('ntap', inv_p_ports['s']) # add pins self.add_pin('I', inv_g, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy( vdd_width=power_width_ntr, vss_width=power_width_ntr) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) idx = self.grid.coord_to_nearest_track(inv_dn_warr.layer_id + 1, inv_dn_warr.upper) tid = TrackID(inv_dn_warr.layer_id + 1, idx) ptap_wire_arrs.append(inv_dn_warr) ntap_wire_arrs.append(inv_dp_warr) self.connect_to_tracks(ptap_wire_arrs, tid) self.connect_to_tracks(ntap_wire_arrs, tid) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nfn=nfn, nfp=nfp, intent=intent, dum_info=dum_info, )
def draw_layout(self): """Draw the layout of a dynamic latch chain. """ # type: () -> None lch = self.params['lch'] ptap_w = self.params['ptap_w'] ntap_w = self.params['ntap_w'] w_dict = self.params['w_dict'] th_dict = self.params['th_dict'] seg_dict = self.params['seg_dict'] ndum = self.params['ndum'] tr_widths = self.params['tr_widths'] tr_spaces = self.params['tr_spaces'] show_pins = self.params['show_pins'] guard_ring_nf = self.params['guard_ring_nf'] top_layer = self.params['top_layer'] tech_cls_name = self.params['tech_cls_name'] if tech_cls_name is not None: self.set_tech_class(tech_cls_name) ana_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf, top_layer=top_layer, tech_cls_name=tech_cls_name) min_fg_sep = ana_info.min_fg_sep # calculate total number of fingers seg_ptail = seg_dict['ptail'] seg_ntail = seg_dict['ntail'] seg_pin = seg_dict['pin'] seg_nin = seg_dict['nin'] fg_ptail = seg_ptail fg_ntail = seg_ntail fg_pin = seg_pin fg_nin = seg_nin # error checking if fg_pin % 2 != 0 or fg_nin % 2 != 0 or fg_ptail % 2 != 0 or fg_ntail % 2 != 0: raise ValueError('Only even number of fingers are supported.') if (fg_pin - fg_nin) % 4 != 0: raise ValueError('This code now only works if fg_pin and fg_nin differ by ' 'multiples of 4.') fg_single_in = max(fg_pin, fg_nin) fg_single = max(fg_ptail, fg_ntail, fg_pin, fg_nin) in_mid_idx = ndum + fg_single - fg_single_in // 2 fg_tot = 2 * (fg_single + ndum) + min_fg_sep ndum_pin = in_mid_idx - fg_pin // 2 ndum_nin = in_mid_idx - fg_nin // 2 if fg_ntail <= fg_nin: ndum_ntail = ndum_nin + fg_nin - fg_ntail else: ndum_ntail = min(ndum_nin, ndum + fg_single - fg_ntail) if fg_ptail <= fg_pin: ndum_ptail = ndum_pin + fg_pin - fg_ptail else: ndum_ptail = min(ndum_pin, ndum + fg_single - fg_ptail) # get width/threshold/orientation info nw_list = [w_dict['ntail'], w_dict['nin']] nth_list = [th_dict['ntail'], th_dict['nin']] n_orientations = ['MX', 'MX'] pw_list = [w_dict['pin'], w_dict['ptail']] pth_list = [th_dict['pin'], th_dict['ptail']] p_orientations = ['R0', 'R0'] # get tracks information tr_manager = TrackManager(self.grid, tr_widths, tr_spaces) hm_layer = self.mos_conn_layer + 1 # allocate tracks wire_names = dict( nch=[ dict(g=['bias'], ds=['tail']), dict(g=['in', 'out'], ds=[]), ], pch=[ dict(g=['in'], ds=[]), dict(g=['bias'], ds=['tail']), ], ) # draw base self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, tr_manager=tr_manager, wire_names=wire_names, n_orientations=n_orientations, p_orientations=p_orientations, guard_ring_nf=guard_ring_nf, top_layer=top_layer) # draw transistors ntaill = self.draw_mos_conn('nch', 0, ndum_ntail, fg_ntail, 2, 0, s_net='ntail', d_net='') ntailr = self.draw_mos_conn('nch', 0, fg_tot - ndum_ntail - fg_ntail, fg_ntail, 2, 0, s_net='ntail', d_net='') ptaill = self.draw_mos_conn('pch', 1, ndum_ptail, fg_ptail, 0, 2, s_net='ptail', d_net='') ptailr = self.draw_mos_conn('pch', 1, fg_tot - ndum_ptail - fg_ptail, fg_ptail, 0, 2, s_net='ptail', d_net='') if (ndum_nin - ndum_ntail) % 2 == 1: tail_nin_port, out_nin_port = 'd', 's' sdir, ddir = 2, 0 s_netl, s_netr, d_netl, d_netr = 'outn', 'outp', 'ntail', 'ntail' else: tail_nin_port, out_nin_port = 's', 'd' sdir, ddir = 0, 2 s_netl, s_netr, d_netl, d_netr = 'ntail', 'ntail', 'outn', 'outp' ninl = self.draw_mos_conn('nch', 1, ndum_nin, fg_nin, sdir, ddir, s_net=s_netl, d_net=d_netl) ninr = self.draw_mos_conn('nch', 1, fg_tot - ndum_nin - fg_nin, fg_nin, sdir, ddir, s_net=s_netr, d_net=d_netr) if (ndum_pin - ndum_ptail) % 2 == 1: tail_pin_port, out_pin_port = 'd', 's' sdir, ddir = 0, 2 s_netl, s_netr, d_netl, d_netr = 'outn', 'outp', 'ptail', 'ptail' else: tail_pin_port, out_pin_port = 's', 'd' sdir, ddir = 2, 0 s_netl, s_netr, d_netl, d_netr = 'ptail', 'ptail', 'outn', 'outp' pinl = self.draw_mos_conn('pch', 0, ndum_pin, fg_pin, sdir, ddir, s_net=s_netl, d_net=d_netl) pinr = self.draw_mos_conn('pch', 0, fg_tot - ndum_pin - fg_pin, fg_pin, sdir, ddir, s_net=s_netr, d_net=d_netr) # draw connections # VDD/VSS self.connect_to_substrate('ptap', [ntaill['d'], ntailr['d']]) self.connect_to_substrate('ntap', [ptaill['d'], ptailr['d']]) # NMOS/PMOS tail tail_tid = self.get_wire_id('nch', 0, 'ds', wire_name='tail') self.connect_to_tracks([ntaill['s'], ntailr['s'], ninl[tail_nin_port], ninr[tail_nin_port]], tail_tid) tail_tid = self.get_wire_id('pch', 1, 'ds', wire_name='tail') self.connect_to_tracks([ptaill['s'], ptailr['s'], pinl[tail_pin_port], pinr[tail_pin_port]], tail_tid) # NMOS/PMOS tail bias bn_tid = self.get_wire_id('nch', 0, 'g', wire_name='bias') bp_tid = self.get_wire_id('pch', 1, 'g', wire_name='bias') self.connect_to_tracks([ntaill['g'], ntailr['g'], ninl['d'], pinl['d']], bn_tid) self.connect_to_tracks([ptaill['g'], ptailr['g'], ninl['d'], pinl['d']], bp_tid) # input/output inn_tid = self.get_wire_id('nch', 1, 'g', wire_name='in') inp_tid = self.get_wire_id('pch', 0, 'g', wire_name='in') inp_idx = inp_tid.base_index inn_idx = inn_tid.base_index in_sum2 = int(round(2 * (inp_idx + inn_idx))) if in_sum2 % 2 == 1: # move inp_idx down so output is centered wrt inputs inp_idx -= 0.5 in_sum2 -= 1 out_tid = TrackID(hm_layer, in_sum2 / 4, width=tr_manager.get_width(hm_layer, 'out')) # connect input/output inp, inn = self.connect_differential_tracks([ninl['g'], pinl['g']], [ninr['g'], pinr['g']], hm_layer, inp_idx, inn_idx, width=inn_tid.width) out = self.connect_to_tracks([ninr[out_nin_port], pinr[out_pin_port]], out_tid, min_len_mode=0) # fill dummies tr_w = tr_manager.get_width(hm_layer, 'sup') vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=tr_w, vss_width=tr_w) # add pins self.add_pin('inp', inp, show=show_pins) self.add_pin('inn', inn, show=show_pins) self.add_pin('out', out, show=show_pins) self.add_pin('VSS', vss_warrs, show=show_pins) self.add_pin('VDD', vdd_warrs, show=show_pins) # compute schematic parameters self._sch_params = dict( lch=lch, w_dict=w_dict, th_dict=th_dict, seg_dict=seg_dict, dum_info=self.get_sch_dummy_info(), )
def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, nf_inv, g_space, ds_space, ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent, ndum, ndum_side, show_pins, fg_tot, debug, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # get resolution res = self.grid.resolution # make sure all fingers are even number if nfn % 2 != 0 or nfp % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) if fg_tot is None or fg_tot < ndum_side * 2 + ndum * 2 + max( nfn, nfp) * 2 + nf_inv: fg_tot = ndum_side * 2 + ndum * 2 + max(nfn, nfp) * 2 + nf_inv else: ndum_side = (fg_tot - ndum * 2 - max(nfn, nfp) * 2 - nf_inv) // 2 # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr * 2 + g_space] pg_tracks = [g_width_ntr * 2 + g_space] nds_tracks = [ds_width_ntr * 2 + ds_space] pds_tracks = [ds_width_ntr * 2 + ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base( lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, ) # # get gate and drain index # ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1) # pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1) # nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1) # pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1) # ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1) # pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1) # # # nand # nand_n0_ports = self.draw_mos_conn('nch', 0, ndum_side, nfn, 1, 1, # s_net='VSS', d_net='ns') # nand_p0_ports = self.draw_mos_conn('pch', 0, ndum_side, nfp, 1, 1, # s_net='VDD', d_net='o_b') # col_idx = ndum_side + max(nfn, nfp) + ndum # nand_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn, 1, 1, # s_net='ns', d_net='o_b') # nand_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp, 1, 1, # s_net='VDD', d_net='o_b') # col_idx = ndum_side + max(nfn, nfp) + ndum*2 + nf_inv # inv_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv, 1, 1, # s_net='VSS', d_net='O') # inv_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv, 1, 1, # s_net='VDD', d_net='O') # # connect nand # nand_gn0_warr = self.connect_to_tracks(nand_n0_ports['g'], ngate_id) # nand_gp0_warr = self.connect_to_tracks(nand_p0_ports['g'], pgate_id) # nand_g0_idx = self.grid.coord_to_nearest_track(nand_gn0_warr.layer_id + 1, nand_gn0_warr.lower) # nand_g0_tid = TrackID(nand_gn0_warr.layer_id + 1, nand_g0_idx) # nand_g0 = self.connect_to_tracks([nand_gn0_warr, nand_gp0_warr], nand_g0_tid) # # nand_gn1_warr = self.connect_to_tracks(nand_n1_ports['g'], ngate_id) # nand_gp1_warr = self.connect_to_tracks(nand_p1_ports['g'], pgate_id) # nand_g1_idx = self.grid.coord_to_nearest_track(nand_gn0_warr.layer_id + 1, nand_gn1_warr.lower) # nand_g1_tid = TrackID(nand_gn0_warr.layer_id + 1, nand_g1_idx) # nand_g1 = self.connect_to_tracks([nand_gn1_warr, nand_gp1_warr], nand_g1_tid) # # connect nand_n0 and nand_n1 # self.connect_to_tracks([nand_n0_ports['d'], nand_n1_ports['s']], ndrain_id) # self.connect_to_substrate('ptap', nand_n0_ports['s']) # self.connect_to_substrate('ntap', [nand_p0_ports['s'], nand_p1_ports['s']]) # # # connect inv # inv_gn_warr = self.connect_to_tracks(inv_n_ports['g'], ngate_id) # inv_gp_warr = self.connect_to_tracks(inv_p_ports['g'], pgate_id) # inv_g_idx = self.grid.coord_to_nearest_track(inv_gn_warr.layer_id + 1, inv_gn_warr.lower) # inv_g_tid = TrackID(inv_gn_warr.layer_id + 1, inv_g_idx) # inv_g = self.connect_to_tracks([inv_gn_warr, inv_gp_warr], inv_g_tid) # # connect gate # o_b = self.connect_to_tracks([nand_p0_ports['d'], nand_p1_ports['d'], nand_n1_ports['d'], inv_g], # pout_id) # o_b = inv_g # use M5 for o_b # # connect drain # o = self.connect_to_tracks([inv_n_ports['d'], inv_p_ports['d']], nout_id) # self.connect_to_substrate('ptap', inv_n_ports['s']) # self.connect_to_substrate('ntap', inv_p_ports['s']) # # # add pins # self.add_pin('A', nand_g0, show=show_pins) # self.add_pin('B', nand_g1, show=show_pins) # if debug is True: # self.add_pin('o_b', o_b, show=show_pins) # self.add_pin('O', o, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy() # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get size self.size = self.grid.get_size_tuple(m5v_layer, width=self.bound_box.width, height=self.bound_box.height, round_up=True) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( lch=lch, wn=wn, wp=wp, nfn=nfn, nfp=nfp, nf_inv=nf_inv, intent=intent, dum_info=dum_info, debug=debug, )
def _draw_layout_helper(self, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # define some global variables global ngate_id, pgate_id, out_id, outp_id global ndum, ndum_side, ndum_cell, nf_inv0, nf_inv1 global m4h_layer, m5v_layer global fg_cell # get parameters pi_res = self.params['pi_res'] lch = self.params['lch'] wn = self.params['wn'] wp = self.params['wp'] nf_inv0 = self.params['nf_inv0'] nf_inv1 = self.params['nf_inv1'] ndum = self.params['ndum'] ndum_side = self.params['ndum_side'] ndum_cell = self.params['ndum_cell'] intent = self.params['intent'] ptap_w = self.params['ptap_w'] ntap_w = self.params['ntap_w'] g_width_ntr = self.params['g_width_ntr'] ds_width_ntr = self.params['ds_width_ntr'] show_pins = self.params['show_pins'] power_width_ntr = self.params['power_width_ntr'] g_space = self.params['g_space'] ds_space = self.params['ds_space'] if ndum_cell is None: ndum_cell = ndum # get resolution res = self.grid.resolution # finger number fg_cell = ndum + ndum_cell + nf_inv0 + nf_inv1 fg_tot = ndum_side * 2 + fg_cell * (pi_res+2) + ndum*(pi_res+1) # make sure all fingers are even number if nf_inv0 % 2 != 0 or nf_inv1 % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr+g_space] pg_tracks = [g_width_ntr+g_space] nds_tracks = [ds_width_ntr+ds_space] pds_tracks = [ds_width_ntr+ds_space] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, top_layer=m5v_layer) # get gate and draiin index ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr) pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr) out_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr) outp_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr) # define wire array dum_in_arr = [] ctrli_in_arr = [] ctrlq_in_arr = [] ctrlib_in_arr = [] ctrlqb_in_arr = [] ctrli_o_arr = [] ctrlq_o_arr = [] ctrlib_o_arr = [] ctrlqb_o_arr = [] ctrli_ob_arr = [] ctrlq_ob_arr = [] ctrlib_ob_arr = [] ctrlqb_ob_arr = [] # Step1: draw dummy cell inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=0, dum=True) dum_in_arr.append(inv0_in) inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=pi_res+1, dum=True) dum_in_arr.append(inv0_in) # Step2: draw cells for i in range(0, pi_res): inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=i+1) if i % 4 == 0: ctrli_in_arr.append(inv0_in) ctrli_o_arr.append(inv1_out) ctrli_ob_arr.append(inv0_out) elif i % 4 == 1: ctrlq_in_arr.append(inv0_in) ctrlq_o_arr.append(inv1_out) ctrlq_ob_arr.append(inv0_out) elif i % 4 == 2: ctrlib_in_arr.append(inv0_in) ctrlib_o_arr.append(inv1_out) ctrlib_ob_arr.append(inv0_out) else: ctrlqb_in_arr.append(inv0_in) ctrlqb_o_arr.append(inv1_out) ctrlqb_ob_arr.append(inv0_out) ctrl_in_arr = ctrli_in_arr + ctrlq_in_arr + ctrlib_in_arr + ctrlqb_in_arr ctrl_o_arr = ctrli_o_arr + ctrlq_o_arr + ctrlib_o_arr + ctrlqb_o_arr ctrl_ob_arr = ctrli_ob_arr + ctrlq_ob_arr + ctrlib_ob_arr + ctrlqb_ob_arr # add pins for i, ctrl_in in enumerate(ctrl_in_arr): self.add_pin('ctrl<{}>'.format(i), ctrl_in, show=show_pins) for i, ctrl_o in enumerate(ctrl_o_arr): self.add_pin('ctrl_o<{}>'.format(i), ctrl_o, show=show_pins) for i, ctrl_ob in enumerate(ctrl_ob_arr): self.add_pin('ctrl_ob<{}>'.format(i), ctrl_ob, show=show_pins) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(vdd_width=power_width_ntr, vss_width=power_width_ntr) # connect dummy input to ground for dum_in in dum_in_arr: self.connect_to_tracks(ptap_wire_arrs, dum_in.track_id, track_upper=dum_in.get_bbox_array(self.grid).top_unit, unit_mode=True, min_len_mode=0) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( pi_res=self.params['pi_res'], lch=self.params['lch'], wn=self.params['wn'], wp=self.params['wp'], nf_inv0=self.params['nf_inv0'], nf_inv1=self.params['nf_inv1'], intent=self.params['intent'], dum_info=dum_info, )
def _draw_layout_helper(self, **kwargs): """Draw the layout of a transistor for characterization. Notes ------- The number of fingers are for only half (or one side) of the tank. Total number should be 2x """ # define some global variables global ngate_id, ngate1_id, pgate_id, out_id, outp_id, ndrain_id, pdrain_id global ndum, ndum_side, nf_inv, nf_tinv0, nf_tinv1 global m4h_layer, m5v_layer global fg_cell # get parameters pi_res = self.params['pi_res'] lch = self.params['lch'] wn = self.params['wn'] wp = self.params['wp'] nf_inv = self.params['nf_inv'] nf_inv = self.params['nf_inv'] nf_tinv0 = self.params['nf_tinv0'] nf_tinv0 = self.params['nf_tinv0'] nf_tinv1 = self.params['nf_tinv1'] nf_tinv1 = self.params['nf_tinv1'] ndum = self.params['ndum'] ndum_side = self.params['ndum_side'] intent = self.params['intent'] ptap_w = self.params['ptap_w'] ntap_w = self.params['ntap_w'] g_width_ntr = self.params['g_width_ntr'] ds_width_ntr = self.params['ds_width_ntr'] show_pins = self.params['show_pins'] power_width_ntr = self.params['power_width_ntr'] # get resolution res = self.grid.resolution # finger number fg_cell = ndum * 2 + max(nf_inv, nf_inv) + max(nf_tinv0, nf_tinv0) + max(nf_tinv1, nf_tinv1) fg_tot = ndum_side * 2 + fg_cell * (pi_res+2) + ndum*(pi_res+1) # make sure all fingers are even number if nf_inv % 2 != 0 or nf_inv % 2 != 0 or nf_tinv0 % 2 != 0 or nf_tinv1 % 2 != 0 or\ nf_tinv0 % 2 != 0 or nf_tinv1 % 2 != 0: raise ValueError("Need all finger number to be even!") # get layer separation space layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0) m4h_layer = layout_info.mconn_port_layer + 1 m5v_layer = layout_info.mconn_port_layer + 2 g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr) ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr) # draw transistor rows nw_list = [wn] pw_list = [wp] nth_list = [intent] pth_list = [intent] ng_tracks = [g_width_ntr*2] pg_tracks = [g_width_ntr*2] nds_tracks = [ds_width_ntr*2] pds_tracks = [ds_width_ntr*2] n_orientation = ['R0'] p_orientation = ['MX'] self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list, ng_tracks=ng_tracks, nds_tracks=nds_tracks, pg_tracks=pg_tracks, pds_tracks=pds_tracks, n_orientations=n_orientation, p_orientations=p_orientation, top_layer=m5v_layer) # get gate and draiin index ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr) ngate1_id = self.make_track_id('nch', 0, 'g', 1, width=g_width_ntr) pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr) out_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr) outp_id = self.make_track_id('pch', 0, 'ds', 1, width=ds_width_ntr) ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr) pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr) # define wire array dum_in_arr = [] dum_ctrl_arr = [] dum_ctrlb_arr = [] clk_i_arr = [] clk_q_arr = [] clk_ib_arr = [] clk_qb_arr = [] clko_arr = [] ctrli_arr = [] ctrli_b_arr = [] ctrlq_arr = [] ctrlq_b_arr = [] ctrlib_arr = [] ctrlib_b_arr = [] ctrlqb_arr = [] ctrlqb_b_arr = [] # draw dummy inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=0, dum=True) dum_in_arr.append(inv_in) dum_ctrl_arr.append(ng_tinv1) dum_ctrlb_arr.append(pg_tinv1) inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=pi_res+1, dum=True) dum_in_arr.append(inv_in) dum_ctrl_arr.append(ng_tinv1) dum_ctrlb_arr.append(pg_tinv1) for i in range(pi_res): # draw clk cell inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=i+1) # 1 is for dummy if i % 4 == 0: clk_i_arr.append(inv_in) ctrli_arr.append(ng_tinv1) ctrli_b_arr.append(pg_tinv1) clko_arr.append(tinv_out) elif i % 4 == 1: clk_q_arr.append(inv_in) ctrlq_arr.append(ng_tinv1) ctrlq_b_arr.append(pg_tinv1) clko_arr.append(tinv_out) elif i % 4 == 2: clk_ib_arr.append(inv_in) ctrlib_arr.append(ng_tinv1) ctrlib_b_arr.append(pg_tinv1) clko_arr.append(tinv_out) else: clk_qb_arr.append(inv_in) ctrlqb_arr.append(ng_tinv1) ctrlqb_b_arr.append(pg_tinv1) clko_arr.append(tinv_out) ctrl_arr = ctrli_arr + ctrlq_arr + ctrlib_arr + ctrlqb_arr ctrlb_arr = ctrli_b_arr + ctrlq_b_arr + ctrlib_b_arr + ctrlqb_b_arr # connect all clk_i_arr idx = self.grid.coord_to_nearest_track(clk_i_arr[0].layer_id+1, clk_i_arr[0].get_bbox_array(self.grid).bottom_unit, unit_mode=True) tid_i = TrackID(clk_i_arr[0].layer_id+1, idx+1) tid_q = TrackID(clk_i_arr[0].layer_id+1, idx+2) tid_ib = TrackID(clk_i_arr[0].layer_id+1, idx+3) tid_qb = TrackID(clk_i_arr[0].layer_id+1, idx+4) clk_i = self.connect_to_tracks(clk_i_arr, tid_i, min_len_mode=0) clk_q = self.connect_to_tracks(clk_q_arr, tid_q, min_len_mode=0) clk_ib = self.connect_to_tracks(clk_ib_arr, tid_ib, min_len_mode=0) clk_qb = self.connect_to_tracks(clk_qb_arr, tid_qb, min_len_mode=0) # connect all clk_o idx = self.grid.coord_to_nearest_track(clko_arr[0].layer_id + 1, clk_i_arr[0].get_bbox_array(self.grid).top_unit, unit_mode=True) tid = TrackID(clko_arr[0].layer_id+1, idx+2) clko = self.connect_to_tracks(clko_arr, tid, min_len_mode=0) # draw dummies ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(vdd_width=power_width_ntr, vss_width=power_width_ntr) # connect dummy for dum_in in dum_in_arr: self.connect_to_tracks(ptap_wire_arrs, dum_in.track_id, track_upper=dum_in.get_bbox_array(self.grid).top_unit, unit_mode=True, min_len_mode=0) for dum_ctrl in dum_ctrl_arr: idx = self.grid.coord_to_nearest_track(dum_ctrl.layer_id+1, dum_ctrl.middle) tid = TrackID(dum_ctrl.layer_id+1, idx) self.connect_to_tracks([ptap_wire_arrs[0], dum_ctrl], tid, track_lower=dum_ctrl.get_bbox_array(self.grid).top_unit, min_len_mode=0) for dum_ctrlb in dum_ctrlb_arr: idx = self.grid.coord_to_nearest_track(dum_ctrlb.layer_id + 1, dum_ctrlb.middle) tid = TrackID(dum_ctrlb.layer_id + 1, idx) self.connect_to_tracks([ntap_wire_arrs[0], dum_ctrlb], tid, track_lower=dum_ctrlb.get_bbox_array(self.grid).top_unit, min_len_mode=0) # add pins self.add_pin('clko', clko, show=show_pins) self.add_pin('clk_i', clk_i, show=show_pins) self.add_pin('clk_q', clk_q, show=show_pins) self.add_pin('clk_ib', clk_ib, show=show_pins) self.add_pin('clk_qb', clk_qb, show=show_pins) for i, ctrl in enumerate(ctrl_arr): self.add_pin('ctrl<{}>'.format(i), ctrl, show=show_pins) for i, ctrlb in enumerate(ctrlb_arr): self.add_pin('ctrlb<{}>'.format(i), ctrlb, show=show_pins) # export supplies self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins) self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins) # get schematic parameters dum_info = self.get_sch_dummy_info() self._sch_params = dict( pi_res=self.params['pi_res'], lch=self.params['lch'], wn=self.params['wn'], wp=self.params['wp'], nf_inv=self.params['nf_inv'], nf_tinv0=self.params['nf_tinv0'], nf_tinv1=self.params['nf_tinv1'], intent=self.params['intent'], dum_info=dum_info, )