Пример #1
0
    def get_dut_conns(self, dut_pins: Iterable[str], src_pins: Set[str],
                      pin_values: Mapping[str, int]) -> Mapping[str, str]:
        pwr_domain: Mapping[str, Tuple[str, str]] = self.specs['pwr_domain']

        ans = {}
        for pin_name in dut_pins:
            pin_val: Optional[int] = pin_values.get(pin_name, None)
            basename, bus_range = parse_cdba_name(pin_name)
            if bus_range is None:
                # scalar pins
                if pin_name in src_pins or pin_val is None:
                    ans[pin_name] = pin_name
                else:
                    ans[pin_name] = self.get_pin_supplies(
                        pin_name, pwr_domain)[pin_val]
            else:
                # bus pins
                if pin_val is None:
                    # no bias values specified
                    ans[pin_name] = pin_name
                else:
                    nlen = len(bus_range)
                    bin_str = bin(pin_val)[2:].zfill(nlen)
                    ans[pin_name] = self._bin_str_to_net(
                        basename, bus_range, bin_str, pwr_domain, src_pins)

        return ans
Пример #2
0
    def get_dut_conns(
            self, dut_pins: Iterable[str], src_pins: Set[str],
            pin_values: Mapping[str, int]) -> Tuple[Dict[str, str], List[str]]:
        pwr_domain: Mapping[str, Tuple[str, str]] = self.specs['pwr_domain']

        ans = {}
        no_conn = []
        for pin_name in dut_pins:
            pin_val: Optional[int] = pin_values.get(pin_name, None)
            basename, bus_range = parse_cdba_name(pin_name)
            if bus_range is None:
                # scalar pins
                if pin_name in src_pins or pin_val is None:
                    ans[pin_name] = pin_name
                else:
                    ans[pin_name] = self.get_pin_supplies(
                        pin_name, pwr_domain)[pin_val]
                if pin_name not in src_pins and pin_val is None:
                    no_conn.append(pin_name)
            else:
                # bus pins
                if pin_val is None:
                    # no bias values specified
                    ans[pin_name] = pin_name
                    no_conn.append(pin_name)
                    # [no_conn.append(f"pin_name<{idx}>") for idx in range(max(bus_range.start, bus_range.stop))]
                else:
                    nlen = len(bus_range)
                    bin_str = bin(pin_val)[2:].zfill(nlen)
                    ans[pin_name] = self._bin_str_to_net(
                        basename, bus_range, bin_str, pwr_domain, src_pins)

        return ans, no_conn
Пример #3
0
 def get_pin_supplies(
         cls, pin_name: str,
         pwr_domain: Mapping[str, Tuple[str, str]]) -> Tuple[str, str]:
     ans = pwr_domain.get(pin_name, None)
     if ans is None:
         basename, _ = parse_cdba_name(pin_name)
         return pwr_domain[basename]
     return ans
Пример #4
0
 def get_recovery_removal_name(cls, pin: str) -> Tuple[str, str]:
     basename, bus_range = parse_cdba_name(pin)
     if bus_range is None:
         v1 = f't_recovery_{basename}_'
         v2 = f't_removal_{basename}_'
     else:
         v1 = f't_recovery_{basename}_{bus_range[0]}'
         v2 = f't_removal_{basename}_{bus_range[0]}'
     return v1, v2
Пример #5
0
 def get_setup_hold_name(cls, pin: str) -> Tuple[str, str]:
     basename, bus_range = parse_cdba_name(pin)
     if bus_range is None:
         var_setup = f't_setup_{basename}_'
         var_hold = f't_hold_{basename}_'
     else:
         var_setup = f't_setup_{basename}_{bus_range[0]}'
         var_hold = f't_hold_{basename}_{bus_range[0]}'
     return var_setup, var_hold
Пример #6
0
    def get_pin_supplies(
            cls, pin_name: str,
            pwr_domain: Mapping[str, Tuple[str, str]]) -> Tuple[str, str]:
        ans = pwr_domain.get(pin_name, None)
        if ans is None:
            # check if this is a r_src pin
            pin_base = cls.get_r_src_pin_base(pin_name)
            if pin_base:
                return pwr_domain[pin_base]

            # check if this is a bus pin, and pwr_domain is specified for the whole bus
            basename = parse_cdba_name(pin_name)[0]
            return pwr_domain[basename]
        return ans
Пример #7
0
    def _get_tbm_specs(sim_envs: Sequence[str], env_params: Mapping[str, Any],
                       dut_pins: Sequence[str], tbit: float, trf: float,
                       cload: float, nbits: int, rtol: float,
                       atol: float) -> Dict[str, Any]:
        tsim = tbit * (2 * nbits + 2) + tbit / 2
        pulse_list = [
            dict(pin='a_in', tper=tbit, tpw=tbit / 2, trf=trf, td=tbit / 2)
        ]
        for i in range(nbits):
            pulse_list.append(
                dict(pin=f'sn<{i}>',
                     tper=2 * tsim,
                     tpw=tsim,
                     trf=trf,
                     td=(2 * i + 2) * tbit + tbit / 4,
                     pos=False))
            pulse_list.append(
                dict(pin=f'sp<{i}>',
                     tper=2 * tsim,
                     tpw=tsim,
                     trf=trf,
                     td=(2 * i + 2) * tbit + tbit / 4,
                     pos=True))

        pin_values = {}
        load_list = [dict(pin='intout', type='cap', value=cload)]
        pwr_domains = {
            parse_cdba_name(pin)[0]: ('VSS', 'VDD')
            for pin in dut_pins
        }
        sim_params = dict(
            t_sim=tsim,
            t_rst=0,
            t_rst_rf=trf,
        )
        sup_values = dict(VSS=0, VDD=env_params['vdd'])
        return dict(sim_params=sim_params,
                    dut_pins=dut_pins,
                    pulse_list=pulse_list,
                    load_list=load_list,
                    pwr_domain=pwr_domains,
                    sup_values=sup_values,
                    pin_values=pin_values,
                    reset_list=[],
                    diff_list=[],
                    rtol=rtol,
                    atol=atol,
                    sim_envs=sim_envs,
                    env_params=env_params,
                    save_outputs=['a_in', 'a_in_buf', 'intout', 'b_in'])
Пример #8
0
def _get_pin_info_list(src_list: Sequence[Mapping[str, Any]], defaults: Mapping[str, Any],
                       pwr_domain: Dict[str, Tuple[str, str]],
                       reset_table: Optional[Dict[str, bool]] = None,
                       in_cap_table: Optional[Dict[str, float]] = None, cap_guess: float = 1.0e-15
                       ) -> List[Dict[str, Any]]:
    pin_list = []
    empty_dict = {}
    default_dict = {k: v for k, v in defaults.items()}
    for pin_info in src_list:
        pin_name: str = pin_info['name']
        reset_val: Optional[int] = pin_info.get('reset_val', None)

        basename, bus_range = parse_cdba_name(pin_name)
        if bus_range is None:
            # scalar pin
            if 'basename' in pin_info:
                raise ValueError('Scalar pins cannot have basename entry defined.')

            cur_info = default_dict.copy()
            cur_info.update(pin_info)
            cur_info.pop('hide', None)
            in_cap_guess = cur_info.pop('cap_guess', cap_guess)

            if in_cap_table is not None:
                in_cap_table[pin_name] = in_cap_guess

            # record power domain
            pwr_domain[pin_name] = (cur_info['gnd_pin'], cur_info['pwr_pin'])
            if reset_val is not None:
                if reset_table is None:
                    raise ValueError('reset_table is not given but reset_val is defined.')
                if pin_name in reset_table:
                    raise ValueError(f'pin {pin_name} is already in reset_table.')
                reset_table[pin_name] = (reset_val == 1)

            if not pin_info.get('hide', False):
                pin_list.append(cur_info)
        else:
            # bus pin
            values: Optional[List[Dict[str, Any]]] = pin_info.get('values', None)
            bus_defaults: Dict[str, Any] = pin_info.get('defaults', empty_dict)

            cur_defaults = default_dict.copy()
            cur_defaults.update(bus_defaults)
            if 'reset_val' not in cur_defaults:
                cur_defaults['reset_val'] = None
            num_bits = len(bus_range)
            # NOTE: make dictionary copies, so we can add cap info to them later
            if values is None:
                values = [cur_defaults.copy() for _ in range(num_bits)]
            elif len(values) != num_bits:
                raise ValueError(f'values list of bus {pin_name} length mismatch')
            else:
                values = []
                for val_ in values:
                    val_ = val_.copy()
                    val_.update(cur_defaults)
                    values.append(val_)

            # record power domain and reset values
            for bus_idx, bit_info in zip(bus_range, values):
                pwr_str: str = _get('pwr_pin', bit_info, cur_defaults)
                gnd_str: str = _get('gnd_pin', bit_info, cur_defaults)
                reset_val: Optional[int] = _get('reset_val', bit_info, cur_defaults)

                in_cap_guess = bit_info.pop('cap_guess', cap_guess)

                bit_name = get_bus_bit_name(basename, bus_idx, cdba=True)
                pwr_domain[bit_name] = (gnd_str, pwr_str)
                if reset_val is not None:
                    if reset_table is None:
                        raise ValueError('reset_table is not given but reset_val is defined.')
                    if bit_name in reset_table:
                        raise ValueError(f'pin {bit_name} is already in reset_table.')
                    reset_table[bit_name] = (reset_val == 1)

                if in_cap_table is not None:
                    in_cap_table[bit_name] = in_cap_guess

            if not pin_info.get('hide', False):
                pin_list.append(dict(name=pin_name, basename=basename, bus_range=bus_range,
                                     values=values))
    return pin_list
Пример #9
0
    def design(self, dut_lib: str, dut_cell: str,
               in_file_list: Sequence[Sequence[str]],
               clk_file_list: Sequence[Sequence[str]],
               load_list: Optional[Sequence[Sequence[str]]],
               vbias_list: Optional[Sequence[Sequence[str]]],
               other_list: Optional[List[Mapping[str,
                                                 Any]]], dut_conns: Dict[str,
                                                                         str],
               dut_params: Optional[Param], no_conns: Sequence[str],
               src_list: Sequence[Mapping[str, Any]]) -> None:
        """Design the testbench.

        The elements of parameter lists are either (pos_term, param) or
        (pos_term, neg_term, param), where pos_term/neg_term are the positive/negative
        terminals of the voltage sources or capacitors.  The negative terminal
        defaults to VSS if not specified.

        for ``load_list`` and ``vbias_list``, if None is given (the default), then
        the default load/bias voltages will be used (the ones shown in schematic
        template).  If an empty list is given, then they'll be removed entirely.

        Parameters
        ----------
        dut_lib : str
            DUT library name
        dut_cell : str
            DUT cell name
        in_file_list : Sequence[Sequence[str]]
            List of PWL input stimuli files
        clk_file_list : Sequence[Sequence[str]]
            List of PWL clk stimuli files
        load_list : Optional[Sequence[Sequence[str]]]
            List of ideal capacitor loads
        other_list : Optional[Sequence[Sequence[str]]]
            List of other devices for tb
        vbias_list : Optional[Sequence[Sequence[str]]]
            List of voltage biases
        dut_conns : Dict[str, str]
            DUT connection dictionary
        dut_params: Optional[Param]
            Replace the DUT statically if empty, otherwise call design with dut_params.
        no_conns: List[str]
            Connects the content of this list to noConn.
        src_list : Sequence[Mapping[str, Any]]
            list of sources and loads.
        """

        if no_conns:
            len_no_conn = 0
            for pin in no_conns:
                basename, bus_range = parse_cdba_name(pin)
                if bus_range is None:
                    len_no_conn += 1
                else:
                    len_no_conn += max(bus_range.start, bus_range.stop) + 1

            self.rename_instance('XNC', f'XNC<{len_no_conn - 1}:0>',
                                 [('noConn', ','.join(no_conns))])
        else:
            self.delete_instance('XNC')

        if vbias_list is None:
            vbias_list = [('VDD', 'vdd')]

        # combine src_list and load_list
        src_load_list = list(src_list)
        if load_list:
            for cap_info in load_list:
                if len(cap_info) == 2:
                    pos_term, val = cap_info
                    neg_term = 'VSS'
                elif len(cap_info) == 3:
                    pos_term, neg_term, val = cap_info
                else:
                    raise ValueError(f'Cannot parse cap element: {cap_info}')

                src_load_list.append(
                    dict(type='cap',
                         lib='analogLib',
                         value=val,
                         conns=dict(PLUS=pos_term, MINUS=neg_term)))

        # setup DUT
        dut_static = dut_params is None
        self.replace_instance_master('XDUT',
                                     dut_lib,
                                     dut_cell,
                                     static=dut_static,
                                     keep_connections=True)
        if not dut_static:
            self.instances['XDUT'].design(**dut_params)
        self.reconnect_instance('XDUT', ((k, v) for k, v in dut_conns.items()))

        # setup PWL files
        def get_path_str(fname: str) -> str:
            return json.dumps(str(Path(fname).resolve()))

        self._array_and_set_params('VIN', in_file_list, 'fileName',
                                   get_path_str)
        self._array_and_set_params('VCLK', clk_file_list, 'fileName',
                                   get_path_str)
        # setup voltage biases
        self._array_and_set_params('VSUP', vbias_list, 'vdc', None)

        # setup sources and loads
        self.design_sources_and_loads(src_load_list, default_name='CLOAD')

        if other_list:
            name_list = []
            element_list = []
            for other_dev in other_list:
                name_list.append(other_dev['name'])
                element_list.append((other_dev['name'], other_dev['conn'],
                                     other_dev['params']))
            self.array_instance('XSW', inst_name_list=name_list)

            for name, conns, val_dict in element_list:
                inst = self.instances[name]
                for k, v in val_dict.items():
                    inst.set_param(k, v)
                self.reconnect_instance(name, conns.items())
        else:
            self.remove_instance('XSW')