Пример #1
0
 def subdivide(op, split_index_list):
     """ subdivide op node in len(split_index_list) + 1 slices
         [0 to split_index_list[0]],
         [split_index_list[0] + 1: split_index_list[1]], .... """
     n = op.get_precision().get_bit_size()
     sub_list = []
     lo_index = 0
     hi_index = None
     for s in split_index_list:
         if lo_index >= n:
             break
         hi_index = min(s, n - 1)
         local_slice = SubSignalSelection(
             op, lo_index, hi_index
         )  #, precision=fixed_point(hi_index - lo_index + 1, 0, signed=False))
         sub_list.append(local_slice)
         # key invariant to allow adding multiple subdivision together:
         # the LSB weight must be uniform
         lo_index = s + 1
     if hi_index < n - 1:
         local_slice = SubSignalSelection(op, lo_index, n - 1)
         sub_list.append(local_slice)
     # padding list
     while len(sub_list) < len(split_index_list) + 1:
         sub_list.append(Constant(0))
     return sub_list
Пример #2
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
Пример #3
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))
Пример #4
0
    def simplify_node(self, node):
        """ return the simplified version of @p node when possible
            else the node itself """
        result = node

        if node in self.memoization_map:
            return self.memoization_map[node]
        elif isinstance(node, SubSignalSelection):
            op_input = self.simplify_node(node.get_input(0))
            lo_index = evaluate_cst_graph(node.get_input(1))
            hi_index = evaluate_cst_graph(node.get_input(2))
            if isinstance(op_input, SubSignalSelection):
                parent_input = self.simplify_node(op_input.get_input(0))
                parent_lo_index = evaluate_cst_graph(op_input.get_input(1))
                new_node = SubSignalSelection(parent_input,
                                              parent_lo_index + lo_index,
                                              parent_lo_index + hi_index)
                forward_attributes(node, new_node)
                result = new_node

        elif isinstance(node, VectorElementSelection):
            op_input = self.simplify_node(node.get_input(0))
            op_index = evaluate_cst_graph(node.get_input(1))
            if isinstance(op_input, SubSignalSelection):
                parent_input = op_input.get_input(0)
                base_index = evaluate_cst_graph(op_input.get_input(1))
                new_node = BitSelection(parent_input, base_index + op_index)
                forward_attributes(node, new_node)
                result = new_node
            elif isinstance(op_input, Constant):
                offset = 0
                if is_fixed_point(op_input.get_precision()):
                    offset = -op_input.get_precision().get_frac_size()
                bit_value = (op_input.get_value() >> (op_index + offset)) & 1
                new_node = Constant(bit_value, precision=node.get_precision())
                forward_attributes(node, new_node)
                result = new_node
        else:
            result = node

        Log.report(LOG_VERBOSE_SIMPLIFY_RTL, "Simplifying {} to {}", node,
                   result)

        self.memoization_map[node] = result
        return result
Пример #5
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
Пример #6
0
def booth_radix4_multiply(lhs, rhs, pos_bit_heap, neg_bit_heap):
    """ Compute the multiplication @p lhs x @p rhs using radix 4 Booth
        recoding and drop the generated partial product in @p
        pos_bit_heap and @p neg_bit_heap based on their sign """
    # booth recoded partial product for n-th digit
    # is based on digit from n-1 to n+1
    #    (n+1) | (n) | (n-1) |  PP  |
    #    ------|-----|-------|------|
    #      0   |  0  |   0   |  +0  |
    #      0   |  0  |   1   |  +X  |
    #      0   |  1  |   0   |  +X  |
    #      0   |  1  |   1   |  +2x |
    #      1   |  0  |   0   |  -2X |
    #      1   |  0  |   1   |  -X  |
    #      1   |  1  |   0   |  -X  |
    #      1   |  1  |   1   |  +0  |
    #    ------|-----|-------|------|
    assert lhs.get_precision().get_bit_size() >= 2

    # lhs is the recoded operand
    # RECODING DIGITS
    # first recoded digit is padded right by 0
    first_digit = Concatenation(SubSignalSelection(
        lhs, 0, 1, precision=ML_StdLogicVectorFormat(2)),
                                Constant(0, precision=ML_StdLogic),
                                precision=ML_StdLogicVectorFormat(3),
                                debug=debug_std,
                                tag="booth_digit_0")
    digit_list = [(first_digit, 0)]

    for digit_index in range(2, lhs.get_precision().get_bit_size(), 2):
        if digit_index + 1 < lhs.get_precision().get_bit_size():
            # digits exist completely in lhs
            digit = SubSignalSelection(lhs,
                                       digit_index - 1,
                                       digit_index + 1,
                                       tag="booth_digit_%d" % digit_index,
                                       debug=debug_std)
        else:
            # MSB padding required
            sign_ext = Constant(0, precision=ML_StdLogic) if not (
                lhs.get_precision().get_signed()) else BitSelection(
                    lhs,
                    lhs.get_precision().get_bit_size() - 1)
            digit = Concatenation(sign_ext,
                                  SubSignalSelection(lhs, digit_index - 1,
                                                     digit_index),
                                  precision=ML_StdLogicVectorFormat(3),
                                  debug=debug_std,
                                  tag="booth_digit_%d" % digit_index)
        digit_list.append((digit, digit_index))
    # if lhs size is a mutiple of two and it is unsigned
    # than an extra digit must be generated to ensure a positive result
    if lhs.get_precision().get_bit_size() % 2 == 0 and not (
            lhs.get_precision().get_signed()):
        digit_index = lhs.get_precision().get_bit_size() - 1
        digit = Concatenation(Constant(0,
                                       precision=ML_StdLogicVectorFormat(2)),
                              BitSelection(lhs, digit_index),
                              precision=ML_StdLogicVectorFormat(3),
                              debug=debug_std,
                              tag="booth_digit_%d" % (digit_index + 1))
        digit_list.append((digit, digit_index + 1))

    def DCV(value):
        """ Digit Constante Value """
        return Constant(value, precision=ML_StdLogicVectorFormat(3))

    # PARTIAL PRODUCT GENERATION
    # Radix-4 booth recoding requires the following Partial Products
    # -2.rhs, -rhs, 0, rhs and 2.rhs
    # Negative PP are obtained by 1's complement of the value correctly shifted
    # adding a positive one to the LSB (inserted separately) and assuming
    # MSB digit has a negative weight
    for digit, index in digit_list:
        pp_zero = LogicalOr(Equal(digit, DCV(0), precision=ML_Bool),
                            Equal(digit, DCV(7), precision=ML_Bool),
                            precision=ML_Bool)
        pp_shifted = LogicalOr(Equal(digit, DCV(3), precision=ML_Bool),
                               Equal(digit, DCV(4), precision=ML_Bool),
                               precision=ML_Bool)
        # excluding zero case
        pp_neg_bit = BitSelection(digit, 2)
        pp_neg = equal_to(pp_neg_bit, 1)
        pp_neg_lsb_carryin = Select(LogicalAnd(pp_neg, LogicalNot(pp_zero)),
                                    Constant(1, precision=ML_StdLogic),
                                    Constant(0, precision=ML_StdLogic),
                                    tag="pp_%d_neg_lsb_carryin" % index,
                                    debug=debug_std)

        # LSB digit
        lsb_pp_digit = Select(pp_shifted,
                              Constant(0, precision=ML_StdLogic),
                              BitSelection(rhs, 0),
                              precision=ML_StdLogic)
        lsb_local_pp = Select(pp_zero,
                              Constant(0, precision=ML_StdLogic),
                              Select(pp_neg,
                                     BitLogicNegate(lsb_pp_digit),
                                     lsb_pp_digit,
                                     precision=ML_StdLogic),
                              debug=debug_std,
                              tag="lsb_local_pp_%d" % index,
                              precision=ML_StdLogic)
        pos_bit_heap.insert_bit(index, lsb_local_pp)
        pos_bit_heap.insert_bit(index, pp_neg_lsb_carryin)

        # other digits
        rhs_size = rhs.get_precision().get_bit_size()
        for k in range(1, rhs_size):
            pp_digit = Select(pp_shifted,
                              BitSelection(rhs, k - 1),
                              BitSelection(rhs, k),
                              precision=ML_StdLogic)
            local_pp = Select(pp_zero,
                              Constant(0, precision=ML_StdLogic),
                              Select(pp_neg,
                                     BitLogicNegate(pp_digit),
                                     pp_digit,
                                     precision=ML_StdLogic),
                              debug=debug_std,
                              tag="local_pp_%d_%d" % (index, k),
                              precision=ML_StdLogic)
            pos_bit_heap.insert_bit(index + k, local_pp)
        # MSB digit
        msb_pp_digit = pp_digit = Select(
            pp_shifted,
            BitSelection(rhs, rhs_size - 1),
            # TODO: fix for signed rhs
            Constant(0, precision=ML_StdLogic)
            if not (rhs.get_precision().get_signed()) else BitSelection(
                rhs, rhs_size - 1),
            precision=ML_StdLogic)
        msb_pp = Select(pp_zero,
                        Constant(0, precision=ML_StdLogic),
                        Select(pp_neg,
                               BitLogicNegate(msb_pp_digit),
                               msb_pp_digit,
                               precision=ML_StdLogic),
                        debug=debug_std,
                        tag="msb_pp_%d" % (index),
                        precision=ML_StdLogic)
        if rhs.get_precision().get_signed():
            neg_bit_heap.insert_bit(index + rhs_size, msb_pp)
        else:
            pos_bit_heap.insert_bit(index + rhs_size, msb_pp)
            # MSB negative digit,
            # 'rhs_size + index) is the position of the MSB digit of rhs shifted by 1
            # we add +1 to get to the sign position
            neg_bit_heap.insert_bit(index + rhs_size + 1, pp_neg_lsb_carryin)
Пример #7
0
        def rec_add(op_x, op_y, level=0, lower_limit=1):
            print("calling rec_add")
            n_x = op_x.get_precision().get_bit_size()
            n_y = op_y.get_precision().get_bit_size()
            n = max(n_x, n_y)
            if n <= lower_limit:
                if n == 1:
                    # end of recursion
                    def LSB(op):
                        return BitSelection(op, 0)

                    bit_x = LSB(op_x)
                    bit_y = LSB(op_y)
                    return (
                        # add
                        Conversion(BitLogicXor(bit_x,
                                               bit_y,
                                               precision=ML_StdLogic),
                                   precision=ML_StdLogicVectorFormat(1)),
                        # add + 1
                        Conversion(BitLogicNegate(BitLogicXor(
                            bit_x, bit_y, precision=ML_StdLogic),
                                                  precision=ML_StdLogic),
                                   precision=ML_StdLogicVectorFormat(1)),
                        # generate
                        BitLogicAnd(bit_x, bit_y, precision=ML_StdLogic),
                        # propagate
                        BitLogicXor(bit_x, bit_y, precision=ML_StdLogic))
                else:
                    numeric_x = TypeCast(op_x,
                                         precision=fixed_point(n_x,
                                                               0,
                                                               signed=False))
                    numeric_y = TypeCast(op_y,
                                         precision=fixed_point(n_y,
                                                               0,
                                                               signed=False))
                    pre_add = numeric_x + numeric_y
                    pre_addp1 = pre_add + 1
                    add = SubSignalSelection(pre_add, 0, n - 1)
                    addp1 = SubSignalSelection(pre_addp1, 0, n - 1)
                    generate = BitSelection(pre_add, n)
                    # TODO/FIXME: padd when op_x's size does not match op_y' size
                    bitwise_xor = BitLogicXor(
                        op_x, op_y, precision=ML_StdLogicVectorFormat(n))
                    op_list = [BitSelection(bitwise_xor, i) for i in range(n)]
                    propagate = logical_reduce(op_list,
                                               op_ctor=BitLogicAnd,
                                               precision=ML_StdLogic)

                    return add, addp1, generate, propagate

            half_n = int(n / 2)

            def subdivide(op, split_index_list):
                """ subdivide op node in len(split_index_list) + 1 slices
                    [0 to split_index_list[0]],
                    [split_index_list[0] + 1: split_index_list[1]], .... """
                n = op.get_precision().get_bit_size()
                sub_list = []
                lo_index = 0
                hi_index = None
                for s in split_index_list:
                    if lo_index >= n:
                        break
                    hi_index = min(s, n - 1)
                    local_slice = SubSignalSelection(
                        op, lo_index, hi_index
                    )  #, precision=fixed_point(hi_index - lo_index + 1, 0, signed=False))
                    sub_list.append(local_slice)
                    # key invariant to allow adding multiple subdivision together:
                    # the LSB weight must be uniform
                    lo_index = s + 1
                if hi_index < n - 1:
                    local_slice = SubSignalSelection(op, lo_index, n - 1)
                    sub_list.append(local_slice)
                # padding list
                while len(sub_list) < len(split_index_list) + 1:
                    sub_list.append(Constant(0))
                return sub_list

            x_slices = subdivide(op_x, [half_n - 1])
            y_slices = subdivide(op_y, [half_n - 1])

            # list of (x + y), (x + y + 1), generate, propagate
            add_slices = [
                rec_add(sub_x, sub_y, level=level + 1, lower_limit=lower_limit)
                for sub_x, sub_y in zip(x_slices, y_slices)
            ]

            NUM_SLICES = len(add_slices)

            def tree_reduce(gen_list, prop_list):
                return LogicalOr(
                    gen_list[-1],
                    LogicalAnd(prop_list[-1],
                               tree_reduce(gen_list[:-1], prop_list[:-1])))

            add_list = [op[0] for op in add_slices]
            addp1_list = [op[1] for op in add_slices]
            generate_list = [op[2] for op in add_slices]
            propagate_list = [op[3] for op in add_slices]

            carry_propagate = [propagate_list[0]]
            carry_generate = [generate_list[0]]
            add_result = [add_list[0]]
            addp1_result = [addp1_list[0]]
            for i in range(1, NUM_SLICES):

                def sub_name(prefix, index):
                    return "%s_%d_%d" % (prefix, level, index)

                carry_propagate.append(
                    BitLogicAnd(propagate_list[i],
                                carry_propagate[i - 1],
                                tag=sub_name("carry_propagate", i),
                                precision=ML_StdLogic))
                carry_generate.append(
                    BitLogicOr(generate_list[i],
                               BitLogicAnd(propagate_list[i],
                                           carry_generate[i - 1],
                                           precision=ML_StdLogic),
                               tag=sub_name("carry_generate", i),
                               precision=ML_StdLogic))
                add_result.append(
                    Select(carry_generate[i - 1],
                           addp1_list[i],
                           add_list[i],
                           tag=sub_name("add_result", i),
                           precision=addp1_list[i].get_precision()))
                addp1_result.append(
                    Select(BitLogicOr(carry_propagate[i - 1],
                                      carry_generate[i - 1],
                                      precision=ML_StdLogic),
                           addp1_list[i],
                           add_list[i],
                           tag=sub_name("addp1_result", i),
                           precision=addp1_list[i].get_precision()))
            add_result_full = vector_concatenation(
                #Conversion(carry_generate[-1], precision=ML_StdLogicVectorFormat(1)),
                *tuple(add_result[::-1]))
            addp1_result_full = vector_concatenation(
                #Conversion(BitLogicOr(carry_generate[-1], carry_propagate[-1], precision=ML_StdLogic), precision=ML_StdLogicVectorFormat(1)),
                *tuple(addp1_result[::-1]))
            return add_result_full, addp1_result_full, carry_generate[
                -1], carry_propagate[-1]