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
Example #2
0
 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)
Example #3
0
 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))
Example #4
0
    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())
Example #5
0
 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,
        )
Example #7
0
    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,
        )
Example #8
0
    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))
Example #9
0
    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)
Example #11
0
 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)
Example #12
0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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)