def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) zero = HalfInt(0) self._q_tr_info = (0, zero, zero) self._sr_hm_tr_info = self._q_tr_info self._sr_vm_tr_info = self._q_tr_info
def from_dict( cls, table: Mapping[Tuple[str, int], Tuple[float, int]]) -> WireLookup: data = { key: (HalfInt.convert(val[0]), val[1]) for key, val in table.items() } return WireLookup(data)
def get_move(self, tr_pitch: int, delta: int) -> RowPlaceInfo: tr_shift = HalfInt((2 * delta) // tr_pitch) el = [] return RowPlaceInfo(self.row_info, self.bot_wires.get_move(tr_shift, el), self.top_wires.get_move(tr_shift, el), self.yb + delta, self.yt + delta, self.yb_blk + delta, self.yt_blk + delta, (self.y_conn[0] + delta, self.y_conn[1] + delta))
def get_blk_info(self, conn_layer: int, w: int, h: int, nx: int, ny: int, **kwargs: Any) -> Optional[ArrayLayInfo]: res_type: str = kwargs.get('res_type', 'standard') if res_type != 'metal': raise ValueError(f'unsupported resistor type: {res_type}') x_pitch: int = self.res_config['x_pitch'] conn_w: int = self.res_config['conn_w'] sp_le = self.tech_info.get_min_line_end_space('M1CA', conn_w, purpose='drawing', even=True) builder = LayoutInfoBuilder() x0 = x_pitch // 2 yl = sp_le yh = h - sp_le x1 = w - x_pitch // 2 boxl = BBox(x0 - conn_w // 2, yl, x0 + conn_w // 2, yh) builder.add_rect_arr(('M1CA', 'drawing'), boxl, nx=2, spx=x1 - x0) xm = w // 2 boxm = BBox(xm - conn_w // 2, yl, xm + conn_w // 2, yh) builder.add_rect_arr(('M1CA', 'drawing'), boxm) boxr = BBox(boxm.xl, yl + conn_w, boxm.xh, yh - conn_w) builder.add_rect_arr(('m1res', 'drawing'), boxr) builder.add_rect_arr(('M1CA', 'drawing'), BBox(boxl.xl, yl, boxm.xh, yl + conn_w)) boxr = boxl.get_move_by(dx=x1 - x0) builder.add_rect_arr(('M1CA', 'drawing'), BBox(boxm.xl, yh - conn_w, boxr.xh, yh)) tidu = HalfInt(2 * ((w // x_pitch) - 1)) return ArrayLayInfo( builder.get_info(BBox(0, 0, w, h)), ImmutableSortedDict({ 'u': WireArrayInfo(1, tidu, yl, yh, 1, 1, 0), 'l': WireArrayInfo(1, HalfInt(0), yl, yh, 1, 1, 0) }), ImmutableSortedDict(), ImmutableSortedDict())
def get_extend(self, tr_pitch, delta: int, top_edge: bool, shared: Sequence[str]) -> RowPlaceInfo: tr_shift = HalfInt((2 * delta) // tr_pitch) if top_edge: top_wires = self.top_wires.get_move_shared(tr_shift, shared) return RowPlaceInfo(self.row_info, self.bot_wires, top_wires, self.yb, self.yt + delta, self.yb_blk, self.yt_blk, self.y_conn) else: return RowPlaceInfo( self.row_info, self.bot_wires.get_move(tr_shift, shared), self.top_wires.get_move(tr_shift, []), self.yb, self.yt + delta, self.yb_blk + delta, self.yt_blk + delta, (self.y_conn[0] + delta, self.y_conn[1] + delta))
def draw_layout(self): place_info = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(place_info) seg_dict: ImmutableSortedDict[str, int] = self.params['seg_dict'] ridx_n: int = self.params['ridx_n'] ridx_p: int = self.params['ridx_p'] has_rstb: bool = self.params['has_rstb'] has_outbuf: bool = self.params['has_outbuf'] has_inbuf: bool = self.params['has_inbuf'] out_pitch: HalfInt = HalfInt.convert(self.params['out_pitch']) w_dict, th_dict = self._get_w_th_dict(ridx_n, ridx_p, has_rstb) seg_fb = seg_dict['fb'] seg_ps = seg_dict['ps'] seg_nr = seg_dict['nr'] seg_obuf = seg_dict['obuf'] if has_outbuf else 0 seg_ibuf = seg_dict['ibuf'] if has_inbuf else 0 w_pfb = w_dict['pfb'] w_nfb = w_dict['nfb'] w_ps = w_dict['ps'] w_nr = w_dict['nr'] w_rst = w_dict.get('pr', 0) w_nbuf = w_nr w_pbuf = w_ps sch_seg_dict = dict(nfb=seg_fb, pfb=seg_fb, ps=seg_ps, nr=seg_nr) if has_rstb: sch_seg_dict['pr'] = seg_rst = seg_dict['rst'] else: seg_rst = 0 if seg_ps & 1 or seg_nr & 1 or seg_rst & 1 or seg_obuf & 1: raise ValueError( 'ps, nr, rst, and buf must have even number of segments') # placement min_sep = self.min_sep_col # use even step size to maintain supply conn_layer wires parity. min_sep += (min_sep & 1) hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 grid = self.grid arr_info = self.arr_info tr_manager = self.tr_manager hm_w = tr_manager.get_width(hm_layer, 'sig') vm_w = tr_manager.get_width(vm_layer, 'sig') hm_sep_col = self.get_hm_sp_le_sep_col(ntr=hm_w) mid_sep = max(hm_sep_col - 2, 0) mid_sep = (mid_sep + 1) // 2 if has_inbuf: m_nibuf = self.add_mos(ridx_n, mid_sep, seg_ibuf, w=w_nbuf) m_pibuf = self.add_mos(ridx_p, mid_sep, seg_ibuf, w=w_pbuf) cur_col = mid_sep + seg_ibuf psrb_list = [m_nibuf.g, m_pibuf.g] else: m_nibuf = m_pibuf = None cur_col = mid_sep psrb_list = [] nr_col = cur_col m_nr = self.add_mos(ridx_n, cur_col, seg_nr, w=w_nr) m_ps = self.add_mos(ridx_p, cur_col, seg_ps, w=w_ps) psrb_list.append(m_ps.g) pcol = cur_col + seg_ps if has_rstb: m_rst = self.add_mos(ridx_p, pcol, seg_rst, w=w_rst) pcol += seg_rst else: m_rst = None cur_col = max(cur_col + seg_nr, pcol) if has_outbuf: m_pinv = self.add_mos(ridx_p, cur_col, seg_obuf, w=w_pbuf) m_ninv = self.add_mos(ridx_n, cur_col, seg_obuf, w=w_nbuf) cur_col += seg_obuf else: m_pinv = m_ninv = None cur_col += min_sep fb_col = cur_col m_pfb = self.add_mos(ridx_p, cur_col, seg_fb, w=w_pfb, g_on_s=True, stack=2, sep_g=True) m_nfb = self.add_mos(ridx_n, cur_col, seg_fb, w=w_nfb, g_on_s=True, stack=2, sep_g=True) self.set_mos_size() # track planning vss_tid = self.get_track_id(ridx_n, MOSWireType.DS, wire_name='sup') nbuf_tid = self.get_track_id(ridx_n, MOSWireType.DS, wire_name='sig', wire_idx=-2) nq_tid = self.get_track_id(ridx_n, MOSWireType.DS, wire_name='sig', wire_idx=-1) psr_tid = self.get_track_id(ridx_p, MOSWireType.G, wire_name='sig', wire_idx=-1) pq_tid = self.get_track_id(ridx_p, MOSWireType.DS, wire_name='sig', wire_idx=0) pbuf_tid = self.get_track_id(ridx_p, MOSWireType.DS, wire_name='sig', wire_idx=1) vdd_tid = self.get_track_id(ridx_p, MOSWireType.DS, wire_name='sup') # try to spread out gate wires to lower parasitics on differential Q wires ng_lower = self.get_track_index(ridx_n, MOSWireType.G, wire_name='sig', wire_idx=0) ng_upper = self.get_track_index(ridx_n, MOSWireType.G, wire_name='sig', wire_idx=-1) g_idx_list = tr_manager.spread_wires( hm_layer, ['sig', 'sig_hs', 'sig_hs', 'sig'], ng_lower, ng_upper, ('sig_hs', 'sig_hs'), alignment=0) self._q_tr_info = (hm_w, g_idx_list[2], g_idx_list[1]) self._sr_hm_tr_info = (hm_w, g_idx_list[3], g_idx_list[0]) if has_rstb: rst_tid = self.get_track_id(ridx_p, MOSWireType.G, wire_name='sig', wire_idx=-2) pq_conn_list = [m_ps.d, m_rst.d, m_pfb.s] vdd_list = [m_ps.s, m_rst.s, m_pfb.d] vss_list = [m_nr.s, m_nfb.d] rstb = self.connect_to_tracks(m_rst.g, rst_tid, min_len_mode=MinLenMode.MIDDLE) rst_vm_tidx = grid.coord_to_track(vm_layer, rstb.middle, mode=RoundMode.GREATER_EQ) rstb_vm = self.connect_to_tracks( rstb, TrackID(vm_layer, rst_vm_tidx, width=vm_w)) self.add_pin('rstb', rstb_vm) else: pq_conn_list = [m_ps.d, m_pfb.s] vdd_list = [m_ps.s, m_pfb.d] vss_list = [m_nr.s, m_nfb.d] self.add_pin('nsr', m_nr.g) self.add_pin('nsrb', m_nfb.g[0::2]) nq = self.connect_to_tracks([m_nr.d, m_nfb.s], nq_tid) pq = self.connect_to_tracks(pq_conn_list, pq_tid) psrb = self.connect_to_tracks(psrb_list, psr_tid, min_len_mode=MinLenMode.UPPER) psr = self.connect_to_tracks(m_pfb.g[0::2], psr_tid, min_len_mode=MinLenMode.LOWER) qb = self.connect_wires([m_nfb.g[1::2], m_pfb.g[1::2]]) self.add_pin('qb', qb) if has_inbuf: vdd_list.append(m_pibuf.s) vss_list.append(m_nibuf.s) nbuf = self.connect_to_tracks(m_nibuf.d, nbuf_tid, min_len_mode=MinLenMode.UPPER) pbuf = self.connect_to_tracks(m_pibuf.d, pbuf_tid, min_len_mode=MinLenMode.UPPER) vm_tidx = grid.coord_to_track(vm_layer, nbuf.middle, mode=RoundMode.LESS_EQ) buf = self.connect_to_tracks([nbuf, pbuf], TrackID(vm_layer, vm_tidx, width=vm_w)) self.add_pin('sr_buf', buf) out_p_htr = out_pitch.dbl_value vm_ref = grid.coord_to_track(vm_layer, 0) srb_vm_tidx = arr_info.col_to_track(vm_layer, nr_col + 1, mode=RoundMode.GREATER_EQ) if has_outbuf: vdd_list.append(m_pinv.s) vss_list.append(m_ninv.s) nbuf = self.connect_to_tracks(m_ninv.d, nbuf_tid, min_len_mode=MinLenMode.MIDDLE) pbuf = self.connect_to_tracks(m_pinv.d, pbuf_tid, min_len_mode=MinLenMode.MIDDLE) vm_delta = grid.coord_to_track( vm_layer, nbuf.middle, mode=RoundMode.LESS_EQ) - vm_ref vm_htr = -(-vm_delta.dbl_value // out_p_htr) * out_p_htr vm_tidx = vm_ref + HalfInt(vm_htr) buf = self.connect_to_tracks([nbuf, pbuf], TrackID(vm_layer, vm_tidx, width=vm_w)) self.add_pin('buf_out', buf) buf_in = self.connect_wires([m_ninv.g, m_pinv.g]) self.add_pin('buf_in', buf_in) q_vm_tidx = tr_manager.get_next_track(vm_layer, srb_vm_tidx, 'sig', 'sig') else: vm_delta = tr_manager.get_next_track(vm_layer, srb_vm_tidx, 'sig', 'sig') - vm_ref vm_htr = -(-vm_delta.dbl_value // out_p_htr) * out_p_htr q_vm_tidx = vm_ref + HalfInt(vm_htr) sr_vm_tidx = arr_info.col_to_track(vm_layer, fb_col, mode=RoundMode.LESS_EQ) self._sr_vm_tr_info = (vm_w, sr_vm_tidx, srb_vm_tidx) q_vm = self.connect_to_tracks([nq, pq], TrackID(vm_layer, q_vm_tidx, width=vm_w)) self.add_pin('q_vm', q_vm) self.add_pin('psr', psr) self.add_pin('psrb', psrb) self.add_pin('VDD', self.connect_to_tracks(vdd_list, vdd_tid)) self.add_pin('VSS', self.connect_to_tracks(vss_list, vss_tid)) lch = arr_info.lch buf_params = ImmutableSortedDict( dict( lch=lch, w_p=w_pbuf, w_n=w_nbuf, th_p=th_dict['ps'], th_n=th_dict['nr'], seg=seg_obuf, )) obuf_params = buf_params if has_outbuf else None ibuf_params = buf_params.copy(append=dict( seg=seg_ibuf)) if has_inbuf else None self.sch_params = dict( core_params=ImmutableSortedDict( dict( lch=lch, seg_dict=ImmutableSortedDict(sch_seg_dict), w_dict=w_dict, th_dict=th_dict, )), outbuf_params=obuf_params, inbuf_params=ibuf_params, has_rstb=has_rstb, )
def draw_layout(self): pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo, flip_tile=True) mux_params: Param = self.params['mux_params'] flop_params: Param = self.params['flop_params'] inv_params: Param = self.params['inv_params'] vm_pitch: HalfInt = HalfInt.convert(self.params['vm_pitch']) vm_pitch_htr = vm_pitch.dbl_value # create masters mux_params = mux_params.copy( append=dict(pinfo=pinfo, vertical_sel=False)) flop_params = flop_params.copy(append=dict( pinfo=pinfo, has_rstlb=True, swap_outbuf=True, out_pitch=vm_pitch)) mux_master: Mux2to1Matched = self.new_template(Mux2to1Matched, params=mux_params) flop_master: FlopStrongArm = self.new_template(FlopStrongArm, params=flop_params) inv_in_tidx = mux_master.get_port( 'in<0>').get_pins()[0].track_id.base_index inv_params = inv_params.copy( append=dict(pinfo=pinfo, sig_locs={'in': inv_in_tidx})) inv_master: InvCore = self.new_template(InvCore, params=inv_params) # placement min_sep = self.min_sep_col min_sep += (min_sep & 1) buf_ncol = inv_master.num_cols mux_ncol = mux_master.num_cols flop_ncol = flop_master.num_cols ncol_tot = max(flop_ncol, mux_ncol + 2 * min_sep + 2 * buf_ncol) mux_off = (ncol_tot - mux_ncol) // 2 flop_off = (ncol_tot - flop_ncol) // 2 mux_in = self.add_tile(mux_master, 0, mux_off) flop = self.add_tile(flop_master, 1, flop_off) mux_out = self.add_tile(mux_master, 3, mux_off) invl = self.add_tile(inv_master, 3, 0) invr = self.add_tile(inv_master, 3, ncol_tot, flip_lr=True) self.set_mos_size() yh = self.bound_box.yh xm = self.bound_box.xm # routing vm_layer = self.conn_layer + 2 grid = self.grid tr_manager = self.tr_manager vm_w = tr_manager.get_width(vm_layer, 'sig') vm_w_ck = tr_manager.get_width(vm_layer, 'clk') # supplies vdd_list = [] vss_list = [] for inst in [mux_in, flop, mux_out, invl, invr]: vdd_list.extend(inst.port_pins_iter('VDD')) vss_list.extend(inst.port_pins_iter('VSS')) self.add_pin('VDD', self.connect_wires(vdd_list), connect=True) self.add_pin('VSS', self.connect_wires(vss_list), connect=True) # input mux flop_clk = mux_in.get_pin('out') self.connect_to_track_wires(flop_clk, flop.get_pin('clk')) in0 = mux_in.get_pin('in<0>') in1 = mux_in.get_pin('in<1>') clk_vm_tidx = flop_clk.track_id.base_index in_vm_test = tr_manager.get_next_track(vm_layer, clk_vm_tidx, 'sig', 'clk', up=True) in_dhtr = (-(in_vm_test - clk_vm_tidx).dbl_value // vm_pitch_htr) * vm_pitch_htr in_delta = HalfInt(in_dhtr) in0 = self.connect_to_tracks(in0, TrackID(vm_layer, clk_vm_tidx + in_delta, width=vm_w_ck), min_len_mode=MinLenMode.LOWER) in1 = self.connect_to_tracks(in1, TrackID(vm_layer, clk_vm_tidx - in_delta, width=vm_w_ck), min_len_mode=MinLenMode.LOWER) self.add_pin('launch', in0) self.add_pin('measure', in1) # divider flop clkp = flop.get_pin('outp') clkn = flop.get_pin('outn') self.connect_differential_wires(mux_in.get_pin('nsel'), mux_in.get_pin('nselb'), clkp, clkn) self.connect_to_track_wires(clkp, mux_in.get_pin('psel')) self.connect_to_track_wires(clkn, mux_in.get_pin('pselb')) self.connect_to_track_wires(flop.get_pin('inn'), clkp) self.connect_to_track_wires(flop.get_pin('inp'), clkn) self.connect_to_tracks(mux_out.get_pin('in<0>'), clkp.track_id, track_upper=yh, track_lower=clkp.lower) self.reexport(flop.get_port('rstlb')) self.reexport(flop.get_port('rstlb_vm_l')) self.reexport(flop.get_port('rsthb')) # output mux clkn_tid = clkn.track_id vm_sp_le = grid.get_line_end_space(vm_layer, clkn_tid.width) clk_dcd = self.connect_to_tracks(mux_out.get_pin('in<1>'), clkn_tid, track_lower=clkn.upper + vm_sp_le, track_upper=yh) clk_out = self.extend_wires(mux_out.get_pin('out'), upper=yh) self.add_pin('clk_dcd', clk_dcd) self.add_pin('clk_out', clk_out) # output mux select signals out_sel = invl.get_pin('out') out_selb = invr.get_pin('out') dcc_byp_delta = tr_manager.get_next_track( vm_layer, out_selb.track_id.base_index, 'sig', 'sig', up=True) - clk_vm_tidx dcc_byp_dhtr = -(-dcc_byp_delta.dbl_value // vm_pitch_htr) * vm_pitch_htr dcc_byp_delta = HalfInt(dcc_byp_dhtr) dcc_byp_tidx = clk_vm_tidx + dcc_byp_delta out_selb_vm_tidx = clk_vm_tidx - dcc_byp_delta self.connect_to_track_wires(mux_out.get_pin('psel'), out_sel) self.connect_to_track_wires(mux_out.get_pin('pselb'), out_selb) nsel, nselb = self.connect_differential_wires(out_sel, out_selb, mux_out.get_pin('nsel'), mux_out.get_pin('nselb')) sel_hm_list = [] selb_vm = self.connect_to_tracks([nselb, invl.get_pin('in')], TrackID(vm_layer, out_selb_vm_tidx, width=vm_w), track_upper=yh, ret_wire_list=sel_hm_list) # get differential matching xl = min((wire.lower for wire in sel_hm_list)) xh = 2 * xm - xl self.extend_wires([nsel, nselb], lower=xl, upper=xh) dcc_byp = self.connect_to_tracks(invr.get_pin('in'), TrackID(vm_layer, dcc_byp_tidx, width=vm_w), track_lower=selb_vm.lower, track_upper=yh) self.add_pin('dcc_byp', dcc_byp) self.sch_params = dict( mux_params=mux_master.sch_params, flop_params=flop_master.sch_params, inv_params=inv_master.sch_params, )
def draw_layout(self): pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) core_params: Param = self.params['core_params'] sync_params: Param = self.params['sync_params'] buf_params: Param = self.params['buf_params'] nsync: int = self.params['nsync'] vm_pitch: HalfInt = HalfInt.convert(self.params['vm_pitch']) # create masters core_params = core_params.copy(append=dict(pinfo=pinfo, vm_pitch=vm_pitch)) half_params = dict(pinfo=pinfo, sync_params=sync_params, buf_params=buf_params, nsync=nsync) core_master: DCCHelperCore = self.new_template(DCCHelperCore, params=core_params) sync_master: SyncChain = self.new_template(SyncChain, params=half_params) buf_ncol = sync_master.buf_ncol # placement hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 vm_w = self.tr_manager.get_width(vm_layer, 'sig') min_sep = self.min_sep_col min_sep += (min_sep & 1) core_ncol = core_master.num_cols sync_ncol = sync_master.num_cols center_ncol = max(2 * buf_ncol + min_sep, core_ncol) half_sep = center_ncol - 2 * buf_ncol core_off = sync_ncol - buf_ncol + (center_ncol - core_ncol) // 2 # add masters core = self.add_tile(core_master, 1, core_off) syncl = self.add_tile(sync_master, 0, sync_ncol, flip_lr=True) syncr = self.add_tile(sync_master, 0, sync_ncol + half_sep) self.set_mos_size(num_cols=2 * sync_ncol + half_sep) bbox = self.bound_box xl = bbox.xl xh = bbox.xh xm = (xl + xh) // 2 # routing # supplies for lay in [hm_layer, xm_layer]: for name in ['VDD', 'VSS']: cur_name = f'{name}_{lay}' warrs = syncl.get_all_port_pins(cur_name) warrs.extend(syncr.port_pins_iter(cur_name)) warrs = self.connect_wires(warrs, lower=xl, upper=xh) if lay == xm_layer: self.add_pin(name, warrs) # rstb for synchronizers grid = self.grid vm_p_htr = vm_pitch.dbl_value vm_center = grid.coord_to_track(vm_layer, xm) vm_delta = grid.coord_to_track(vm_layer, xh, mode=RoundMode.LESS_EQ) - vm_center vm_dhtr = -(-vm_delta.dbl_value // vm_p_htr) * vm_p_htr vm_delta = HalfInt(vm_dhtr) rstlb_r_tidx = vm_center + vm_delta rstlb_l_tidx = vm_center - vm_delta rstlbr_list = syncr.get_all_port_pins('rstlb') vss_bot = syncr.get_pin('VSS_bot') rstlbr_list.append(vss_bot) rstb_ref = self.connect_to_tracks(rstlbr_list, TrackID(vm_layer, rstlb_r_tidx, width=vm_w)) rstlbl_list = syncl.get_all_port_pins('rstlb') rstb = self.connect_to_tracks(rstlbl_list, TrackID(vm_layer, rstlb_l_tidx, width=vm_w), track_lower=rstb_ref.lower) self.add_pin('rstb', rstb) # clk for synchronizers clk_ref = self.connect_to_track_wires(vss_bot, syncr.get_pin('clk_sync')) clkl = self.extend_wires(syncl.get_pin('clk_sync'), lower=clk_ref.lower) clk_ref = self.connect_to_track_wires(clkl, syncl.get_pin('clk_buf')) self.extend_wires(syncr.get_pin('clk_buf'), upper=2 * xm - clk_ref.lower) # rstb_sync warr_list = [] rstb_sync = syncl.get_pin('out') rstb_ref = self.connect_to_tracks(core.get_pin('rstlb_vm_l'), rstb_sync.track_id, ret_wire_list=warr_list) self.extend_wires(core.get_pin('rsthb'), upper=warr_list[0].upper) rstb_ref = self.connect_wires([rstb_ref, syncl.get_pin('out')])[0] self.extend_wires(syncr.get_pin('out'), lower=2 * xm - rstb_ref.upper) # input clocks launch = self.connect_to_track_wires(syncl.get_pin('clk_in'), core.get_pin('launch')) measure = self.connect_to_track_wires(syncr.get_pin('clk_in'), core.get_pin('measure')) self.add_pin('launch', self.extend_wires(launch, lower=0)) self.add_pin('measure', self.extend_wires(measure, lower=0)) # reexports self.reexport(core.get_port('clk_out'), net_name='ckout') self.reexport(core.get_port('clk_dcd')) self.reexport(core.get_port('dcc_byp')) self.sch_params = sync_master.sch_params.copy(append=dict( core_params=core_master.sch_params))
def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) se_params: Param = self.params['se_params'] flop_params: Param = self.params['flop_params'] inv_params: Param = self.params['inv_params'] vm_pitch: HalfInt = HalfInt.convert(self.params['vm_pitch']) # create masters flop_pinfo = self.get_draw_base_sub_pattern(2, 4) flop_params = flop_params.copy( append=dict(pinfo=flop_pinfo, out_pitch=vm_pitch)) se_params = se_params.copy(append=dict(pinfo=self.get_tile_pinfo(0), vertical_out=False, vertical_in=False)) inv_params = inv_params.copy( append=dict(pinfo=self.get_tile_pinfo(2), ridx_n=0, ridx_p=-1)) flop_master = self.new_template(FlopStrongArm, params=flop_params) se_master = self.new_template(SingleToDiff, params=se_params) inv_master = self.new_template(InvCore, params=inv_params) # floorplanning tr_manager = self.tr_manager hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 vm_w = tr_manager.get_width(vm_layer, 'sig') vm_w_hs = tr_manager.get_width(vm_layer, 'sig_hs') # get flop column quantization sd_pitch = self.sd_pitch vm_coord_pitch = int(vm_pitch * self.grid.get_track_pitch(vm_layer)) sep_half = max(-(-self.min_sep_col // 2), -(-vm_coord_pitch // sd_pitch)) blk_ncol = lcm([sd_pitch, vm_coord_pitch]) // sd_pitch sep_ncol = self.min_sep_col flop_ncol2 = flop_master.num_cols // 2 se_col = sep_half center_col = sep_half + inv_master.num_cols + sep_ncol + flop_ncol2 center_col = -(-center_col // blk_ncol) * blk_ncol cur_col = center_col - flop_ncol2 if (cur_col & 1) != (se_col & 1): se_col += 1 se = self.add_tile(se_master, 0, se_col) inv = self.add_tile(inv_master, 2, cur_col - sep_ncol, flip_lr=True) flop = self.add_tile(flop_master, 2, cur_col) cur_col += flop_master.num_cols + self.sub_sep_col // 2 lay_range = range(self.conn_layer, xm_layer + 1) vdd_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range} vss_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range} sup_info = self.get_supply_column_info(xm_layer) for tile_idx in range(self.num_tile_rows): self.add_supply_column(sup_info, cur_col, vdd_table, vss_table, ridx_p=-1, ridx_n=0, tile_idx=tile_idx, flip_lr=False) self.set_mos_size() # connections # supplies for lay in range(hm_layer, xm_layer + 1, 2): vss = vss_table[lay] vdd = vdd_table[lay] if lay == hm_layer: for inst in [inv, flop, se]: vdd.extend(inst.get_all_port_pins('VDD')) vss.extend(inst.get_all_port_pins('VSS')) vdd = self.connect_wires(vdd) vss = self.connect_wires(vss) self.add_pin(f'VDD_{lay}', vdd, hide=True) self.add_pin(f'VSS_{lay}', vss, hide=True) inp = flop.get_pin('inp') inn = flop.get_pin('inn') loc_list = tr_manager.place_wires(vm_layer, ['sig_hs'] * 2, center_coord=inp.middle)[1] inp, inn = self.connect_differential_tracks(inp, inn, vm_layer, loc_list[0], loc_list[1], width=vm_w_hs) self.add_pin('sa_inp', inp) self.add_pin('sa_inn', inn) in_vm_ref = self.grid.coord_to_track(vm_layer, 0) in_vm_tidx = tr_manager.get_next_track(vm_layer, in_vm_ref, 'sig', 'sig', up=True) vm_phtr = vm_pitch.dbl_value in_vm_dhtr = -(-(in_vm_tidx - in_vm_ref).dbl_value // vm_phtr) * vm_phtr in_vm_tidx = in_vm_ref + HalfInt(in_vm_dhtr) in_warr = self.connect_to_tracks(se.get_all_port_pins('in'), TrackID(vm_layer, in_vm_tidx, width=vm_w), track_lower=0) self.add_pin('in', in_warr) out = flop.get_pin('outp') self.add_pin('out', self.extend_wires(out, upper=self.bound_box.yh)) self.reexport(flop.get_port('clkl'), net_name='clk', hide=False) self.reexport(flop.get_port('rstlb')) self.reexport(se.get_port('outp'), net_name='midp') self.reexport(se.get_port('outn'), net_name='midn') self.reexport(inv.get_port('in'), net_name='dum') self.sch_params = dict( se_params=se_master.sch_params, flop_params=flop_master.sch_params, inv_params=inv_master.sch_params, )
def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) sa_params: Param = self.params['sa_params'] sr_params: Param = self.params['sr_params'] has_rstlb: bool = self.params['has_rstlb'] swap_outbuf: bool = self.params['swap_outbuf'] out_pitch: HalfInt = HalfInt.convert(self.params['out_pitch']) # create masters sr_pinfo = self.get_tile_pinfo(1) sr_params = sr_params.copy(append=dict(pinfo=sr_pinfo, has_rstb=has_rstlb, has_inbuf=True, swap_outbuf=swap_outbuf, out_pitch=out_pitch)) sr_master: SRLatchSymmetric = self.new_template(SRLatchSymmetric, params=sr_params) even_center = sr_master.num_cols % 4 == 0 sa_pinfo = self.get_tile_pinfo(0) dig_style = (sa_pinfo == sr_pinfo) if dig_style: # digital style sa_params = sa_params.copy(append=dict( pinfo=sa_pinfo, has_rstb=has_rstlb, even_center=even_center)) sa_master: MOSBase = self.new_template(SAFrontendDigital, params=sa_params) else: # analog style sa_params = sa_params.copy(append=dict(pinfo=sa_pinfo, has_rstb=has_rstlb, even_center=even_center, vertical_out=False, vertical_rstb=False)) sa_master: MOSBase = self.new_template(SAFrontend, params=sa_params) # placement sa_ncol = sa_master.num_cols sr_ncol = sr_master.num_cols ncol = max(sa_ncol, sr_ncol) sa = self.add_tile(sa_master, 0, (ncol - sa_ncol) // 2) # NOTE: flip SR latch so outputs and inputs lines up nicely sr = self.add_tile(sr_master, 1, (ncol - sr_ncol) // 2 + sr_ncol, flip_lr=True) self.set_mos_size() # supplies self.add_pin('VSS', [sr.get_pin('VSS'), sa.get_pin('VSS')], connect=True) vdd = self.connect_wires([sr.get_pin('VDD'), sa.get_pin('VDD')])[0] self.add_pin('VDD', vdd) # connect outputs rb = sr.get_pin('rb') sb = sr.get_pin('sb') outp = sa.get_all_port_pins('outp') outn = sa.get_all_port_pins('outn') self.connect_to_track_wires(outp, rb) self.connect_to_track_wires(outn, sb) # connect reset signals if has_rstlb: rstlb = sr.get_pin('rstlb') rsthb = sr.get_pin('rsthb') if dig_style: sa_rstb = sa.get_pin('rstb') rstlbl = self.connect_to_track_wires(sa_rstb, rstlb) rsthb = self.connect_to_tracks(vdd, rsthb.track_id, track_lower=rstlbl.lower, track_upper=rsthb.upper) self.add_pin('rstlb', sa_rstb) self.add_pin('rsthb', rsthb, hide=True) else: sa_rstbl = [sa.get_pin('prstbl'), sa.get_pin('nrstb')] sa_rstbr = [sa.get_pin('prstbr'), sa_rstbl[1]] rstlbl = self.connect_to_track_wires(sa_rstbl, rstlb) rstlbr = self.connect_to_tracks(sa_rstbr, rsthb.track_id) self.connect_to_tracks(rsthb, vdd.track_id) self.add_pin('rstlb', sa_rstbl[1]) self.add_pin('rstlb_vm_r', rstlbr, hide=True) self.add_pin('rstlb_vm_l', rstlbl, hide=True) # reexport pins for name in ['inp', 'inn', 'clk', 'clkl', 'clkr']: self.reexport(sa.get_port(name)) self.reexport(sr.get_port('q'), net_name='outp') self.reexport(sr.get_port('qb'), net_name='outn') self.sch_params = dict( sa_params=sa_master.sch_params.copy(remove=['has_rstb']), sr_params=sr_master.sch_params.copy(remove=['has_rstb']), has_rstlb=has_rstlb)
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) zero = HalfInt(0) self._out_tinfo = (1, zero, zero)
# Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from typing import Union import pytest from pybag.enum import RoundMode from bag.util.math import HalfInt from bag.layout.routing import RoutingGrid @pytest.mark.parametrize("lay, coord, w_ntr, mode, half_track, expect", [ (4, 720, 1, RoundMode.LESS_EQ, True, HalfInt(10)), ]) def test_find_next_track(routing_grid: RoutingGrid, lay: int, coord: int, w_ntr: int, mode: Union[RoundMode, int], half_track: bool, expect: HalfInt) -> None: """Check that find_next_htr() works properly.""" ans = routing_grid.find_next_track(lay, coord, tr_width=w_ntr, half_track=half_track, mode=mode) assert ans == expect assert isinstance(ans, HalfInt)