def __init__(self, a: Bus, b: Bus, cla_block_size: int = 4, prefix: str = "s_cla"): super().__init__(a=a, b=b, cla_block_size=cla_block_size, prefix=prefix) self.c_data_type = "int64_t" # Additional XOR gates to ensure correct sign extension in case of sign addition sign_xor_1 = XorGate(self.a.get_wire(self.N - 1), self.b.get_wire(self.N - 1), prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(sign_xor_1) sign_xor_2 = XorGate(sign_xor_1.out, self.get_previous_component(2).out, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(sign_xor_2) self.out.connect(self.N, sign_xor_2.out)
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa"): super().__init__(a, b, c, prefix) # 2 wires for component's bus output (sum, cout) self.out = Bus(self.prefix + "_out", 2) # PG logic propagate_xor = XorGate(a, b, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(propagate_xor) generate_and = AndGate(a, b, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(generate_and) # Sum # XOR gate for calculation of 1-bit sum obj_xor = XorGate(propagate_xor.out, c, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), outid=0, parent_component=self) self.add_component(obj_xor) self.out.connect(0, obj_xor.out) # Cout # AND gate for calculation of 1-bit cout obj_and = AndGate(propagate_xor.out, c, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(obj_and) obj_or = OrGate(generate_and.out, obj_and.out, prefix=self.prefix + "_or" + str(self.get_instance_num(cls=OrGate)), outid=1, parent_component=self) self.add_component(obj_or) self.out.connect(1, obj_or.out)
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "pg_logic"): super().__init__(a, b, prefix) # 3 wires for component's bus output (propagate, generate, sum) self.out = Bus(self.prefix + "_out", 3) # PG logic propagate_or = OrGate(a, b, prefix=self.prefix + "_or" + str(self.get_instance_num(cls=OrGate)), outid=0, parent_component=self) self.add_component(propagate_or) generate_and = AndGate(a, b, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), outid=1, parent_component=self) self.add_component(generate_and) sum_xor = XorGate(a, b, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), outid=2, parent_component=self) self.add_component(sum_xor) self.out.connect(0, propagate_or.out) self.out.connect(1, generate_and.out) self.out.connect(2, sum_xor.out)
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "hs"): super().__init__(a, b, prefix) # 2 wires for component's bus output (difference, bout) self.out = Bus(self.prefix + "_out", 2) # Difference # XOR gate for calculation of 1-bit difference difference_xor = XorGate(a=self.a, b=self.b, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), outid=0, parent_component=self) self.add_component(difference_xor) self.out.connect(0, difference_xor.out) # Bout # NOT and AND gates for calculation of 1-bit borrow out not_obj = NotGate(a=self.a, prefix=self.prefix + "_not" + str(self.get_instance_num(cls=NotGate)), parent_component=self) self.add_component(not_obj) borrow_and = AndGate(a=not_obj.out, b=self.b, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), outid=1, parent_component=self) self.add_component(borrow_and) self.out.connect(1, borrow_and.out)
def __init__(self, a: Bus, b: Bus, bypass_block_size: int = 4, prefix: str = "u_cska"): super().__init__() self.N = max(a.N, b.N) self.prefix = prefix self.a = Bus(prefix=a.prefix, wires_list=a.bus) self.b = Bus(prefix=b.prefix, wires_list=b.bus) # 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) # Output wires for N sum bits and additional cout bit self.out = Bus(self.prefix+"_out", self.N+1) # To signify current number of blocks and number of bits that remain to be added into function blocks N_blocks = 0 N_wires = self.N cin = ConstantWireValue0() while N_wires != 0: propagate_wires = [] block_size = bypass_block_size if N_wires >= bypass_block_size else N_wires for i in range(block_size): # Generate propagate wires for corresponding bit pairs propagate_xor = XorGate(a=self.a.get_wire((N_blocks*bypass_block_size)+i), b=self.b.get_wire((N_blocks*bypass_block_size)+i), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(propagate_xor) propagate_wires.append(propagate_xor.out) if N_blocks == 0 and i == 0: obj_adder = HalfAdder(a=self.a.get_wire((N_blocks*bypass_block_size)+i), b=self.b.get_wire((N_blocks*bypass_block_size)+i), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=HalfAdder))) else: obj_adder = FullAdder(a=self.a.get_wire((N_blocks*bypass_block_size)+i), b=self.b.get_wire((N_blocks*bypass_block_size)+i), c=cout, prefix=self.prefix+"_fa"+str(self.get_instance_num(cls=FullAdder))) cout = obj_adder.get_carry_wire() self.add_component(obj_adder) # Connecting adder's output sum bit to its proper position within the described circuit's output bus self.out.connect(i+(N_blocks*bypass_block_size), obj_adder.get_sum_wire()) # ANDing of propagate wires, gate's output serves as select signal into 2:1 multiplexer and signifies whether block's input carry should be propagated (thus reducing delay) or not propagation_and = MultipleInputLogicGate(a=Bus(prefix=self.prefix+f"_propagate_signal{N_blocks}", N=len(propagate_wires), wires_list=propagate_wires), two_input_gate_cls=AndGate, parent_component=self, prefix=self.prefix+f"_and_propagate{N_blocks}") mux = TwoOneMultiplexer(a=cout, b=cin, c=propagation_and.out, prefix=self.prefix+"_mux2to1"+str(self.get_instance_num(cls=TwoOneMultiplexer))) self.add_component(mux) # Updating cin for the the next bypass block # Also updating cout value which is used as cin for the first adder of the next block cin = mux.out.get_wire() cout = mux.out.get_wire() N_wires -= block_size N_blocks += 1 # Connection of final Cout self.out.connect(self.N, cin)
def __init__(self, a: Wire = Wire(name="d0"), b: Wire = Wire(name="d1"), c: Wire = Wire(name="sel"), prefix: str = "mux2to1"): super().__init__(a, b, c, prefix) # Represents select signal (self.c naming for proper unified generation) self.c = c # 1 wire for component's output bus self.out = Bus(self.prefix + "_out", 1) # 2:1MUX logic and_obj = AndGate(a=self.b, b=self.c, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(and_obj) not_obj = NotGate(a=self.c, prefix=self.prefix + "_not" + str(self.get_instance_num(cls=NotGate)), parent_component=self) self.add_component(not_obj) and_obj = AndGate(a=self.a, b=self.get_previous_component().out, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(and_obj) xor_obj = XorGate(a=self.get_previous_component(3).out, b=self.get_previous_component().out, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(xor_obj) # Connection of MUX output wire self.out.connect(0, xor_obj.out)
def __init__(self, a: Bus, b: Bus, cla_block_size: int = 4, prefix: str = "u_cla"): super().__init__() self.N = max(a.N, b.N) self.prefix = prefix self.a = Bus(prefix=a.prefix, wires_list=a.bus) self.b = Bus(prefix=b.prefix, wires_list=b.bus) # 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) # Output wires for N sum bits and additional cout bit self.out = Bus(self.prefix + "_out", self.N + 1) # To signify current number of blocks and number of bits that remain to be added into function blocks N_blocks = 0 N_wires = self.N cin = ConstantWireValue0() while N_wires != 0: # Lists containing all propagate/generate wires self.propagate = [] self.generate = [] # Cin0 used as a first generate wire for obtaining next carry bits self.generate.append(cin) block_size = cla_block_size if N_wires >= cla_block_size else N_wires # Gradual addition of propagate/generate logic blocks and AND/OR gates for Cout bits generation, XOR gates for Sum bits generation for i in range(block_size): pg_block = PGLogicBlock( self.a.get_wire((N_blocks * cla_block_size) + i), self.b.get_wire((N_blocks * cla_block_size) + i), prefix=self.prefix + "_pg_logic" + str(self.get_instance_num(cls=PGLogicBlock))) self.propagate.append(pg_block.get_propagate_wire()) self.generate.append(pg_block.get_generate_wire()) self.add_component(pg_block) if i == 0 and N_blocks == 0: obj_sum_xor = XorGate( pg_block.get_sum_wire(), cin, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(obj_sum_xor) self.out.connect(i + (N_blocks * cla_block_size), obj_sum_xor.out) # Carry propagation calculation obj_and = AndGate( self.propagate[(N_blocks * cla_block_size) + i], self.generate[(N_blocks * cla_block_size) + i], prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(obj_and) # Carry bit generation obj_cout_or = OrGate( pg_block.get_generate_wire(), self.get_previous_component().out, prefix=self.prefix + "_or" + str( self.get_instance_num(cls=OrGate, count_disabled_gates=False)), parent_component=self) self.add_component(obj_cout_or) else: obj_sum_xor = XorGate( pg_block.get_sum_wire(), self.get_previous_component(2).out, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(obj_sum_xor) self.out.connect(i + (N_blocks * cla_block_size), obj_sum_xor.out) # List of AND gates outputs that are later combined in a multi-bit OR gate composite_or_gates_inputs = [] for g_index in range(len(self.generate) - 1): composite_wires = [] # Getting a list of wires used for current bit position cout composite AND gate's generation # E.g. for Cout2 = G1 + G0·P1 C0·P0·P1 it gets a list containing [C0,P0,P1] then [G0,P1] composite_wires.append(self.generate[g_index]) for p_index in range( len(self.propagate) - 1, g_index - 1, -1): composite_wires.append(self.propagate[p_index]) # For each pg pair values algorithmically combine two input AND gates to replace multiple input gates (resolves fan-in issue) pg_wires = Bus(wires_list=composite_wires) multi_bit_and_gate = MultipleInputLogicGate( a=pg_wires, two_input_gate_cls=AndGate, prefix=self.prefix + "_and", parent_component=self) composite_or_gates_inputs.append( multi_bit_and_gate.out) # Final OR gates cascade using generated AND gates output wires composite_or_wires = Bus( wires_list=composite_or_gates_inputs) multi_bit_or_gate = MultipleInputLogicGate( a=composite_or_wires, two_input_gate_cls=OrGate, prefix=self.prefix + "_or", parent_component=self) # Carry bit generation obj_cout_or = OrGate( pg_block.get_generate_wire(), multi_bit_or_gate.out, prefix=self.prefix + "_or" + str( self.get_instance_num(cls=OrGate, count_disabled_gates=False)), parent_component=self) self.add_component(obj_cout_or) # Updating cin for the the next bypass block # Also updating cout value which is used as cin for the first adder of the next block cin = obj_cout_or.out N_wires -= block_size N_blocks += 1 # Connection of final Cout self.out.connect(self.N, cin)
def __init__(self, a: Bus, b: Bus, prefix: str = "s_wallace_cla", unsigned_adder_class_name: str = UnsignedCarryLookaheadAdder): super().__init__() self.N = max(a.N, b.N) self.prefix = prefix self.a = Bus(prefix=a.prefix, wires_list=a.bus) self.b = Bus(prefix=b.prefix, wires_list=b.bus) # 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) # Output wires for multiplication product self.out = Bus(self.prefix + "_out", self.N * 2) # Initialize all columns partial products forming AND/NAND gates matrix based on Baugh-Wooley multiplication self.columns = self.init_column_heights(signed=True) # Not used for 1 bit multiplier if self.N != 1: # Adding constant wire with value 1 to achieve signedness based on Baugh-Wooley multiplication algorithm # (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end) self.columns[self.N].insert(1, ConstantWireValue1()) self.update_column_heights(curr_column=self.N, curr_height_change=1) # Perform reduction until all columns have 2 or less bits in them while not all(height <= 2 for (height, *_) in self.columns): col = 0 while col < len(self.columns): # If column has exactly 3 bits in height and all previous columns has maximum of 2 bits in height, combine them in a half adder if self.get_column_height(col) == 3 and all( height <= 2 for (height, *_) in self.columns[0:col - 1]): # Add half adder and also AND/NAND gates if neccesarry (via add_column_wire invocation) into list of circuit components obj_adder = HalfAdder( self.add_column_wire(column=col, bit=0), self.add_column_wire(column=col, bit=1), prefix=self.prefix + "_ha" + str(self.get_instance_num(cls=HalfAdder))) self.add_component(obj_adder) # Update the number of current and next column wires self.update_column_heights(curr_column=col, curr_height_change=-1, next_column=col + 1, next_height_change=1) # Update current and next column wires arrangement # add ha's generated sum to the bottom of current column # add ha's generated cout to the top of next column self.update_column_wires( curr_column=col, next_column=col + 1, adder=self.get_previous_component(1)) # If column has more than 3 bits in height, combine them in a full adder elif self.get_column_height(col) > 3: # Add full adder and also AND/NAND gates if neccesarry (via add_column_wire invocation) into list of circuit components obj_adder = FullAdder( self.add_column_wire(column=col, bit=0), self.add_column_wire(column=col, bit=1), self.add_column_wire(column=col, bit=2), prefix=self.prefix + "_fa" + str(self.get_instance_num(cls=FullAdder))) self.add_component(obj_adder) # Update the number of current and next column wires self.update_column_heights(curr_column=col, curr_height_change=-2, next_column=col + 1, next_height_change=1) # Update current and next column wires arrangement # add fa's generated sum to the bottom of current column # add fa's generated cout to the top of next column self.update_column_wires( curr_column=col, next_column=col + 1, adder=self.get_previous_component(1)) col += 1 # Output generation # First output bit from single first pp AND gate self.out.connect(0, self.add_column_wire(column=0, bit=0)) # Final addition of remaining bits # 1 bit multiplier case if self.N == 1: self.out.connect(1, ConstantWireValue0()) return # 2 bit multiplier case elif self.N == 2: obj_ha = HalfAdder(self.add_column_wire(column=1, bit=0), self.add_column_wire(column=1, bit=1), prefix=self.prefix + "_ha" + str(self.get_instance_num(cls=HalfAdder))) self.add_component(obj_ha) self.out.connect(1, obj_ha.get_sum_wire()) obj_fa = FullAdder(self.get_previous_component().get_carry_wire(), self.add_column_wire(column=2, bit=0), self.add_column_wire(column=2, bit=1), prefix=self.prefix + "_fa" + str(self.get_instance_num(cls=FullAdder))) self.add_component(obj_fa) self.out.connect(2, obj_fa.get_sum_wire()) self.out.connect(3, obj_fa.get_carry_wire()) # Final addition of remaining bits using chosen unsigned multi bit adder else: # Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit) adder_prefix = self.prefix + "_" + unsigned_adder_class_name( a=a, b=b).prefix + str(len(self.columns) - 1) adder_a = Bus(prefix=f"{adder_prefix}_a", wires_list=[ self.add_column_wire(column=col, bit=0) for col in range(1, len(self.columns)) ]) adder_b = Bus(prefix=f"{adder_prefix}_b", wires_list=[ self.add_column_wire(column=col, bit=1) for col in range(1, len(self.columns)) ]) final_adder = unsigned_adder_class_name(a=adder_a, b=adder_b, prefix=adder_prefix) self.add_component(final_adder) [ self.out.connect(o, final_adder.out.get_wire(o - 1), inserted_wire_desired_index=o - 1) for o in range(1, len(self.out.bus)) ] # Final XOR to ensure proper sign extension obj_xor = XorGate(ConstantWireValue1(), self.out.get_wire(self.out.N - 1), prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(obj_xor) self.out.connect(self.out.N - 1, obj_xor.out)
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="bin"), prefix: str = "fs"): super().__init__(a, b, c, prefix) # 2 wires for component's bus output (difference, bout) self.out = Bus(self.prefix + "_out", 2) # Difference xor_obj = XorGate(a=self.a, b=self.b, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), parent_component=self) self.add_component(xor_obj) not_obj = NotGate(a=self.a, prefix=self.prefix + "_not" + str(self.get_instance_num(cls=NotGate)), parent_component=self) self.add_component(not_obj) and_obj = AndGate(a=not_obj.out, b=self.b, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(and_obj) difference_xor = XorGate(a=self.c, b=xor_obj.out, prefix=self.prefix + "_xor" + str(self.get_instance_num(cls=XorGate)), outid=0, parent_component=self) self.add_component(difference_xor) self.out.connect(0, difference_xor.out) # Borrow out not_obj = NotGate(a=xor_obj.out, prefix=self.prefix + "_not" + str(self.get_instance_num(cls=NotGate)), parent_component=self) self.add_component(not_obj) and_obj = AndGate(a=not_obj.out, b=self.c, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), parent_component=self) self.add_component(and_obj) borrow_out_or = OrGate(a=and_obj.out, b=self.get_previous_component(4).out, prefix=self.prefix + "_or" + str(self.get_instance_num(cls=OrGate)), outid=1, parent_component=self) self.add_component(borrow_out_or) self.out.connect(1, borrow_out_or.out)
def __init__(self, a: Bus, b: Bus, prefix: str = "s_arrmul"): super().__init__() self.c_data_type = "int64_t" self.N = max(a.N, b.N) self.prefix = prefix self.a = Bus(prefix=a.prefix, wires_list=a.bus) self.b = Bus(prefix=b.prefix, wires_list=b.bus) # 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) # Output wires for multiplication product self.out = Bus(self.prefix + "_out", self.N * 2) # Gradual generation of partial products for b_multiplier_index in range(self.N): for a_multiplicand_index in range(self.N): # AND and NAND gates generation for calculation of partial products and sign extension if (b_multiplier_index == self.N - 1 and a_multiplicand_index != self.N - 1) or ( b_multiplier_index != self.N - 1 and a_multiplicand_index == self.N - 1): obj_nand = NandGate(self.a.get_wire(a_multiplicand_index), self.b.get_wire(b_multiplier_index), prefix=self.prefix + "_nand" + str(a_multiplicand_index) + "_" + str(b_multiplier_index), parent_component=self) self.add_component(obj_nand) else: obj_and = AndGate(self.a.get_wire(a_multiplicand_index), self.b.get_wire(b_multiplier_index), prefix=self.prefix + "_and" + str(a_multiplicand_index) + "_" + str(b_multiplier_index), parent_component=self) self.add_component(obj_and) if b_multiplier_index != 0: previous_product = self.components[ a_multiplicand_index + b_multiplier_index].out if b_multiplier_index == 1 else self.get_previous_partial_product( a_index=a_multiplicand_index, b_index=b_multiplier_index) # HA generation for first 1-bit adder in each row starting from the second one if a_multiplicand_index == 0: obj_adder = HalfAdder( self.get_previous_component().out, previous_product, prefix=self.prefix + "_ha" + str(a_multiplicand_index) + "_" + str(b_multiplier_index)) self.add_component(obj_adder) # Product generation self.out.connect(b_multiplier_index, obj_adder.get_sum_wire()) # FA generation else: # Constant wire with value 1 used at the last FA in second row (as one of its inputs) for signed multiplication (based on Baugh Wooley algorithm) if a_multiplicand_index == self.N - 1 and b_multiplier_index == 1: previous_product = ConstantWireValue1() obj_adder = FullAdder( self.get_previous_component().out, previous_product, self.get_previous_component( number=2).get_carry_wire(), prefix=self.prefix + "_fa" + str(a_multiplicand_index) + "_" + str(b_multiplier_index)) self.add_component(obj_adder) # PRODUCT GENERATION if a_multiplicand_index == 0 and b_multiplier_index == 0: self.out.connect(a_multiplicand_index, obj_and.out) # 1 bit multiplier case if a_multiplicand_index == self.N - 1: obj_nor = NorGate(ConstantWireValue1(), self.get_previous_component().out, prefix=self.prefix + "_nor_zero_extend", parent_component=self) self.add_component(obj_nor) self.out.connect(a_multiplicand_index + 1, obj_nor.out) elif b_multiplier_index == self.N - 1: self.out.connect(b_multiplier_index + a_multiplicand_index, obj_adder.get_sum_wire()) if a_multiplicand_index == self.N - 1: obj_xor = XorGate( self.get_previous_component().get_carry_wire(), ConstantWireValue1(), prefix=self.prefix + "_xor" + str(a_multiplicand_index + 1) + "_" + str(b_multiplier_index), parent_component=self) self.add_component(obj_xor) self.out.connect(self.out.N - 1, obj_xor.out)