Module ariths_gen.multi_bit_circuits.approximate_adders.quad
Implementation of QuAdder
For more information, see: M. A. Hanif, R. Hafiz, O. Hasan and M. Shafique, "QuAd: Design and analysis of Quality-area optimal Low-Latency approximate Adders," 2017 54th ACM/EDAC/IEEE Design Automation Conference (DAC), Austin, TX, USA, 2017, pp. 1-6, doi: 10.1145/3061639.3062306.
Classes
class QuAdder (a, b, R, P, prefix, name='quad', adder_type=None, use_log=False, **kwargs)-
Expand source code
class QuAdder(GeneralCircuit): """ Implementation of QuAd https://ieeexplore.ieee.org/document/8060326 The implementation is inspired by Matlab code from the authors of the paper: ```matlab temp_count=1; for iij=1:length(R_vect) fprintf(fileID,['wire [' num2str(R_vect(iij)+P_vect(iij)) ':0] temp' num2str(temp_count) ';\n']); temp_count=temp_count + 1; end temp_count=1; for iiij=1:length(R_vect) if (sum(R_vect(1:iiij))+P_vect(1)-1) == (sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) fprintf(fileID,['aassign temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':0] = in1[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) '] + in2[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) '];\n']); else disp(R_vect(1:iiij)) fprintf(fileID,['bassign temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':0] = in1[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) ':' num2str(sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) '] + in2[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) ':' num2str(sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) '];\n']); end temp_count=temp_count+1; end statement='};\n'; temp_count=1; for iiij=1:length(R_vect) if iiij ~= length(R_vect) if (R_vect(iiij)==1) statement = [', temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)-1) '] ' statement]; else statement = [', temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)-1) ':' num2str(P_vect(iiij)) '] ' statement]; end else statement = ['assign res[' num2str(N) ':0] =' '{ temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':' num2str(P_vect(iiij)) '] ' statement]; end temp_count=temp_count+1; end ``` """ def log(self, *args): if self.use_log: print(*args) def __init__(self, a, b, R, P, prefix, name="quad", adder_type=None, use_log=False, **kwargs): """ :param a: Bus first input :param b: Bus second input :param R: list of integers, defines the resultant bits of all the sub-adders (the first index specifies the resultant bits of sub-adder 1 and so on) :param P: list of integers, defines the prediction bits of all the sub-adders (again the first index specifies the prediction bits of sub-adder 1 and so on) """ if not adder_type: adder_type = UnsignedRippleCarryAdder # Assumptions checks assert len(R) == len(P), "R and P must have the same length" print([P[i] < P[i-1] + R[i-1] for i in range(1, len(P))]) assert all([P[i] < P[i-1] + R[i-1] for i in range(1, len(P))] ), "Pi must be lower than Pi-1 + Ri-1" assert sum(R) == a.N, "Sum of R must be equal to number of bits" self.use_log = use_log self.N = max(a.N, b.N) super().__init__(inputs=[a, b], prefix=prefix, name=name, out_N=self.N+1, **kwargs) # Bus sign extension in case buses have different lengths self.a.bus_extend(N=self.N, prefix=a.prefix) self.b.bus_extend(N=self.N, prefix=b.prefix) # warnings.warn("QuAdder is not tested yet") # Connect all outputs to zero for i in range(self.N+1): self.out[i] = ConstantWireValue0() # Declaration of temporary wires (just for debug purposes) temp_count = 0 for iiij in range(0, len(R)): self.log('wire [' + str(R[iiij]+P[iiij]) + ':0] temp' + str(temp_count) + ';') temp_count = temp_count + 1 def bus_subconnect(out_bus, in_bus, out_indexes, in_indexes): out_indexes = list(out_indexes) in_indexes = list(in_indexes) assert len(out_indexes) == len(in_indexes) for i, j in zip(out_indexes, in_indexes): if j >= in_bus.N: out_bus[i] = ConstantWireValue0() # unsigned extension else: out_bus.connect(i, in_bus.get_wire(j)) # [i] = in_bus[j] # Connection of adders temp_count = 0 temp_bus = [] for iiij in range(0, len(R)): # Former verilog output self.log("assign temp{}[{}:0] = in1[{}:{}] + in2[{}:{}];".format( temp_count, R[iiij]+P[iiij], sum(R[0:iiij + 1]) + P[0]-1, sum(R[0:iiij + 1]) + P[0]-R[iiij]-P[iiij], sum(R[0:iiij + 1]) + P[0]-1, sum(R[0:iiij + 1]) + P[0]-R[iiij]-P[iiij] )) a1 = Bus(f"{prefix}_temp_{temp_count}_a", R[iiij]+P[iiij]) b1 = Bus(f"{prefix}_temp_{temp_count}_b", R[iiij]+P[iiij]) bus_subconnect(b1, self.b, range(R[iiij]+P[iiij]), range(sum(R[0:iiij + 1])+P[0]-R[iiij]-P[iiij], sum(R[0:iiij + 1])+P[0])) bus_subconnect(a1, self.a, range(R[iiij]+P[iiij]), range(sum(R[0:iiij + 1])+P[0]-R[iiij]-P[iiij], sum(R[0:iiij + 1])+P[0])) temp_bus.append(self.add_component( adder_type(a1, b1, prefix=f"{prefix}_add_{temp_count}") )) temp_count = temp_count+1 # Final connection temp_count = 0 statement = "}" wire_id = 0 for iiij in range(0, len(R)): if iiij != len(R) - 1: if R[iiij] == 1: statement = ', temp{}[{}]'.format( temp_count, R[iiij]+P[iiij] - 1) + statement else: statement = ', temp{}[{}:{}]'.format( temp_count, R[iiij]+P[iiij] - 1, P[iiij]) + statement else: statement = 'assign res[' + str(self.N) + ':0] =' + '{ temp' + str( temp_count) + '[' + str(R[iiij]+P[iiij]) + ':' + str(P[iiij]) + '] ' + statement self.log(statement) for i in range(P[iiij], R[iiij]+P[iiij]): self.log(temp_count, i, wire_id, temp_bus[temp_count].out[i]) self.out[wire_id] = temp_bus[temp_count].out[i] wire_id += 1 temp_count = temp_count+1 # Last carry (MSB) self.out[wire_id] = temp_bus[temp_count - 1].out[R[iiij]+P[iiij]]Implementation of QuAd
<https://ieeexplore.ieee.org/document/8060326> The implementation is inspired by Matlab code from the authors of the paper: ```matlab temp_count=1; for iij=1:length(R_vect) fprintf(fileID,['wire [' num2str(R_vect(iij)+P_vect(iij)) ':0] temp' num2str(temp_count) ';']); temp_count=temp_count + 1; end
temp_count=1; for iiij=1:length(R_vect) if (sum(R_vect(1:iiij))+P_vect(1)-1) == (sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) fprintf(fileID,['aassign temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':0] = in1[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) '] + in2[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) '];']); else disp(R_vect(1:iiij)) fprintf(fileID,['bassign temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':0] = in1[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) ':' num2str(sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) '] + in2[' num2str(sum(R_vect(1:iiij))+P_vect(1)-1) ':' num2str(sum(R_vect(1:iiij))+P_vect(1)-R_vect(iiij)-P_vect(iiij)) ']; ']); end temp_count=temp_count+1; end
statement='};'; temp_count=1; for iiij=1:length(R_vect) if iiij ~= length(R_vect) if (R_vect(iiij)==1) statement = [', temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)-1) '] ' statement]; else statement = [', temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)-1) ':' num2str(P_vect(iiij)) '] ' statement]; end else statement = ['assign res[' num2str(N) ':0] =' '{ temp' num2str(temp_count) '[' num2str(R_vect(iiij)+P_vect(iiij)) ':' num2str(P_vect(iiij)) '] ' statement]; end temp_count=temp_count+1; end ```
:param a: Bus first input :param b: Bus second input :param R: list of integers, defines the resultant bits of all the sub-adders (the first index specifies the resultant bits of sub-adder 1 and so on) :param P: list of integers, defines the prediction bits of all the sub-adders (again the first index specifies the prediction bits of sub-adder 1 and so on)
Ancestors
Methods
def log(self, *args)-
Expand source code
def log(self, *args): if self.use_log: print(*args)
Inherited members
GeneralCircuit:add_componentget_blif_code_flatget_blif_code_hierget_c_code_flatget_c_code_hierget_cgp_code_flatget_circuit_blifget_circuit_cget_circuit_defget_circuit_gatesget_circuit_vget_circuit_wire_indexget_circuit_wiresget_component_typesget_declaration_blifget_declaration_c_flatget_declaration_c_hierget_declaration_v_flatget_declaration_v_hierget_declarations_c_hierget_declarations_v_hierget_function_blif_flatget_function_block_blifget_function_block_cget_function_block_vget_function_blocks_blifget_function_blocks_cget_function_blocks_vget_function_out_blifget_function_out_c_flatget_function_out_c_hierget_function_out_python_flatget_function_out_v_flatget_function_out_v_hierget_hier_subcomponent_defget_includes_cget_init_c_flatget_init_c_hierget_init_python_flatget_init_v_flatget_init_v_hierget_instance_numget_invocation_blif_hierget_invocations_blif_hierget_multi_bit_componentsget_one_bit_componentsget_out_invocation_cget_out_invocation_vget_outputs_cgpget_parameters_cgpget_previous_componentget_prototype_blifget_prototype_cget_prototype_pythonget_prototype_vget_python_code_flatget_triplets_cgpget_unique_typesget_v_code_flatget_v_code_hiersave_wire_id