Beispiel #1
0
def legalize_fixed_point_subselection(optree,
                                      input_prec_solver=default_prec_solver):
    """ Legalize a SubSignalSelection on a fixed-point node """
    sub_input = optree.get_input(0)
    inf_index = evaluate_cst_graph(optree.get_inf_index(),
                                   input_prec_solver=input_prec_solver)
    sup_index = evaluate_cst_graph(optree.get_sup_index(),
                                   input_prec_solver=input_prec_solver)
    assert not inf_index is None and not sup_index is None
    input_format = ML_StdLogicVectorFormat(
        sub_input.get_precision().get_bit_size())
    output_format = ML_StdLogicVectorFormat(sup_index - inf_index + 1)
    subselect = SubSignalSelection(TypeCast(sub_input, precision=input_format),
                                   inf_index,
                                   sup_index,
                                   precision=output_format)
    result = TypeCast(
        subselect,
        precision=optree.get_precision(),
    )
    # TypeCast may be simplified during code generation so attributes
    # may also be forwarded to previous node
    forward_attributes(optree, subselect)
    forward_attributes(optree, result)
    return result
Beispiel #2
0
def raw_fp_field_extraction(optree):
    """ generate an operation sub-graph to extract the fp field
        (mantissa without implicit digit) of a fp node """
    size = optree.get_precision().get_base_format().get_bit_size()
    field_size = optree.get_precision().get_base_format().get_field_size()
    return TypeCast(SubSignalSelection(
        TypeCast(optree, precision=ML_StdLogicVectorFormat(size)), 0,
        field_size - 1),
                    precision=fixed_point(field_size, 0, signed=False))
Beispiel #3
0
def mantissa_extraction_modifier_from_fields(op,
                                             field_op,
                                             exp_is_zero,
                                             tag="mant_extr"):
    """ Legalizing a MantissaExtraction node into a sub-graph
        of basic operation, assuming <field_op> bitfield and <exp_is_zero> flag
        are already available """

    op_precision = op.get_precision().get_base_format()

    implicit_digit = Select(
        exp_is_zero,
        Constant(0, precision=ML_StdLogic),
        Constant(1, precision=ML_StdLogic),
        precision=ML_StdLogic,
        tag=tag + "_implicit_digit",
    )
    result = Concatenation(
        implicit_digit,
        TypeCast(field_op,
                 precision=ML_StdLogicVectorFormat(
                     op_precision.get_field_size())),
        precision=ML_StdLogicVectorFormat(op_precision.get_mantissa_size()),
    )
    return result
Beispiel #4
0
def get_output_check_statement(output_signal, output_tag, output_value):
    """ Generate output value check statement """
    test_pass_cond = Comparison(
        output_signal,
        output_value,
        specifier=Comparison.Equal,
        precision=ML_Bool
    )

    check_statement = ConditionBlock(
        LogicalNot(
            test_pass_cond,
            precision = ML_Bool
        ),
        Report(
            Concatenation(
                " result for {}: ".format(output_tag),
                Conversion(
                    output_signal if output_signal.get_precision() is ML_StdLogic else
                    TypeCast(
                        output_signal,
                        precision=ML_StdLogicVectorFormat(
                            output_signal.get_precision().get_bit_size()
                        )
                     ),
                    precision = ML_String
                    ),
                precision = ML_String
            )
        )
    )
    return test_pass_cond, check_statement
Beispiel #5
0
def signal_str_conversion(optree, op_format):
    """ converision of @p optree from op_format to ML_String """
    return Conversion(
        optree if op_format is ML_StdLogic else
        TypeCast(
            optree,
            precision=ML_StdLogicVectorFormat(
                op_format.get_bit_size()
            )
         ),
        precision=ML_String
    )
Beispiel #6
0
def comp_3to2(a, b, c):
    """ 3 digits to 2 digits compressor """
    s = BitLogicXor(a,
                    BitLogicXor(b, c, precision=ML_StdLogic),
                    precision=ML_StdLogic)
    c = BitLogicOr(BitLogicAnd(a, b, precision=ML_StdLogic),
                   BitLogicOr(BitLogicAnd(a, c, precision=ML_StdLogic),
                              BitLogicAnd(c, b, precision=ML_StdLogic),
                              precision=ML_StdLogic),
                   precision=ML_StdLogic)
    return c, s

    a = TypeCast(a, precision=fixed_point(1, 0, signed=False))
    b = TypeCast(b, precision=fixed_point(1, 0, signed=False))
    c = TypeCast(c, precision=fixed_point(1, 0, signed=False))

    full = TypeCast(Conversion(a + b + c,
                               precision=fixed_point(2, 0, signed=False)),
                    precision=ML_StdLogicVectorFormat(2))
    carry = BitSelection(full, 1)
    digit = BitSelection(full, 0)
    return carry, digit
Beispiel #7
0
def generate_bitfield_extraction(target_format, input_node, lo_index,
                                 hi_index):
    shift = lo_index
    mask_size = hi_index - lo_index + 1

    input_format = input_node.get_precision().get_base_format()
    if is_fixed_point(input_format) and is_fixed_point(target_format):
        frac_size = target_format.get_frac_size()
        int_size = input_format.get_bit_size() - frac_size
        cast_format = ML_Custom_FixedPoint_Format(int_size,
                                                  frac_size,
                                                  signed=False)
    else:
        cast_format = None

    # 1st step: shifting the input node the right amount
    shifted_node = input_node if shift == 0 else BitLogicRightShift(
        input_node,
        Constant(shift, precision=ML_Int32),
        precision=input_format)
    raw_format = ML_Custom_FixedPoint_Format(input_format.get_bit_size(),
                                             0,
                                             signed=False)
    # 2nd step: masking the input node
    # TODO/FIXME: check thast mask does not overflow or wrap-around
    masked_node = BitLogicAnd(TypeCast(shifted_node, precision=raw_format),
                              Constant((2**mask_size - 1),
                                       precision=raw_format),
                              precision=raw_format)

    if not cast_format is None:
        casted_node = TypeCast(masked_node, precision=cast_format)
    else:
        casted_node = masked_node

    converted_node = Conversion(casted_node, precision=target_format)
    return converted_node
Beispiel #8
0
def generate_field_extraction(optree, precision, lo_index, hi_index):
    """ extract bit-field optree[lo_index:hi_index-1] and cast to precision """
    if optree.precision != precision:
        optree = TypeCast(optree, precision=precision)
    result = optree
    if lo_index != 0:
        result = BitLogicRightShift(optree,
                                    Constant(vectorize_cst(
                                        lo_index, precision),
                                             precision=precision),
                                    precision=precision)
    if (hi_index - lo_index + 1) != precision.get_bit_size():
        mask = Constant(vectorize_cst(2**(hi_index - lo_index + 1) - 1,
                                      precision),
                        precision=precision)
        result = BitLogicAnd(result, mask, precision=precision)
    return result
Beispiel #9
0
 def get_index_node(self, vx):
     assert vx.precision is self.precision
     int_precision = vx.precision.get_integer_format()
     index_size = self.exp_bits + self.field_bits
     # building an index mask from the index_size
     index_mask = Constant(2**index_size - 1, precision=int_precision)
     shift_amount = Constant(vx.get_precision().get_field_size() -
                             self.field_bits,
                             precision=int_precision)
     exp_offset = Constant(self.precision.get_integer_coding(
         S2**self.low_exp_value),
                           precision=int_precision)
     return BitLogicAnd(BitLogicRightShift(Subtraction(
         TypeCast(vx, precision=int_precision),
         exp_offset,
         precision=int_precision),
                                           shift_amount,
                                           precision=int_precision),
                        index_mask,
                        precision=int_precision)
Beispiel #10
0
def legalize_vector_reduction_test(optree):
    """ Legalize a vector test (e.g. IsMaskNotAnyZero) to a sub-graph
        of basic operations """
    op_input = optree.get_input(0)
    vector_size = op_input.get_precision().get_vector_size()
    conv_format = {
        2: v2int32,
        4: v4int32,
        8: v8int32,
    }[vector_size]

    cast_format = {
        2: ML_Int64,
        4: ML_Int128,
        8: ML_Int256,
    }[vector_size]
    return Comparison(TypeCast(Conversion(op_input, precision=conv_format),
                               precision=cast_format),
                      Constant(0, precision=cast_format),
                      specifier=Comparison.Equal,
                      precision=ML_Bool)
Beispiel #11
0
def generate_exp_insertion(optree, result_precision):
    """ generate the expanded version of ExponentInsertion
        with @p optree as input and assuming @p result_precision
        as output precision """
    if result_precision.is_vector_format():
        scalar_format = optree.precision.get_scalar_format()
        vector_size = optree.precision.get_vector_size()
        bias_cst = [-result_precision.get_scalar_format().get_bias()
                    ] * vector_size
        shift_cst = [result_precision.get_scalar_format().get_field_size()
                     ] * vector_size
    else:
        scalar_format = optree.precision
        bias_cst = -result_precision.get_bias()
        shift_cst = result_precision.get_field_size()
    assert is_std_integer_format(scalar_format)
    biased_exponent = Addition(optree,
                               Constant(bias_cst, precision=optree.precision),
                               precision=optree.precision)
    result = BitLogicLeftShift(biased_exponent,
                               Constant(shift_cst, precision=optree.precision),
                               precision=optree.precision)
    return TypeCast(result, precision=result_precision)
Beispiel #12
0
def mantissa_extraction_modifier(optree):
    """ Legalizing a MantissaExtraction node into a sub-graph
        of basic operation """
    init_stage = optree.attributes.get_dyn_attribute("init_stage")
    op = optree.get_input(0)
    tag = optree.get_tag() or "mant_extr"

    op_precision = op.get_precision().get_base_format()
    exp_prec = ML_StdLogicVectorFormat(op_precision.get_exponent_size())
    field_prec = ML_StdLogicVectorFormat(op_precision.get_field_size())

    exp_op = RawExponentExtraction(op,
                                   precision=exp_prec,
                                   init_stage=init_stage,
                                   tag=tag + "_exp_extr")
    field_op = SubSignalSelection(TypeCast(
        op,
        precision=op.get_precision().get_support_format(),
        init_stage=init_stage,
        tag=tag + "_field_cast"),
                                  0,
                                  op_precision.get_field_size() - 1,
                                  precision=field_prec,
                                  init_stage=init_stage,
                                  tag=tag + "_field")
    exp_is_zero = Comparison(exp_op,
                             Constant(op_precision.get_zero_exponent_value(),
                                      precision=exp_prec,
                                      init_stage=init_stage),
                             precision=ML_Bool,
                             specifier=Comparison.Equal,
                             init_stage=init_stage)

    result = mantissa_extraction_modifier_from_fields(op, field_op,
                                                      exp_is_zero)
    forward_attributes(optree, result)
    return result
Beispiel #13
0
 def legalizer(exp_insertion_node):
     optree = exp_insertion_node.get_input(0)
     if result_precision.is_vector_format():
         scalar_format = optree.precision.get_scalar_format()
         vector_size = optree.precision.get_vector_size()
         bias_cst = [-result_precision.get_scalar_format().get_bias()
                     ] * vector_size
         shift_cst = [
             result_precision.get_scalar_format().get_field_size()
         ] * vector_size
     else:
         scalar_format = optree.precision
         bias_cst = -result_precision.get_bias()
         shift_cst = result_precision.get_field_size()
     assert is_std_integer_format(scalar_format)
     biased_exponent = Addition(optree,
                                Constant(bias_cst,
                                         precision=optree.precision),
                                precision=optree.precision)
     result = BitLogicLeftShift(biased_exponent,
                                Constant(shift_cst,
                                         precision=optree.precision),
                                precision=optree.precision)
     return TypeCast(result, precision=result_precision)
Beispiel #14
0
def convert_bit_heap_to_fixed_point(current_bit_heap, signed=False):
    # final propagating sum
    op_index = 0
    op_list = []
    op_statement = Statement()
    while current_bit_heap.max_count() > 0:
        op_size = current_bit_heap.max_index - current_bit_heap.min_index + 1
        op_format = ML_StdLogicVectorFormat(op_size)
        op_reduce = Signal("op_%d" % op_index,
                           precision=op_format,
                           var_type=Variable.Local)

        offset_index = current_bit_heap.min_index

        for index in range(current_bit_heap.min_index,
                           current_bit_heap.max_index + 1):
            out_index = index - offset_index
            bit_list = current_bit_heap.pop_bits(index, 1)
            if len(bit_list) == 0:
                op_statement.push(
                    ReferenceAssign(BitSelection(op_reduce, out_index),
                                    Constant(0, precision=ML_StdLogic)))
            else:
                assert len(bit_list) == 1
                op_statement.push(
                    ReferenceAssign(BitSelection(op_reduce, out_index),
                                    bit_list[0]))

        op_precision = fixed_point(op_size + offset_index,
                                   -offset_index,
                                   signed=signed)
        op_list.append(
            PlaceHolder(TypeCast(op_reduce, precision=op_precision),
                        op_statement))
        op_index += 1
    return op_list, op_statement
Beispiel #15
0
def generate_exp_insertion(optree, result_precision):
    """ generate the expanded version of ExponentInsertion
        with @p optree as input and assuming @p result_precision
        as output precision """
    if result_precision.is_vector_format():
        scalar_format = optree.precision.get_scalar_format()
        vector_size = optree.precision.get_vector_size()
        # determine the working format (for expression)
        work_format = VECTOR_TYPE_MAP[result_precision.get_scalar_format().
                                      get_integer_format()][vector_size]
        bias_cst = [-result_precision.get_scalar_format().get_bias()
                    ] * vector_size
        shift_cst = [result_precision.get_scalar_format().get_field_size()
                     ] * vector_size
    else:
        scalar_format = optree.precision
        work_format = result_precision.get_integer_format()
        bias_cst = -result_precision.get_bias()
        shift_cst = result_precision.get_field_size()
    if not is_std_integer_format(scalar_format):
        Log.report(
            Log.Error,
            "{} should be a std integer format in generate_exp_insertion {} with precision {}",
            scalar_format, optree, result_precision)
    assert is_std_integer_format(scalar_format)
    biased_exponent = Addition(Conversion(optree, precision=work_format) if
                               not optree.precision is work_format else optree,
                               Constant(bias_cst, precision=work_format),
                               precision=work_format)
    result = BitLogicLeftShift(biased_exponent,
                               Constant(
                                   shift_cst,
                                   precision=work_format,
                               ),
                               precision=work_format)
    return TypeCast(result, precision=result_precision)
Beispiel #16
0
    def generic_atan2_generate(self, _vx, vy=None):
        """ if vy is None, compute atan(_vx), else compute atan2(vy / vx) """

        if vy is None:
            # approximation
            # if abs_vx <= 1.0 then atan(abx_vx) is directly approximated
            # if abs_vx > 1.0 then atan(abs_vx) = pi/2 - atan(1 / abs_vx)
            #
            # for vx >= 0, atan(vx) = atan(abs_vx)
            #
            # for vx < 0, atan(vx) = -atan(abs_vx) for vx < 0
            #                      = -pi/2 + atan(1 / abs_vx)
            vx = _vx
            sign_cond = vx < 0
            abs_vx = Select(vx < 0, -vx, vx, tag="abs_vx", debug=debug_multi)
            bound_cond = abs_vx > 1
            inv_abs_vx = 1 / abs_vx

            # condition to select subtraction
            cond = LogicalOr(LogicalAnd(vx < 0, LogicalNot(bound_cond)),
                             vx > 1,
                             tag="cond",
                             debug=debug_multi)

            # reduced argument
            red_vx = Select(bound_cond,
                            inv_abs_vx,
                            abs_vx,
                            tag="red_vx",
                            debug=debug_multi)

            offset = None
        else:
            # bound_cond is True iff Abs(vy / _vx) > 1.0
            bound_cond = Abs(vy) > Abs(_vx)
            bound_cond.set_attributes(tag="bound_cond", debug=debug_multi)
            # vx and vy are of opposite signs
            #sign_cond = (_vx * vy) < 0
            # using cast to int(signed) and bitwise xor
            # to determine if _vx and vy are of opposite sign rapidly
            fast_sign_cond = BitLogicXor(
                TypeCast(_vx, precision=self.precision.get_integer_format()),
                TypeCast(vy, precision=self.precision.get_integer_format()),
                precision=self.precision.get_integer_format()) < 0
            # sign_cond = (_vx * vy) < 0
            sign_cond = fast_sign_cond
            sign_cond.set_attributes(tag="sign_cond", debug=debug_multi)

            # condition to select subtraction
            # TODO: could be accelerated if LogicalXor existed
            slow_cond = LogicalOr(
                LogicalAnd(sign_cond,
                           LogicalNot(bound_cond)),  # 1 < (vy / _vx) < 0
                LogicalAnd(bound_cond,
                           LogicalNot(sign_cond)),  # (vy / _vx) > 1
                tag="cond",
                debug=debug_multi)
            cond = slow_cond

            numerator = Select(bound_cond,
                               _vx,
                               vy,
                               tag="numerator",
                               debug=debug_multi)
            denominator = Select(bound_cond,
                                 vy,
                                 _vx,
                                 tag="denominator",
                                 debug=debug_multi)
            # reduced argument
            red_vx = Abs(numerator) / Abs(denominator)
            red_vx.set_attributes(tag="red_vx", debug=debug_multi)

            offset = Select(
                _vx > 0,
                Constant(0, precision=self.precision),
                # vx < 0
                Select(
                    sign_cond,
                    # vy > 0
                    Constant(sollya.pi, precision=self.precision),
                    Constant(-sollya.pi, precision=self.precision),
                    precision=self.precision),
                precision=self.precision,
                tag="offset")

        approx_fct = sollya.atan(sollya.x)

        if self.method == "piecewise":
            sign_vx = Select(cond,
                             -1,
                             1,
                             precision=self.precision,
                             tag="sign_vx",
                             debug=debug_multi)

            cst_sign = Select(sign_cond,
                              -1,
                              1,
                              precision=self.precision,
                              tag="cst_sign",
                              debug=debug_multi)
            cst = cst_sign * Select(
                bound_cond, sollya.pi / 2, 0, precision=self.precision)
            cst.set_attributes(tag="cst", debug=debug_multi)

            bound_low = 0.0
            bound_high = 1.0
            num_intervals = self.num_sub_intervals
            error_threshold = S2**-(self.precision.get_mantissa_size() + 8)

            approx, eval_error = piecewise_approximation(
                approx_fct,
                red_vx,
                self.precision,
                bound_low=bound_low,
                bound_high=bound_high,
                max_degree=None,
                num_intervals=num_intervals,
                error_threshold=error_threshold,
                odd=True)

            result = cst + sign_vx * approx
            result.set_attributes(tag="result",
                                  precision=self.precision,
                                  debug=debug_multi)

        elif self.method == "single":
            approx_interval = Interval(0, 1.0)
            # determining the degree of the polynomial approximation
            poly_degree_range = sollya.guessdegree(
                approx_fct / sollya.x, approx_interval,
                S2**-(self.precision.get_field_size() + 2))
            poly_degree = int(sollya.sup(poly_degree_range)) + 4
            Log.report(Log.Info, "poly_degree={}".format(poly_degree))

            # arctan is an odd function, so only odd coefficient must be non-zero
            poly_degree_list = list(range(1, poly_degree + 1, 2))
            poly_object, poly_error = Polynomial.build_from_approximation_with_error(
                approx_fct, poly_degree_list,
                [1] + [self.precision.get_sollya_object()] *
                (len(poly_degree_list) - 1), approx_interval)

            odd_predicate = lambda index, _: ((index - 1) % 4 != 0)
            even_predicate = lambda index, _: (index != 1 and
                                               (index - 1) % 4 == 0)

            poly_odd_object = poly_object.sub_poly_cond(odd_predicate,
                                                        offset=1)
            poly_even_object = poly_object.sub_poly_cond(even_predicate,
                                                         offset=1)

            sollya.settings.display = sollya.hexadecimal
            Log.report(Log.Info, "poly_error: {}".format(poly_error))
            Log.report(Log.Info, "poly_odd: {}".format(poly_odd_object))
            Log.report(Log.Info, "poly_even: {}".format(poly_even_object))

            poly_odd = PolynomialSchemeEvaluator.generate_horner_scheme(
                poly_odd_object, abs_vx)
            poly_odd.set_attributes(tag="poly_odd", debug=debug_multi)
            poly_even = PolynomialSchemeEvaluator.generate_horner_scheme(
                poly_even_object, abs_vx)
            poly_even.set_attributes(tag="poly_even", debug=debug_multi)
            exact_sum = poly_odd + poly_even
            exact_sum.set_attributes(tag="exact_sum", debug=debug_multi)

            # poly_even should be (1 + poly_even)
            result = vx + vx * exact_sum
            result.set_attributes(tag="result",
                                  precision=self.precision,
                                  debug=debug_multi)

        else:
            raise NotImplementedError

        if not offset is None:
            result = result + offset

        std_scheme = Statement(Return(result))
        scheme = std_scheme

        return scheme
Beispiel #17
0
    def generate_auto_test(self,
                           test_num=10,
                           test_range=Interval(-1.0, 1.0),
                           debug=False,
                           time_step=10):
        """ time_step: duration of a stage (in ns) """
        # instanciating tested component
        # map of input_tag -> input_signal and output_tag -> output_signal
        io_map = {}
        # map of input_tag -> input_signal, excludind commodity signals
        # (e.g. clock and reset)
        input_signals = {}
        # map of output_tag -> output_signal
        output_signals = {}
        # excluding clock and reset signals from argument list
        # reduced_arg_list = [input_port for input_port in self.implementation.get_arg_list() if not input_port.get_tag() in ["clk", "reset"]]
        reduced_arg_list = self.implementation.get_arg_list()
        for input_port in reduced_arg_list:
            input_tag = input_port.get_tag()
            input_signal = Signal(input_tag + "_i",
                                  precision=input_port.get_precision(),
                                  var_type=Signal.Local)
            io_map[input_tag] = input_signal
            if not input_tag in ["clk", "reset"]:
                input_signals[input_tag] = input_signal
        for output_port in self.implementation.get_output_port():
            output_tag = output_port.get_tag()
            output_signal = Signal(output_tag + "_o",
                                   precision=output_port.get_precision(),
                                   var_type=Signal.Local)
            io_map[output_tag] = output_signal
            output_signals[output_tag] = output_signal

        # building list of test cases
        tc_list = []

        self_component = self.implementation.get_component_object()
        self_instance = self_component(io_map=io_map, tag="tested_entity")
        test_statement = Statement()

        # initializing random test case generator
        self.init_test_generator()

        # Appending standard test cases if required
        if self.auto_test_std:
            tc_list += self.standard_test_cases

        for i in range(test_num):
            input_values = self.generate_test_case(input_signals, io_map, i,
                                                   test_range)
            tc_list.append((input_values, None))

        def compute_results(tc):
            """ update test case with output values if required """
            input_values, output_values = tc
            if output_values is None:
                return input_values, self.numeric_emulate(input_values)
            else:
                return tc

        # filling output values
        tc_list = [compute_results(tc) for tc in tc_list]

        for input_values, output_values in tc_list:
            input_msg = ""

            # Adding input setting
            for input_tag in input_values:
                input_signal = io_map[input_tag]
                # FIXME: correct value generation depending on signal precision
                input_value = input_values[input_tag]
                test_statement.add(
                    ReferenceAssign(
                        input_signal,
                        Constant(input_value,
                                 precision=input_signal.get_precision())))
                value_msg = input_signal.get_precision().get_cst(
                    input_value, language=VHDL_Code).replace('"', "'")
                value_msg += " / " + hex(input_signal.get_precision(
                ).get_base_format().get_integer_coding(input_value))
                input_msg += " {}={} ".format(input_tag, value_msg)
            test_statement.add(Wait(time_step * self.stage_num))
            # Adding output value comparison
            for output_tag in output_signals:
                output_signal = output_signals[output_tag]
                output_value = Constant(
                    output_values[output_tag],
                    precision=output_signal.get_precision())
                output_precision = output_signal.get_precision()
                expected_dec = output_precision.get_cst(
                    output_values[output_tag],
                    language=VHDL_Code).replace('"', "'")
                expected_hex = " / " + hex(
                    output_precision.get_base_format().get_integer_coding(
                        output_values[output_tag]))
                value_msg = "{} / {}".format(expected_dec, expected_hex)

                test_pass_cond = Comparison(output_signal,
                                            output_value,
                                            specifier=Comparison.Equal,
                                            precision=ML_Bool)

                test_statement.add(
                    ConditionBlock(
                        LogicalNot(test_pass_cond, precision=ML_Bool),
                        Report(
                            Concatenation(
                                " result for {}: ".format(output_tag),
                                Conversion(TypeCast(
                                    output_signal,
                                    precision=ML_StdLogicVectorFormat(
                                        output_signal.get_precision(
                                        ).get_bit_size())),
                                           precision=ML_String),
                                precision=ML_String))))
                test_statement.add(
                    Assert(
                        test_pass_cond,
                        "\"unexpected value for inputs {input_msg}, output {output_tag}, expecting {value_msg}, got: \""
                        .format(input_msg=input_msg,
                                output_tag=output_tag,
                                value_msg=value_msg),
                        severity=Assert.Failure))

        testbench = CodeEntity("testbench")
        test_process = Process(
            test_statement,
            # end of test
            Assert(Constant(0, precision=ML_Bool),
                   " \"end of test, no error encountered \"",
                   severity=Assert.Failure))

        testbench_scheme = Statement(self_instance, test_process)

        if self.pipelined:
            half_time_step = time_step / 2
            assert (half_time_step * 2) == time_step
            # adding clock process for pipelined bench
            clk_process = Process(
                Statement(
                    ReferenceAssign(io_map["clk"],
                                    Constant(1, precision=ML_StdLogic)),
                    Wait(half_time_step),
                    ReferenceAssign(io_map["clk"],
                                    Constant(0, precision=ML_StdLogic)),
                    Wait(half_time_step),
                ))
            testbench_scheme.push(clk_process)

        testbench.add_process(testbench_scheme)

        return [testbench]
Beispiel #18
0
    def generate_scheme(self):
        int_precision = self.precision.get_integer_format()
        # We wish to compute vx / vy
        vx = self.implementation.add_input_variable("x", self.precision, interval=self.input_intervals[0])
        vy = self.implementation.add_input_variable("y", self.precision, interval=self.input_intervals[1])
        if self.mode is FULL_MODE:
            quo = self.implementation.add_input_variable("quo", ML_Pointer_Format(int_precision))

        i = Variable("i", precision=int_precision, var_type=Variable.Local)
        q = Variable("q", precision=int_precision, var_type=Variable.Local)

        CI = lambda v: Constant(v, precision=int_precision)
        CF = lambda v: Constant(v, precision=self.precision)

        vx_subnormal = Test(vx, specifier=Test.IsSubnormal, tag="vx_subnormal")
        vy_subnormal = Test(vy, specifier=Test.IsSubnormal, tag="vy_subnormal")

        DELTA_EXP = self.precision.get_mantissa_size()
        scale_factor = Constant(2.0**DELTA_EXP, precision=self.precision)
        inv_scale_factor = Constant(2.0**-DELTA_EXP, precision=self.precision)

        normalized_vx = Select(vx_subnormal, vx * scale_factor, vx, tag="scaled_vx")
        normalized_vy = Select(vy_subnormal, vy * scale_factor, vy, tag="scaled_vy")

        real_ex = ExponentExtraction(vx, tag="real_ex", precision=int_precision)
        real_ey = ExponentExtraction(vy, tag="real_ey", precision=int_precision)

        # if real_e<x/y> is +1023 then it may Overflow in -real_ex for ExponentInsertion
        # which only supports downto -1022 before falling into subnormal numbers (which are
        # not supported by ExponentInsertion)
        real_ex_h0 = real_ex / 2
        real_ex_h1 = real_ex - real_ex_h0

        real_ey_h0 = real_ey / 2
        real_ey_h1 = real_ey - real_ey_h0

        EI = lambda v: ExponentInsertion(v, precision=self.precision)

        mx = Abs((vx * EI(-real_ex_h0)) * EI(-real_ex_h1), tag="mx")
        my = Abs((vy * EI(-real_ey_h0)) * EI(-real_ey_h1), tag="pre_my")

        # scale_ey is used to regain the unscaling of mx in the first loop
        # if real_ey >= real_ex, the first loop is never executed
        # so a different scaling is required
        mx_unscaling = Select(real_ey < real_ex, real_ey, real_ex)
        ey_half0 = (mx_unscaling) / 2
        ey_half1 = (mx_unscaling) - ey_half0

        scale_ey_half0 = ExponentInsertion(ey_half0, precision=self.precision, tag="scale_ey_half0")
        scale_ey_half1 = ExponentInsertion(ey_half1, precision=self.precision, tag="scale_ey_half1")

        # if only vy is subnormal we want to normalize it
        #normal_cond = LogicalAnd(vy_subnormal, LogicalNot(vx_subnormal))
        normal_cond = vy_subnormal #LogicalAnd(vy_subnormal, LogicalNot(vx_subnormal))
        my = Select(normal_cond, Abs(MantissaExtraction(vy * scale_factor)), my, tag="my")


        # vx / vy = vx * 2^-ex * 2^(ex-ey) / (vy * 2^-ey)
        # vx % vy

        post_mx = Variable("post_mx", precision=self.precision, var_type=Variable.Local)

        # scaling for half comparison
        VY_SCALING = Select(vy_subnormal, 1.0, 0.5, precision=self.precision)
        VX_SCALING = Select(vy_subnormal, 2.0, 1.0, precision=self.precision)

        def LogicalXor(a, b):
            return LogicalOr(LogicalAnd(a, LogicalNot(b)), LogicalAnd(LogicalNot(a), b))

        rem_sign = Select(vx < 0, CF(-1), CF(1), precision=self.precision, tag="rem_sign")
        quo_sign = Select(LogicalXor(vx <0, vy < 0), CI(-1), CI(1), precision=int_precision, tag="quo_sign")

        loop_watchdog = Variable("loop_watchdog", precision=ML_Int32, var_type=Variable.Local)

        loop = Statement(
            real_ex, real_ey, mx, my, loop_watchdog,
            ReferenceAssign(loop_watchdog, 5000),
            ReferenceAssign(q, CI(0)),
            Loop(
                ReferenceAssign(i, CI(0)), i < (real_ex - real_ey),
                Statement(
                    ReferenceAssign(i, i+CI(1)),
                    ReferenceAssign(q, ((q << 1) + Select(mx >= my, CI(1), CI(0))).modify_attributes(tag="step1_q")),
                    ReferenceAssign(mx, (CF(2) * (mx - Select(mx >= my, my, CF(0)))).modify_attributes(tag="step1_mx")),
                    # loop watchdog
                    ReferenceAssign(loop_watchdog, loop_watchdog - 1),
                    ConditionBlock(loop_watchdog < 0, Return(-1)),
                ),
            ),
            # unscaling remainder
            ReferenceAssign(mx, ((mx * scale_ey_half0) * scale_ey_half1).modify_attributes(tag="scaled_rem")),
            ReferenceAssign(my, ((my * scale_ey_half0) * scale_ey_half1).modify_attributes(tag="scaled_rem_my")),
            Loop(
                Statement(), (my > Abs(vy)),
                Statement(
                    ReferenceAssign(q, ((q << 1) + Select(mx >= Abs(my), CI(1), CI(0))).modify_attributes(tag="step2_q")),
                    ReferenceAssign(mx, (mx - Select(mx >= Abs(my), Abs(my), CF(0))).modify_attributes(tag="step2_mx")),
                    ReferenceAssign(my, (my * 0.5).modify_attributes(tag="step2_my")),
                    # loop watchdog
                    ReferenceAssign(loop_watchdog, loop_watchdog - 1),
                    ConditionBlock(loop_watchdog < 0, Return(-1)),
                ),
            ),
            ReferenceAssign(q, q << 1),
            Loop(
                ReferenceAssign(i, CI(0)), mx > Abs(vy),
                Statement(
                    ReferenceAssign(q, (q + Select(mx > Abs(vy), CI(1), CI(0))).modify_attributes(tag="step3_q")),
                    ReferenceAssign(mx, (mx - Select(mx > Abs(vy), Abs(vy), CF(0))).modify_attributes(tag="step3_mx")),
                    # loop watchdog
                    ReferenceAssign(loop_watchdog, loop_watchdog - 1),
                    ConditionBlock(loop_watchdog < 0, Return(-1)),
                ),
            ),
            ReferenceAssign(q, q + Select(mx >= Abs(vy), CI(1), CI(0))),
            ReferenceAssign(mx, (mx - Select(mx >= Abs(vy), Abs(vy), CF(0))).modify_attributes(tag="pre_half_mx")),
            ConditionBlock(
                # actual comparison is mx > | abs(vy * 0.5) | to avoid rounding effect when
                # vy is subnormal we mulitply both side by 2.0**60
                ((mx * VX_SCALING) > Abs(vy * VY_SCALING)).modify_attributes(tag="half_test"),
                Statement(
                    ReferenceAssign(q, q + CI(1)),
                    ReferenceAssign(mx, (mx - Abs(vy)))
                )
            ),
            ConditionBlock(
                # if the remainder is exactly half the dividend
                # we need to make sure the quotient is even
                LogicalAnd(
                    Equal(mx * VX_SCALING, Abs(vy * VY_SCALING)),
                    Equal(Modulo(q, CI(2)), CI(1)),
                ),
                Statement(
                    ReferenceAssign(q, q + CI(1)),
                    ReferenceAssign(mx, (mx - Abs(vy)))
                )
            ),
            ReferenceAssign(mx, rem_sign * mx),
            ReferenceAssign(q,
                Modulo(TypeCast(q, precision=self.precision.get_unsigned_integer_format()), Constant(2**self.quotient_size, precision=self.precision.get_unsigned_integer_format()), tag="mod_q")
            ),
            ReferenceAssign(q, quo_sign * q),
        )

        # NOTES: Warning QuotientReturn must always preceeds RemainderReturn
        if self.mode is QUOTIENT_MODE:
            #
            QuotientReturn = Return
            RemainderReturn = lambda _: Statement()
        elif self.mode is REMAINDER_MODE:
            QuotientReturn = lambda _: Statement()
            RemainderReturn = Return
        elif self.mode is FULL_MODE:
            QuotientReturn = lambda v: ReferenceAssign(Dereference(quo, precision=int_precision), v) 
            RemainderReturn = Return
        else:
            raise NotImplemented

        # quotient invalid value
        QUO_INVALID_VALUE = 0

        mod_scheme = Statement(
            # x or y is NaN, a NaN is returned
            ConditionBlock(
                LogicalOr(Test(vx, specifier=Test.IsNaN), Test(vy, specifier=Test.IsNaN)),
                Statement(
                    QuotientReturn(QUO_INVALID_VALUE),
                    RemainderReturn(FP_QNaN(self.precision))
                ),
            ),
            #
            ConditionBlock(
                Test(vy, specifier=Test.IsZero),
                Statement(
                    QuotientReturn(QUO_INVALID_VALUE),
                    RemainderReturn(FP_QNaN(self.precision))
                ),
            ),
            ConditionBlock(
                Test(vx, specifier=Test.IsZero),
                Statement(
                    QuotientReturn(0),
                    RemainderReturn(vx)
                ),
            ),
            ConditionBlock(
                Test(vx, specifier=Test.IsInfty),
                Statement(
                    QuotientReturn(QUO_INVALID_VALUE),
                    RemainderReturn(FP_QNaN(self.precision))
                )
            ),
            ConditionBlock(
                Test(vy, specifier=Test.IsInfty),
                Statement(
                    QuotientReturn(0),
                    RemainderReturn(vx),
                )
            ),
            ConditionBlock(
                Abs(vx) < Abs(vy * 0.5),
                Statement(
                    QuotientReturn(0),
                    RemainderReturn(vx),
                )
            ),
            ConditionBlock(
                Equal(vx, vy),
                Statement(
                    QuotientReturn(1),
                    # 0 with the same sign as x
                    RemainderReturn(vx - vx),
                ),
            ),
            ConditionBlock(
                Equal(vx, -vy),
                Statement(
                    # quotient is -1
                    QuotientReturn(-1),
                    # 0 with the same sign as x
                    RemainderReturn(vx - vx),
                ),
            ),
            loop,
            QuotientReturn(q),
            RemainderReturn(mx),
        )

        quo_scheme = Statement(
            # x or y is NaN, a NaN is returned
            ConditionBlock(
                LogicalOr(Test(vx, specifier=Test.IsNaN), Test(vy, specifier=Test.IsNaN)),
                Return(QUO_INVALID_VALUE),
            ),
            #
            ConditionBlock(
                Test(vy, specifier=Test.IsZero),
                Return(QUO_INVALID_VALUE),
            ),
            ConditionBlock(
                Test(vx, specifier=Test.IsZero),
                Return(0),
            ),
            ConditionBlock(
                Test(vx, specifier=Test.IsInfty),
                Return(QUO_INVALID_VALUE),
            ),
            ConditionBlock(
                Test(vy, specifier=Test.IsInfty),
                Return(QUO_INVALID_VALUE),
            ),
            ConditionBlock(
                Abs(vx) < Abs(vy * 0.5),
                Return(0),
            ),
            ConditionBlock(
                Equal(vx, vy),
                Return(1),
            ),
            ConditionBlock(
                Equal(vx, -vy),
                Return(-1),
            ),
            loop,
            Return(q),

        )

        return mod_scheme
Beispiel #19
0
    def generate_scheme(self):
        # declaring CodeFunction and retrieving input variable
        vx = self.implementation.add_input_variable("x", self.precision)

        table_size_log = self.table_size_log
        integer_size = 31
        integer_precision = ML_Int32

        max_bound = sup(abs(self.input_intervals[0]))
        max_bound_log = int(ceil(log2(max_bound)))
        Log.report(Log.Info, "max_bound_log=%s " % max_bound_log)
        scaling_power = integer_size - max_bound_log
        Log.report(Log.Info, "scaling power: %s " % scaling_power)

        storage_precision = ML_Custom_FixedPoint_Format(1, 30, signed=True)

        Log.report(Log.Info, "tabulating cosine and sine")
        # cosine and sine fused table
        fused_table = ML_NewTable(
            dimensions=[2**table_size_log, 2],
            storage_precision=storage_precision,
            tag="fast_lib_shared_table")  # self.uniquify_name("cossin_table"))
        # filling table
        for i in range(2**table_size_log):
            local_x = i / S2**table_size_log * S2**max_bound_log

            cos_local = cos(
                local_x
            )  # nearestint(cos(local_x) * S2**storage_precision.get_frac_size())

            sin_local = sin(
                local_x
            )  # nearestint(sin(local_x) * S2**storage_precision.get_frac_size())

            fused_table[i][0] = cos_local
            fused_table[i][1] = sin_local

        # argument reduction evaluation scheme
        # scaling_factor = Constant(S2**scaling_power, precision = self.precision)

        red_vx_precision = ML_Custom_FixedPoint_Format(31 - scaling_power,
                                                       scaling_power,
                                                       signed=True)
        Log.report(
            Log.Verbose, "red_vx_precision.get_c_bit_size()=%d" %
            red_vx_precision.get_c_bit_size())
        # red_vx = NearestInteger(vx * scaling_factor, precision = integer_precision)
        red_vx = Conversion(vx,
                            precision=red_vx_precision,
                            tag="red_vx",
                            debug=debug_fixed32)

        computation_precision = red_vx_precision  # self.precision
        output_precision = self.get_output_precision()
        Log.report(Log.Info,
                   "computation_precision is %s" % computation_precision)
        Log.report(Log.Info, "storage_precision     is %s" % storage_precision)
        Log.report(Log.Info, "output_precision      is %s" % output_precision)

        hi_mask_value = 2**32 - 2**(32 - table_size_log - 1)
        hi_mask = Constant(hi_mask_value, precision=ML_Int32)
        Log.report(Log.Info, "hi_mask=0x%x" % hi_mask_value)

        red_vx_hi_int = BitLogicAnd(TypeCast(red_vx, precision=ML_Int32),
                                    hi_mask,
                                    precision=ML_Int32,
                                    tag="red_vx_hi_int",
                                    debug=debugd)
        red_vx_hi = TypeCast(red_vx_hi_int,
                             precision=red_vx_precision,
                             tag="red_vx_hi",
                             debug=debug_fixed32)
        red_vx_lo = red_vx - red_vx_hi
        red_vx_lo.set_attributes(precision=red_vx_precision,
                                 tag="red_vx_lo",
                                 debug=debug_fixed32)
        table_index = BitLogicRightShift(TypeCast(red_vx, precision=ML_Int32),
                                         scaling_power -
                                         (table_size_log - max_bound_log),
                                         precision=ML_Int32,
                                         tag="table_index",
                                         debug=debugd)

        tabulated_cos = TableLoad(fused_table,
                                  table_index,
                                  0,
                                  tag="tab_cos",
                                  precision=storage_precision,
                                  debug=debug_fixed32)
        tabulated_sin = TableLoad(fused_table,
                                  table_index,
                                  1,
                                  tag="tab_sin",
                                  precision=storage_precision,
                                  debug=debug_fixed32)

        error_function = lambda p, f, ai, mod, t: dirtyinfnorm(f - p, ai)

        Log.report(Log.Info, "building polynomial approximation for cosine")
        # cosine polynomial approximation
        poly_interval = Interval(0, S2**(max_bound_log - table_size_log))
        Log.report(Log.Info, "poly_interval=%s " % poly_interval)
        cos_poly_degree = 2  # int(sup(guessdegree(cos(x), poly_interval, accuracy_goal)))

        Log.report(Log.Verbose, "cosine polynomial approximation")
        cos_poly_object, cos_approx_error = Polynomial.build_from_approximation_with_error(
            cos(sollya.x), [0, 2],
            [0] + [computation_precision.get_bit_size()],
            poly_interval,
            sollya.absolute,
            error_function=error_function)
        #cos_eval_scheme = PolynomialSchemeEvaluator.generate_horner_scheme(cos_poly_object, red_vx_lo, unified_precision = computation_precision)
        Log.report(Log.Info, "cos_approx_error=%e" % cos_approx_error)
        cos_coeff_list = cos_poly_object.get_ordered_coeff_list()
        coeff_C0 = cos_coeff_list[0][1]
        coeff_C2 = Constant(cos_coeff_list[1][1],
                            precision=ML_Custom_FixedPoint_Format(-1,
                                                                  32,
                                                                  signed=True))

        Log.report(Log.Info, "building polynomial approximation for sine")

        # sine polynomial approximation
        sin_poly_degree = 2  # int(sup(guessdegree(sin(x)/x, poly_interval, accuracy_goal)))
        Log.report(Log.Info, "sine poly degree: %e" % sin_poly_degree)
        Log.report(Log.Verbose, "sine polynomial approximation")
        sin_poly_object, sin_approx_error = Polynomial.build_from_approximation_with_error(
            sin(sollya.x) / sollya.x, [0, 2], [0] +
            [computation_precision.get_bit_size()] * (sin_poly_degree + 1),
            poly_interval,
            sollya.absolute,
            error_function=error_function)
        sin_coeff_list = sin_poly_object.get_ordered_coeff_list()
        coeff_S0 = sin_coeff_list[0][1]
        coeff_S2 = Constant(sin_coeff_list[1][1],
                            precision=ML_Custom_FixedPoint_Format(-1,
                                                                  32,
                                                                  signed=True))

        # scheme selection between sine and cosine
        if self.cos_output:
            scheme = self.generate_cos_scheme(computation_precision,
                                              tabulated_cos, tabulated_sin,
                                              coeff_S2, coeff_C2, red_vx_lo)
        else:
            scheme = self.generate_sin_scheme(computation_precision,
                                              tabulated_cos, tabulated_sin,
                                              coeff_S2, coeff_C2, red_vx_lo)

        result = Conversion(scheme, precision=self.get_output_precision())

        Log.report(
            Log.Verbose, "result operation tree :\n %s " % result.get_str(
                display_precision=True, depth=None, memoization_map={}))
        scheme = Statement(Return(result))

        return scheme