def run_test(db: TemplateDB, lay_list: List[Tuple[TemplateBase, str]], fpath_list: List[Path]) -> None: for fpath in fpath_list: print(f'creating layout from file: {fpath.name}') specs = read_yaml(fpath) lay_cls = cast(Type[TemplateBase], import_class(specs['lay_class'])) params = specs['params'] master = db.new_template(lay_cls, params=params) lay_list.append((master, fpath.stem))
def draw_layout(self): cls_name: str = self.params['cls_name'] params: Mapping[str, Any] = self.params['params'] gen_cls = cast(Type[ArrayBase], import_class(cls_name)) master = self.new_template(gen_cls, params=params) inst = self.draw_boundaries(master, master.top_layer) # pass out schematic parameters self.sch_params = master.sch_params # re-export pins for name in inst.port_names_iter(): self.reexport(inst.get_port(name))
def draw_layout(self): params = self.params cls_name: str = params['cls_name'] dut_params: Param = params['params'] export_hidden: bool = params['export_hidden'] half_blk_x: bool = params['half_blk_x'] half_blk_y: bool = params['half_blk_y'] gen_cls = cast(Type[MOSBase], import_class(cls_name)) master = self.new_template(gen_cls, params=dut_params) self.wrap_mos_base(master, export_hidden, half_blk_x=half_blk_x, half_blk_y=half_blk_y)
def draw_layout(self) -> None: cls_name: str = self.params['cls_name'] params: Param = self.params['params'] draw_taps: bool = self.params['draw_taps'] pwr_gnd_list: List[Tuple[str, str]] = self.params['pwr_gnd_list'] if draw_taps: master = self.new_template(STDCellWithTap, params=dict(cls_name=cls_name, params=params, pwr_gnd_list=pwr_gnd_list)) else: gen_cls = cast(Type[MOSBase], import_class(cls_name)) master = self.new_template(gen_cls, params=params) self.wrap_mos_base(master, False)
def draw_layout(self) -> None: gen_cls = cast(Type[MOSBase], import_class(self.params['cls_name'])) pwr_gnd_list: List[Tuple[str, str]] = self.params['pwr_gnd_list'] master: MOSBase = self.new_template(gen_cls, params=self.params['params']) self._core = master self.draw_base(master.draw_base_info) num_tiles = master.num_tile_rows tap_ncol = max((self.get_tap_ncol(tile_idx=tile_idx) for tile_idx in range(num_tiles))) tap_sep_col = self.sub_sep_col num_cols = master.num_cols + 2 * (tap_sep_col + tap_ncol) self.set_mos_size(num_cols, num_tiles=num_tiles) # breakpoint() if not pwr_gnd_list: pwr_gnd_list = [('VDD', 'VSS')] * num_tiles elif len(pwr_gnd_list) != num_tiles: raise ValueError('pwr_gnd_list length mismatch.') inst = self.add_tile(master, 0, tap_ncol + tap_sep_col) sup_names = set() for tidx in range(num_tiles): pwr_name, gnd_name = pwr_gnd_list[tidx] sup_names.add(pwr_name) sup_names.add(gnd_name) vdd_list = [] vss_list = [] self.add_tap(0, vdd_list, vss_list, tile_idx=tidx) self.add_tap(num_cols, vdd_list, vss_list, tile_idx=tidx, flip_lr=True) self.add_pin(pwr_name, vdd_list, connect=True) self.add_pin(gnd_name, vss_list, connect=True) for name in inst.port_names_iter(): if name in sup_names: self.reexport(inst.get_port(name), connect=True) else: self.reexport(inst.get_port(name)) self.sch_params = master.sch_params self._sch_cls = master.get_schematic_class_inst()
async def async_measure_performance( self, name: str, sim_dir: Path, sim_db: SimulationDB, dut: Optional[DesignInstance]) -> Dict[str, Any]: specs = self.specs flop_params: Mapping[str, Any] = specs['flop_params'] tbm_cls_val: Union[str, Type[FlopTimingBase]] = specs['tbm_cls'] t_rf_list: Sequence[float] = specs['t_rf_list'] t_clk_rf_list: Sequence[float] = specs['t_clk_rf_list'] t_clk_rf_first: bool = specs['t_clk_rf_first'] fake: bool = specs.get('fake', False) use_dut: bool = specs.get('use_dut', True) meas_dut = dut if use_dut else None tbm_cls = cast(Type[FlopTimingBase], import_class(tbm_cls_val)) mode_list = tbm_cls.get_meas_modes(flop_params) out_mode_list = tbm_cls.get_output_meas_modes(flop_params) # output timing measurement self.log('Measuring output delays') timing_table = {} gatherer = GatherHelper() for out_mode in out_mode_list: gatherer.append( self.get_out_timing(name, sim_db, meas_dut, sim_dir, tbm_cls, out_mode, fake, timing_table)) self.log('Measuring input constraints') clk_len = len(t_clk_rf_list) in_len = len(t_rf_list) arr_shape = (clk_len, in_len) if t_clk_rf_first else (in_len, clk_len) for ck_idx, t_clk_rf in enumerate(t_clk_rf_list): for rf_idx, t_rf in enumerate(t_rf_list): for meas_mode in mode_list: coro = self.get_in_timing(name, sim_db, meas_dut, sim_dir, meas_mode, fake, t_clk_rf, t_rf, ck_idx, rf_idx, arr_shape, t_clk_rf_first, timing_table) gatherer.append(coro) await gatherer.gather_err() ans = {key: list(val.values()) for key, val in timing_table.items()} return ans
def draw_layout(self) -> None: params = self.params cls_name: str = params['cls_name'] params: Param = params['params'] pmos_gr: str = params['pmos_gr'] nmos_gr: str = params['nmos_gr'] sep_ncol: Tuple[int, int] = params['sep_ncol'] edge_ncol: int = params['edge_ncol'] gen_cls = cast(Type[MOSBase], import_class(cls_name)) master: MOSBase = self.new_template(gen_cls, params=params) _, sup_list = self.draw_guard_ring(master, pmos_gr, nmos_gr, sep_ncol, edge_ncol) for tile_idx, (vss_list, vdd_list) in enumerate(sup_list): for ridx, warr in enumerate(vss_list): self.add_pin(f'VSS_guard_{tile_idx}_{ridx}', warr) for ridx, warr in enumerate(vdd_list): self.add_pin(f'VDD_guard_{tile_idx}_{ridx}', warr)
def draw_layout(self) -> None: ndio_cls_name: str = self.params['ndio_cls'] pdio_cls_name: str = self.params['pdio_cls'] ndio_params: Param = self.params['ndio_params'] pdio_params: Param = self.params['pdio_params'] fe_params: Param = self.params['fe_params'] npadout: int = self.params['npadout'] w_dio_min: int = self.params['w_dio_min'] dio_margin: int = self.params['dio_margin'] tb_margin: int = self.params['tb_margin'] fe_ip_params = dict( cls_name='xbase.layout.mos.top.GenericWrapper', params=dict( cls_name=Frontend.get_qualified_name(), params=fe_params, export_hidden=True, half_blk_x=False, ), ) # make masters fe_master: TemplateBase = self.new_template(IPMarginTemplate, params=fe_ip_params) ndio_cls = cast(Type[TemplateBase], import_class(ndio_cls_name)) pdio_cls = cast(Type[TemplateBase], import_class(pdio_cls_name)) nd_master: TemplateBase = self.new_template(ndio_cls, params=ndio_params) pd_master: TemplateBase = self.new_template(pdio_cls, params=pdio_params) # floorplan grid = self.grid top_layer = nd_master.top_layer w_blk, h_blk = grid.get_block_size(top_layer) tb_margin = -(-tb_margin // h_blk) * h_blk fe_box = fe_master.bound_box nd_box = nd_master.bound_box pd_box = pd_master.bound_box h_fe = fe_box.h h_nd = nd_box.h h_pd = pd_box.h w_fe = fe_box.w w_nd = nd_box.w w_pd = pd_box.w w_dio = max(w_dio_min + dio_margin, w_nd + w_pd) w_tot = w_fe + w_dio w_tot = -(-w_tot // w_blk) * w_blk h_tot = max(h_fe, h_nd, h_pd) + 2 * tb_margin y_fe = (h_tot - h_fe) // (2 * h_blk) * h_blk y_nd = (h_tot - h_nd) // (2 * h_blk) * h_blk y_pd = (h_tot - h_pd) // (2 * h_blk) * h_blk x_nd = w_fe x_pd = w_tot - w_pd # instantiate blocks fe = self.add_instance(fe_master, inst_name='XFE', xform=Transform(0, y_fe)) nd = self.add_instance(nd_master, inst_name='XND', xform=Transform(x_nd, y_nd)) pd = self.add_instance(pd_master, inst_name='XPD', xform=Transform(x_pd, y_pd)) self.set_size_from_bound_box(top_layer, BBox(0, 0, w_tot, h_tot)) # diode guard ring connections vlay = (fe.get_port('VSS').get_single_layer(), 'drawing') vdir = Direction.LOWER vss_list = [] vdd_list = [] vddio_list = [] vss_bbox: List[BBox] = fe.get_all_port_pins('VSS', layer=vlay[0]) vdd_bbox: List[BBox] = fe.get_all_port_pins('VDDCore', layer=vlay[0]) vddio_bbox: List[BBox] = fe.get_all_port_pins('VDDIO', layer=vlay[0]) vss_pd = pd.get_all_port_pins('gr') for bbox in vss_bbox: vss_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vss_pd)) vss_list = self.connect_wires(vss_list) vddio_nd = nd.get_all_port_pins('gr') for bbox in vddio_bbox: vddio_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vddio_nd)) vddio_list = self.connect_wires(vddio_list) # diode ports vddio_pd = pd.get_all_port_pins('sub') vss_nd = nd.get_all_port_pins('sub') dio_sp_le = grid.get_line_end_space(vss_nd[0].layer_id, vss_nd[0].track_id.width, even=True) dio_sp_le2 = dio_sp_le // 2 if dio_margin < 0: dio_margin = dio_sp_le2 dio_port_xh = w_tot - dio_margin x_dio_mid = (nd.bound_box.xh + pd.bound_box.xl) // 2 vddio_pd = self.extend_wires(vddio_pd, lower=x_dio_mid + dio_sp_le2, upper=dio_port_xh) vss_nd = self.extend_wires(vss_nd, lower=x_nd, upper=x_dio_mid - dio_sp_le2) self.add_pin('VDDIO', vddio_pd) self.add_pin('VSS', vss_nd) pad = pd.get_all_port_pins('pad') pad.extend(nd.port_pins_iter('pad')) pad = self.connect_wires(pad, lower=x_nd, upper=dio_port_xh)[0] self.add_pin('iopad', pad) # short diode wires so we are LVS clean ym_layer = vddio_nd[0].layer_id - 1 vss_tidx = grid.coord_to_track(ym_layer, x_nd + w_nd, mode=RoundMode.GREATER_EQ) vddio_tidx = grid.coord_to_track(ym_layer, x_pd, mode=RoundMode.LESS_EQ) iopad_tidx = grid.get_middle_track(vss_tidx, vddio_tidx, round_up=False) ym_w = grid.get_min_track_width(ym_layer, top_ntr=vddio_nd[0].track_id.width) vddio_pd.extend(vddio_list) vss_nd.extend(vss_list) self.connect_to_tracks(vddio_pd, TrackID(ym_layer, vddio_tidx, width=ym_w)) self.connect_to_tracks(vss_nd, TrackID(ym_layer, vss_tidx, width=ym_w)) self.connect_to_tracks(pad, TrackID(ym_layer, iopad_tidx, width=ym_w)) # connect iopad and iclkn npad = pad.track_id.num pad_conn = pad[:npadout] iclkn_bnds = [COORD_MAX, COORD_MIN] iopad_out_list = [] for bbox in fe.port_pins_iter('txpadout', layer=vlay[0]): warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn) iopad_out_list.append(warr) for bbox in fe.port_pins_iter('rxpadin', layer=vlay[0]): cur_bnds = [0, 0] warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn, ret_bnds=cur_bnds) iopad_out_list.append(warr) iclkn_bnds[0] = min(iclkn_bnds[0], cur_bnds[0]) iclkn_bnds[1] = max(iclkn_bnds[1], cur_bnds[1]) # export iopad_out pad_conn_tid = pad_conn.track_id pad_layer = pad_conn_tid.layer_id iopad_out_list = self.connect_wires(iopad_out_list) lower = iopad_out_list[0].lower pad_bnds = grid.get_wire_bounds(pad_layer, pad_conn_tid.base_index, width=pad_conn_tid.width) pin_len = grid.get_next_length(pad_layer, pad_conn_tid.width, pad_bnds[1] - pad_bnds[0], even=True) ms_params = self.add_res_metal_warr(pad_layer, pad_conn_tid.base_index, lower + pin_len, lower + 2 * pin_len, width=pad_conn_tid.width, num=pad_conn_tid.num, pitch=pad_conn_tid.pitch) self.add_pin('iopad_out', WireArray(pad_conn_tid, lower, lower + pin_len)) bbox_iclkn = fe.get_pin('iclkn', layer=vlay[0]) bbox_iclkn = bbox_iclkn.set_interval(Orient2D.y, iclkn_bnds[0], iclkn_bnds[1]) # NOTE: some process require metal to be in same hierarchy as pin self.add_rect(vlay, bbox_iclkn) self.add_pin_primitive('iclkn', vlay[0], bbox_iclkn) # supply connections for idx in range(npad): tid = vss_nd[idx].track_id if idx == 0 or idx == npad - 1: cur_list = vdd_list cur_bbox = vdd_bbox elif idx & 1: cur_list = vss_list cur_bbox = vss_bbox else: cur_list = vddio_list cur_bbox = vddio_bbox for bbox in cur_bbox: cur_list.append(self.connect_bbox_to_tracks(vdir, vlay, bbox, tid)) self.add_pin('VDDCore', self.connect_wires(vdd_list)) self.add_pin('VDDIO', self.connect_wires(vddio_list)) self.add_pin('VSS', self.connect_wires(vss_list)) for name in ['VDDCore', 'VDDIO', 'VSS']: self.reexport(fe.get_port(f'{name}_xm'), net_name=name, hide=False) # reexport pins for name in ['din', 'ipdrv_buf<1>', 'ipdrv_buf<0>', 'indrv_buf<1>', 'indrv_buf<0>', 'itx_en_buf', 'weak_pulldownen', 'weak_pullupenb']: self.reexport(fe.get_port(name)) for name in ['clk_en', 'data_en', 'por', 'odat', 'odat_async', 'oclkp', 'oclkn']: self.reexport(fe.get_port(name)) self.sch_params = dict( fe_params=fe_master.sch_params, nd_params=nd_master.sch_params, pd_params=pd_master.sch_params, ms_params=ms_params, )