def get_default_args(entity_name="my_compound_adder", **kw): DEFAULT_VALUES = { "precision": fixed_point(34, 0, signed=False), "debug_flag": False, "target": vhdl_backend.VHDLBackend(), "output_file": "my_compound_adder.vhd", "io_formats": { "x": fixed_point(32, 0, signed=False), "y": fixed_point(32, 0, signed=False) }, "passes": [ "beforepipelining:size_datapath", "beforepipelining:rtl_legalize", "beforepipelining:unify_pipeline_stages" ], "entity_name": entity_name, "language": VHDL_Code, "lower_limit": 1, } DEFAULT_VALUES.update(kw) return DefaultEntityArgTemplate(**DEFAULT_VALUES, )
def generate_scheme(self): """ main scheme generation """ Log.report(Log.Info, "width parameter is {}".format(self.width)) int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) var_y = self.implementation.add_input_signal("y", input_precision) var_x.set_attributes(debug = debug_fixed) var_y.set_attributes(debug = debug_fixed) test = (var_x > 1) test.set_attributes(tag = "test", debug = debug_std) large_add = (var_x + var_y) pre_result = Select( test, 1, large_add, tag = "pre_result", debug = debug_fixed ) result = Conversion(pre_result, precision=output_precision) self.implementation.add_output_signal("vr_out", result) return [self.implementation]
def __init__(self, arg_template=None): """ Initialize """ # building default arg_template if necessary arg_template = SubComponentInstance.get_default_args() if \ arg_template is None else arg_template # initializing I/O precision self.width = arg_template.width precision = arg_template.precision io_precisions = [precision] * 2 Log.report( Log.Info, "generating Adaptative Entity with width={}".format(self.width) ) # initializing base class ML_EntityBasis.__init__(self, base_name="adaptative_design", arg_template=arg_template ) self.accuracy = arg_template.accuracy self.precision = arg_template.precision int_size = 3 frac_size = 7 self.input_precision = fixed_point(int_size, frac_size) self.output_precision = fixed_point(int_size, frac_size)
def generate_scheme(self): """ main scheme generation """ Log.report(Log.Info, "width parameter is {}".format(self.width)) int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) var_y = self.implementation.add_input_signal("y", input_precision) var_x.set_attributes(debug = debug_fixed) var_y.set_attributes(debug = debug_fixed) sub = var_x - var_y c = Constant(0) self.implementation.start_new_stage() #pre_result = Select( # c > sub, # c, # sub #) pre_result = Max(0, sub) self.implementation.start_new_stage() result = Conversion(pre_result + var_x, precision=output_precision) self.implementation.add_output_signal("vr_out", result) return [self.implementation]
def solve_format_SignCast(optree): """ Resolve the format for a SignCast node """ assert isinstance(optree, SignCast) precision = optree.get_input(0).get_precision() int_size = precision.get_integer_size() frac_size = precision.get_frac_size() if optree.specifier is SignCast.Signed: signed_precision = fixed_point(int_size, frac_size, signed=True) return signed_precision elif optree.specifier is SignCast.Unsigned: unsigned_precision = fixed_point(int_size, frac_size, signed=False) return unsigned_precision else: Log.report(Log.Error, "unknown specifier {} in solve_format_SignCast".format(optree.specifier))
def solve_format_SubSignalSelection(optree, format_solver): """ Dummy legalization of SubSignalSelection operation node """ if optree.get_precision() is None: select_input = optree.get_input(0) input_prec = select_input.get_precision() inf_index = evaluate_cst_graph(optree.get_inf_index(), input_prec_solver=format_solver) sup_index = evaluate_cst_graph(optree.get_sup_index(), input_prec_solver=format_solver) if is_fixed_point(input_prec): frac_size = input_prec.get_frac_size() - inf_index integer_size = input_prec.get_integer_size() - ( input_prec.get_bit_size() - 1 - sup_index) if frac_size + integer_size <= 0: Log.report( Log.Error, "range determined for SubSignalSelection format [{}:{}] has negative size: {}, optree is {}", integer_size, frac_size, integer_size + frac_size, optree) return fixed_point(integer_size, frac_size) else: return ML_StdLogicVectorFormat(sup_index - inf_index + 1) else: return optree.get_precision()
def solve_format_Constant(optree): """ Legalize Constant node """ assert isinstance(optree, Constant) value = optree.get_value() if FP_SpecialValue.is_special_value(value): return optree.get_precision() elif not optree.get_precision() is None: # if precision is already set (manually forced), returns it return optree.get_precision() else: # fixed-point format solving frac_size = -1 FRAC_THRESHOLD = 100 # maximum number of frac bit to be tested # TODO: fix for i in range(FRAC_THRESHOLD): if int(value*2**i) == value * 2**i: frac_size = i break if frac_size < 0: Log.report(Log.Error, "value {} is not an integer, from node:\n{}", value, optree) abs_value = abs(value) signed = value < 0 # int_size = max(int(sollya.ceil(sollya.log2(abs_value+2**frac_size))), 0) + (1 if signed else 0) int_size = max(int(sollya.ceil(sollya.log2(abs_value + 1))), 0) + (1 if signed else 0) if frac_size == 0 and int_size == 0: int_size = 1 return fixed_point(int_size, frac_size, signed=signed)
def generate_scheme(self): """ main scheme generation """ Log.report(Log.Info, "input_precision is {}".format(self.input_precision)) Log.report(Log.Info, "output_precision is {}".format(self.output_precision)) shift_amount_precision = fixed_point(3, 0, signed=False) # declaring main input variable var_x = self.implementation.add_input_signal("x", self.input_precision) var_y = self.implementation.add_input_signal("s", shift_amount_precision) cst_8 = Constant(9, precision=ML_Integer) cst_7 = Constant(7, precision=ML_Integer) cst_right_shifted_x = BitLogicRightShift(var_x, cst_8) cst_left_shifted_x = BitLogicLeftShift(var_x, cst_7) dyn_right_shifted_x = BitLogicRightShift(var_x, var_y) dyn_left_shifted_x = BitLogicLeftShift(var_x, var_y) result = cst_right_shifted_x + cst_left_shifted_x + dyn_right_shifted_x + dyn_left_shifted_x # output self.implementation.add_output_signal("vr_out", result) return [self.implementation]
def solve_format_CLZ(optree): """ Legalize CountLeadingZeros precision Args: optree (CountLeadingZeros): input node Returns: ML_Format: legal format for CLZ """ assert isinstance(optree, CountLeadingZeros) op_input = optree.get_input(0) input_precision = op_input.get_precision() if is_fixed_point(input_precision): if input_precision.get_signed(): Log.report(Log.Warning , "signed format in solve_format_CLZ") # +1 for carry overflow int_size = int(sollya.floor(sollya.log2(input_precision.get_bit_size()))) + 1 frac_size = 0 return fixed_point( int_size, frac_size, signed=False ) else: Log.report(Log.Warning , "unsupported format in solve_format_CLZ") return optree.get_precision()
def get_default_args(**kw): default_dict = { "precision": fixed_point(32, 0), "target": VHDLBackend(), "output_file": "mult_array.vhd", "entity_name": "mult_array", "language": VHDL_Code, "Method": ReductionMethod.Wallace_4to2, "pipelined": False, "dummy_mode": False, "booth_mode": False, "method": ReductionMethod.Wallace, "op_expr": multiplication_descriptor_parser("FS9.0xFS13.0"), "stage_height_limit": [None], "passes": [ ("beforepipelining:size_datapath"), ("beforepipelining:rtl_legalize"), ("beforepipelining:unify_pipeline_stages"), ], } default_dict.update(kw) return DefaultEntityArgTemplate(**default_dict)
def solve_format_ArithOperation( optree, integer_size_func=lambda lhs_prec, rhs_prec: None, frac_size_func=lambda lhs_prec, rhs_prec: None, signed_func=lambda lhs, lhs_prec, rhs, rhs_prec: False): """ determining fixed-point format for a generic 2-op arithmetic operation (e.g. Multiplication, Addition, Subtraction) """ lhs = optree.get_input(0) rhs = optree.get_input(1) lhs_precision = lhs.get_precision() rhs_precision = rhs.get_precision() abstract_operation = (lhs_precision is ML_Integer) and (rhs_precision is ML_Integer) if abstract_operation: return ML_Integer if lhs_precision is ML_Integer: cst_eval = evaluate_cst_graph(lhs, input_prec_solver=solve_format_rec) lhs_precision = solve_format_Constant(Constant(cst_eval)) if rhs_precision is ML_Integer: cst_eval = evaluate_cst_graph(rhs, input_prec_solver=solve_format_rec) rhs_precision = solve_format_Constant(Constant(cst_eval)) if is_fixed_point(lhs_precision) and is_fixed_point(rhs_precision): # +1 for carry overflow int_size = integer_size_func(lhs_precision, rhs_precision) frac_size = frac_size_func(lhs_precision, rhs_precision) is_signed = signed_func(lhs, lhs_precision, rhs, rhs_precision) return fixed_point(int_size, frac_size, signed=is_signed) else: return optree.get_precision()
def solve_format_Concatenation(optree): """ legalize Concatenation operation node """ if not optree.get_precision() is None: return optree.get_precision() else: bit_size = reduce(lambda x, y: x + y, [op.get_precision().get_bit_size() for op in optree.get_inputs()], 0) return fixed_point(bit_size, 0, signed = False)
def numeric_emulate(self, io_map): """ Meta-Function numeric emulation """ int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) value_x = io_map["x"] value_y = io_map["y"] test = value_x > 1 large_add = output_precision.truncate(value_x + value_y) result_value = 1 if test else large_add result = { "vr_out": result_value } print(io_map, result) return result
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))
def generate_scheme(self): """ main scheme generation """ Log.report(Log.Info, "width parameter is {}".format(self.width)) int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) var_y = self.implementation.add_input_signal("y", input_precision) var_x.set_attributes(debug=debug_fixed) var_y.set_attributes(debug=debug_fixed) test = (var_x > 1) test.set_attributes(tag="test", debug=debug_std) sub = var_x - var_y c = Constant(0) pre_result_select = Select(c > sub, Select(c < var_y, sub, Select(LogicalAnd( c > var_x, c < var_y, tag="last_lev_cond"), var_x, c, tag="last_lev_sel"), tag="pre_select"), var_y, tag="pre_result_select") pre_result = Max(0, var_x - var_y, tag="pre_result") result = Conversion(Addition(pre_result, pre_result_select, tag="add"), precision=output_precision) self.implementation.add_output_signal("vr_out", result) return [self.implementation]
def generate_scheme(self): """ main scheme generation """ int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) var_y = self.implementation.add_input_signal("y", input_precision) var_z = self.implementation.add_input_signal("z", input_precision) abstract_formulae = var_x + var_y * var_z + 7 round_bit = BitSelection( abstract_formulae, FixedPointPosition(abstract_formulae, 0, align=FixedPointPosition.FromPointToLSB), ) msb_bit = BitSelection( abstract_formulae, FixedPointPosition(abstract_formulae, 0, align=FixedPointPosition.FromMSBToLSB)) lsb_bit = BitSelection( abstract_formulae, FixedPointPosition(abstract_formulae, 0, align=FixedPointPosition.FromLSBToLSB)) self.implementation.add_output_signal("round", round_bit) self.implementation.add_output_signal("msb", msb_bit) self.implementation.add_output_signal("lsb", lsb_bit) return [self.implementation]
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
def solve_format_Negation(optree): """ legalize format of bitwise logical operation Args: optree (ML_Operation): bitwise logical input node Returns: (ML_Format): legal format for input node """ op_input = optree.get_input(0) input_precision = op_input.get_precision() # TODO: OPTIMIZATION, increment according to input range # rather than according to input bit-size int_inc = 1 if not input_precision.get_signed() else 0 int_size = input_precision.get_integer_size() + int_inc frac_size = input_precision.get_frac_size() return fixed_point(int_size, frac_size, signed=True)
def solve_format_Constant(optree): """ Legalize Constant node """ assert isinstance(optree, Constant) value = optree.get_value() if FP_SpecialValue.is_special_value(value): return optree.get_precision() elif not optree.get_precision() is None: # if precision is already set (manually forced), returns it return optree.get_precision() else: # fixed-point format solving assert int(value) == value abs_value = abs(value) signed = value < 0 int_size = max(int(sollya.ceil(sollya.log2(abs_value + 1))), 0) + (1 if signed else 0) frac_size = 0 if frac_size == 0 and int_size == 0: int_size = 1 return fixed_point(int_size, frac_size, signed=signed)
def solve_format_SubSignalSelection(optree): """ Dummy legalization of SubSignalSelection operation node """ if optree.get_precision() is None: select_input = optree.get_input(0) input_prec = select_input.get_precision() inf_index = evaluate_cst_graph(optree.get_inf_index(), input_prec_solver=solve_format_rec) sup_index = evaluate_cst_graph(optree.get_sup_index(), input_prec_solver=solve_format_rec) if is_fixed_point(input_prec): frac_size = input_prec.get_frac_size() - inf_index integer_size = input_prec.get_integer_size() - ( input_prec.get_bit_size() - 1 - sup_index) return fixed_point(integer_size, frac_size) else: return ML_StdLogicVectorFormat(sup_index - inf_index + 1) else: return optree.get_precision()
def determine_minimal_fixed_format_cst(value): """ determine the minimal size format which can encode exactly the constant value value """ # fixed-point format solving frac_size = -1 FRAC_THRESHOLD = 100 # maximum number of frac bit to be tested # TODO: fix for i in range(FRAC_THRESHOLD): if int(value * 2**i) == value * 2**i: frac_size = i break if frac_size < 0: Log.report(Log.Error, "value {} is not an integer, from node:\n{}", value, optree) abs_value = abs(value) signed = value < 0 # int_size = max(int(sollya.ceil(sollya.log2(abs_value+2**frac_size))), 0) + (1 if signed else 0) int_size = max(int(sollya.ceil(sollya.log2(abs_value + 1))), 0) + (1 if signed else 0) if frac_size == 0 and int_size == 0: int_size = 1 return fixed_point(int_size, frac_size, signed=signed)
def __init__(self, arg_template=DefaultEntityArgTemplate, precision=fixed_point(32, 0, signed=False), accuracy=ML_Faithful, debug_flag=False, target=VHDLBackend(), output_file="mult_array.vhd", entity_name="mult_array", language=VHDL_Code, acc_prec=None, pipelined=False): # initializing I/O precision precision = arg_template.precision io_precisions = [precision] * 2 # initializing base class ML_EntityBasis.__init__(self, base_name="mult_array", entity_name=entity_name, output_file=output_file, io_precisions=io_precisions, backend=target, debug_flag=debug_flag, language=language, arg_template=arg_template) self.accuracy = accuracy # main precision (used for product operand and default for accumulator) self.precision = precision # enable operator pipelining self.pipelined = pipelined # multiplication input descriptor self.op_expr = arg_template.op_expr self.dummy_mode = arg_template.dummy_mode self.booth_mode = arg_template.booth_mode # reduction method self.reduction_method = arg_template.method # limit of height for each compression stage self.stage_height_limit = arg_template.stage_height_limit
def largest_format(format0, format1): if is_fixed_point(format0) and is_fixed_point(format1): # unsigned_int_size = format0.get_integer_size() if format1.get_signed() \ else format1.get_integer_size() signed_int_size = format1.get_integer_size() if format1.get_signed() \ else format0.get_integer_size() xor_signed = (format0.get_signed() != format1.get_signed()) and \ (unsigned_int_size >= signed_int_size) int_size = max(format0.get_integer_size(), format1.get_integer_size()) + (1 if xor_signed else 0) frac_size = max(format0.get_frac_size(), format1.get_frac_size()) return fixed_point(int_size, frac_size, signed=format0.get_signed() or format1.get_signed()) elif format0 is None or format0 is ML_Integer: # TODO: fix for abstract format return format1 elif format1 is None or format1 is ML_Integer: # TODO: fix for abstract format return format0 elif format0.get_bit_size() == format1.get_bit_size(): return format0 else: Log.report(Log.Error, "unable to determine largest format") raise NotImplementedError
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
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]
def generate_advanced_scheme(self): ## Generate Fused multiply and add comput <x> . <y> + <z> Log.report( Log.Info, "generating MultArray with output precision {precision}".format( precision=self.precision)) acc = None def merge_product_in_heap(operand_list, pos_bit_heap, neg_bit_heap): """ generate product operand_list[0] * operand_list[1] and insert all the partial products into the heaps @p pos_bit_heap (positive bits) and @p neg_bit_heap (negative bits) """ a_i, b_i = operand_list if self.booth_mode: booth_radix4_multiply(a_i, b_i, pos_bit_heap, neg_bit_heap) else: # non-booth product generation a_i_precision = a_i.get_precision() b_i_precision = b_i.get_precision() a_i_signed = a_i_precision.get_signed() b_i_signed = b_i.get_precision().get_signed() unsigned_prod = not (a_i_signed) and not (b_i_signed) a_i_size = a_i_precision.get_bit_size() b_i_size = b_i_precision.get_bit_size() for pp_index in range(a_i_size): a_j_signed = a_i_signed and (pp_index == a_i_size - 1) bit_a_j = BitSelection(a_i, pp_index) pp = Select(equal_to(bit_a_j, 1), b_i, 0) offset = pp_index - a_i_precision.get_frac_size() for b_index in range(b_i_size): b_k_signed = b_i_signed and (b_index == b_i_size - 1) pp_signed = a_j_signed ^ b_k_signed pp_weight = offset + b_index local_bit = BitSelection(pp, b_index) if pp_signed: neg_bit_heap.insert_bit(pp_weight, local_bit) else: pos_bit_heap.insert_bit(pp_weight, local_bit) def merge_addition_in_heap(operand_list, pos_bit_heap, neg_bit_heap): """ expand addition of operand_list[0] to the bit heaps """ add_op = operand_list[0] precision = add_op.get_precision() size = precision.get_bit_size() offset = -precision.get_frac_size() # most significant bit if precision.get_signed(): neg_bit_heap.insert_bit(size - 1 + offset, BitSelection(add_op, size - 1)) else: pos_bit_heap.insert_bit(size - 1 + offset, BitSelection(add_op, size - 1)) # any other bit for index in range(size - 1): pos_bit_heap.insert_bit(index + offset, BitSelection(add_op, index)) # generating input signals stage_operation_map = self.instanciate_inputs( insert_mul_callback=lambda a, b: (merge_product_in_heap, [a, b]), insert_op_callback=lambda op: (merge_addition_in_heap, [op])) # heap of positive bits pos_bit_heap = BitHeap() # heap of negative bits neg_bit_heap = BitHeap() def reduce_heap(pos_bit_heap, neg_bit_heap, limit=2): """ reduce both pos_bit_heap and neg_bit_heap until their height is lower or equal to @p limit """ # Partial Product reduction while pos_bit_heap.max_count() > limit: pos_bit_heap = REDUCTION_METHOD_MAP[self.reduction_method]( pos_bit_heap) dump_heap_stats("pos_bit_heap", pos_bit_heap) while neg_bit_heap.max_count() > limit: neg_bit_heap = REDUCTION_METHOD_MAP[self.reduction_method]( neg_bit_heap) dump_heap_stats("neg_bit_heap", neg_bit_heap) return pos_bit_heap, neg_bit_heap def dump_heap_stats(title, bit_heap): Log.report(Log.Verbose, " {} max count: {}", title, bit_heap.max_count()) stage_index_list = sorted(stage_operation_map.keys()) for stage_id in stage_index_list: Log.report(Log.Verbose, "considering stage: {}".format(stage_id)) # synchronizing pipeline stage if stage_id is None: pass else: while stage_id > self.implementation.get_current_stage(): current_stage_id = self.implementation.get_current_stage() pos_bit_heap, neg_bit_heap = reduce_heap( pos_bit_heap, neg_bit_heap, limit=self.stage_height_limit[current_stage_id]) Log.report( Log.Verbose, "Inserting a new pipeline stage, stage_id={}, current_stage={}", stage_id, self.implementation.get_current_stage()) self.implementation.start_new_stage() # inserting input operations that appears at this stage operation_list = stage_operation_map[stage_id] for merge_ctor, operand_list in operation_list: Log.report(Log.Verbose, "merging a new operation result") merge_ctor(operand_list, pos_bit_heap, neg_bit_heap) Log.report(Log.Verbose, "final stage reduction") # final stage reduction pos_bit_heap, neg_bit_heap = reduce_heap(pos_bit_heap, neg_bit_heap) # final conversion to scalar operands pos_op_list, pos_assign_statement = convert_bit_heap_to_fixed_point( pos_bit_heap, signed=False) neg_op_list, neg_assign_statement = convert_bit_heap_to_fixed_point( neg_bit_heap, signed=False) # a PlaceHolder is inserted to force forwarding of op_statement # which will be removed otherwise as it does not appear anywhere in # the final operation graph acc = None if len(pos_op_list) > 0: reduced_pos_sum = reduce(operator.__add__, pos_op_list) reduced_pos_sum.set_attributes(tag="reduced_pos_sum", debug=debug_fixed) pos_acc = PlaceHolder(reduced_pos_sum, pos_assign_statement) acc = pos_acc if len(neg_op_list) > 0: reduced_neg_sum = reduce(operator.__add__, neg_op_list) reduced_neg_sum.set_attributes(tag="reduced_neg_sum", debug=debug_fixed) neg_acc = PlaceHolder(reduced_neg_sum, neg_assign_statement) acc = neg_acc if acc is None else acc - neg_acc acc.set_attributes(tag="raw_acc", debug=debug_fixed) self.precision = fixed_point(self.precision.get_integer_size(), self.precision.get_frac_size(), signed=self.precision.get_signed()) result = Conversion(acc, tag="result", precision=self.precision, debug=debug_fixed) self.implementation.add_output_signal("result_o", result) return [self.implementation]
def generate_scheme(self): """ main scheme generation """ int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) expected_interval = {} # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) x_interval = Interval(-10.3,10.7) var_x.set_interval(x_interval) expected_interval[var_x] = x_interval var_y = self.implementation.add_input_signal("y", input_precision) y_interval = Interval(-17.9,17.2) var_y.set_interval(y_interval) expected_interval[var_y] = y_interval var_z = self.implementation.add_input_signal("z", input_precision) z_interval = Interval(-7.3,7.7) var_z.set_interval(z_interval) expected_interval[var_z] = z_interval cst = Constant(42.5, tag = "cst") expected_interval[cst] = Interval(42.5) conv_ceil = Ceil(var_x, tag = "ceil") expected_interval[conv_ceil] = sollya.ceil(x_interval) conv_floor = Floor(var_y, tag = "floor") expected_interval[conv_floor] = sollya.floor(y_interval) mult = var_z * var_x mult.set_tag("mult") mult_interval = z_interval * x_interval expected_interval[mult] = mult_interval large_add = (var_x + var_y) - mult large_add.set_attributes(tag = "large_add") large_add_interval = (x_interval + y_interval) - mult_interval expected_interval[large_add] = large_add_interval var_x_lzc = CountLeadingZeros(var_x, tag="var_x_lzc") expected_interval[var_x_lzc] = Interval(0, input_precision.get_bit_size()) reduced_result = Max(0, Min(large_add, 13)) reduced_result.set_tag("reduced_result") reduced_result_interval = interval_max( Interval(0), interval_min( large_add_interval, Interval(13) ) ) expected_interval[reduced_result] = reduced_result_interval select_result = Select( var_x > var_y, reduced_result, var_z, tag = "select_result" ) select_interval = interval_union(reduced_result_interval, z_interval) expected_interval[select_result] = select_interval # floating-point operation on mantissa and exponents fp_x_range = Interval(-0.01, 100) unbound_fp_var = Variable("fp_x", precision=ML_Binary32, interval=fp_x_range) mant_fp_x = MantissaExtraction(unbound_fp_var, tag="mant_fp_x", precision=ML_Binary32) exp_fp_x = ExponentExtraction(unbound_fp_var, tag="exp_fp_x", precision=ML_Int32) ins_exp_fp_x = ExponentInsertion(exp_fp_x, tag="ins_exp_fp_x", precision=ML_Binary32) expected_interval[unbound_fp_var] = fp_x_range expected_interval[exp_fp_x] = Interval( sollya.floor(sollya.log2(sollya.inf(abs(fp_x_range)))), sollya.floor(sollya.log2(sollya.sup(abs(fp_x_range)))) ) expected_interval[mant_fp_x] = Interval(1, 2) expected_interval[ins_exp_fp_x] = Interval( S2**sollya.inf(expected_interval[exp_fp_x]), S2**sollya.sup(expected_interval[exp_fp_x]) ) # checking interval evaluation for var in [var_x_lzc, exp_fp_x, unbound_fp_var, mant_fp_x, ins_exp_fp_x, cst, var_x, var_y, mult, large_add, reduced_result, select_result, conv_ceil, conv_floor]: interval = evaluate_range(var) expected = expected_interval[var] print("{}: {}".format(var.get_tag(), interval)) print(" vs expected {}".format(expected)) assert not interval is None assert interval == expected return [self.implementation]
def generate_scheme(self): """ main scheme generation """ int_size = 3 frac_size = self.width - int_size input_precision = fixed_point(int_size, frac_size) output_precision = fixed_point(int_size, frac_size) expected_interval = {} # declaring main input variable var_x = self.implementation.add_input_signal("x", input_precision) x_interval = Interval(-10.3, 10.7) var_x.set_interval(x_interval) expected_interval[var_x] = x_interval var_y = self.implementation.add_input_signal("y", input_precision) y_interval = Interval(-17.9, 17.2) var_y.set_interval(y_interval) expected_interval[var_y] = y_interval var_z = self.implementation.add_input_signal("z", input_precision) z_interval = Interval(-7.3, 7.7) var_z.set_interval(z_interval) expected_interval[var_z] = z_interval cst = Constant(42.5, tag="cst") expected_interval[cst] = Interval(42.5) conv_ceil = Ceil(var_x, tag="ceil") expected_interval[conv_ceil] = sollya.ceil(x_interval) conv_floor = Floor(var_y, tag="floor") expected_interval[conv_floor] = sollya.floor(y_interval) mult = var_z * var_x mult.set_tag("mult") mult_interval = z_interval * x_interval expected_interval[mult] = mult_interval large_add = (var_x + var_y) - mult large_add.set_attributes(tag="large_add") large_add_interval = (x_interval + y_interval) - mult_interval expected_interval[large_add] = large_add_interval reduced_result = Max(0, Min(large_add, 13)) reduced_result.set_tag("reduced_result") reduced_result_interval = interval_max( Interval(0), interval_min(large_add_interval, Interval(13))) expected_interval[reduced_result] = reduced_result_interval select_result = Select(var_x > var_y, reduced_result, var_z, tag="select_result") select_interval = interval_union(reduced_result_interval, z_interval) expected_interval[select_result] = select_interval # checking interval evaluation for var in [ cst, var_x, var_y, mult, large_add, reduced_result, select_result, conv_ceil, conv_floor ]: interval = evaluate_range(var) expected = expected_interval[var] print("{}: {} vs expected {}".format(var.get_tag(), interval, expected)) assert not interval is None assert interval == expected return [self.implementation]