def __init__(self, a: Bus, b: Bus, prefix: str = "u_rca"): 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) # Gradual addition of 1-bit adder components for input_index in range(self.N): # First adder is a half adder if input_index == 0: obj_adder = HalfAdder(self.a.get_wire(input_index), self.b.get_wire(input_index), prefix=self.prefix + "_ha") # Rest adders are full adders else: obj_adder = FullAdder( self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix + "_fa" + str(input_index)) self.add_component(obj_adder) self.out.connect(input_index, obj_adder.get_sum_wire()) if input_index == (self.N - 1): self.out.connect(self.N, obj_adder.get_carry_wire())
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: Bus, b: Bus, prefix: str = "u_pg_rca"): 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) # Gradual addition of 1-bit adder components for input_index in range(self.N): if input_index == 0: # First full adder with connected constant wire with value 0 as cin 0 obj_pg_fa = FullAdderPG(self.a.get_wire(input_index), self.b.get_wire(input_index), ConstantWireValue0(), prefix=self.prefix + "_pg_fa" + str(input_index)) else: obj_pg_fa = FullAdderPG(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().out, prefix=self.prefix + "_pg_fa" + str(input_index)) self.add_component(obj_pg_fa) self.out.connect(input_index, obj_pg_fa.get_sum_wire()) obj_and = AndGate( self.get_previous_component().c, self.get_previous_component().get_propagate_wire(), prefix=self.prefix + "_and" + str(input_index), parent_component=self) obj_or = OrGate(obj_and.out, self.get_previous_component().get_generate_wire(), prefix=self.prefix + "_or" + str(input_index), parent_component=self) self.add_component(obj_and) self.add_component(obj_or) # Connecting last output bit to last cout if input_index == (self.N - 1): self.out.connect(self.N, 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 = "ha"): super().__init__(a, b, prefix) # 2 wires for component's bus output (sum, cout) self.out = Bus(self.prefix + "_out", 2) # Sum # XOR gate for calculation of 1-bit sum obj_xor = XorGate(a, b, 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(a, b, prefix=self.prefix + "_and" + str(self.get_instance_num(cls=AndGate)), outid=1, parent_component=self) self.add_component(obj_and) self.out.connect(1, obj_and.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: 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 = "u_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 gates matrix self.columns = self.init_column_heights() # 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 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 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()) # 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_ha = HalfAdder(self.get_previous_component().get_carry_wire(), self.add_column_wire(column=2, bit=0), prefix=self.prefix + "_ha" + str(self.get_instance_num(cls=HalfAdder))) self.add_component(obj_ha) self.out.connect(2, obj_ha.get_sum_wire()) self.out.connect(3, obj_ha.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)) ]
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 = "u_arrmul"): 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) # Gradual generation of partial products for b_multiplier_index in range(self.N): for a_multiplicand_index in range(self.N): # AND gates generation for calculation of partial products 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)) 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()) # HA generation, last 1-bit adder in second row elif a_multiplicand_index == self.N - 1 and b_multiplier_index == 1: obj_adder = HalfAdder( self.get_previous_component().out, self.get_previous_component( number=2).get_carry_wire(), prefix=self.prefix + "_ha" + str(a_multiplicand_index) + "_" + str(b_multiplier_index)) self.add_component(obj_adder) # FA generation else: 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: self.out.connect(a_multiplicand_index + 1, ConstantWireValue0) 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: self.out.connect(self.out.N - 1, obj_adder.get_carry_wire())
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)
SignedArrayMultiplier, SignedDaddaMultiplier, SignedWallaceMultiplier, ) from ariths_gen.multi_bit_circuits.dividers import ( ArrayDivider ) import sys import os """ Generation of circuits """ if __name__ == "__main__": N = 8 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") directory = "build" os.makedirs(directory, exist_ok=True) representation = "h" # RCA name = f"{representation}_u_rca{N}" circuit = UnsignedRippleCarryAdder(a, b, prefix=name) circuit.get_v_code_hier(open(f"{directory}/{name}.v", "w")) name = f"{representation}_s_rca{N}" circuit = SignedRippleCarryAdder(a, b, prefix=name) circuit.get_v_code_hier(open(f"{directory}/{name}.v", "w"))
def __init__(self, a: Bus, b: Bus, prefix: str = "s_dadda_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) # Get starting stage and maximum possible column height self.stage, self.d = self.get_maximum_height( initial_value=min(self.a.N, self.b.N)) # 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 stage 0 for stage in range(self.stage, 0, -1): col = 0 while col < len(self.columns): if self.get_column_height(col) == self.d + 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)) elif self.get_column_height(col) > self.d: # 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)) # Next iteration with same column in case there is need for further reduction col -= 1 col += 1 # Update maximum possible column height _, self.d = self.get_maximum_height(stage) # 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 (no sign extension) 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: Bus, b: Bus, prefix: str = "arrdiv"): 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 quotient result self.out = Bus(self.prefix + "_out", self.N) # Performing series of iterative subtractions # Gradually shifting the divisor for a_index in reversed(range(self.N)): # Series of subtractions to obtain quotient bit for b_index in range(self.N): # First full subtractor is formed from divisor's LSB bit (b_index) and divident's MSB bit (a_index) if b_index == 0: adder_object = FullSubtractor( a=self.a.get_wire(a_index), b=self.b.get_wire(b_index), c=ConstantWireValue0(), prefix=self.prefix + "_fs" + str(self.get_instance_num(cls=FullSubtractor))) elif a_index == self.N - 1: adder_object = FullSubtractor( a=ConstantWireValue0(), b=self.b.get_wire(b_index), c=self.get_previous_component().get_borrow_wire(), prefix=self.prefix + "_fs" + str(self.get_instance_num(cls=FullSubtractor))) else: adder_object = FullSubtractor( a=self.get_previous_component(self.N + 1).out.get_wire(), b=self.b.get_wire(b_index), c=self.get_previous_component().get_borrow_wire(), prefix=self.prefix + "_fs" + str(self.get_instance_num(cls=FullSubtractor))) self.add_component(adder_object) # Don't generate multiplexers for divison remainders if a_index != 0: for mux_index in range(self.N - 1): mux_object = TwoOneMultiplexer( a=self.get_previous_component( self.N).get_difference_wire(), b=self.get_previous_component(self.N).a, c=self.get_previous_component( 1 + mux_index).get_borrow_wire(), prefix=self.prefix + "_mux2to1" + str(self.get_instance_num(cls=TwoOneMultiplexer))) self.add_component(mux_object) # Every borrow out obtained from each iteration of subtractions needs to be negated to represent the quotient output bit quotient = NotGate(a=adder_object.get_borrow_wire(), prefix=self.prefix + "_not" + str(self.get_instance_num(cls=NotGate)), parent_component=self) self.add_component(quotient) self.out.connect(a_index, quotient.out)