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: 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 add_column_wires(self, column: list, column_index: int, signed: bool): """Fills circuit's partial product column with corresponding bit pairs. Args: column (list): List representing column of partial product bits. column_index (int): Index of partial products column. signed (bool): Specify whether pp columns bit pairs should perform signed multiplication or not. Returns: list: Updated column list containing corresponding number of input bit pairs to form proper pp column. """ # Adding neccessary number of lists (based on number of bits in the column – stored in `column[0]`) # to column that each represent individual bit pairs for described column (these bit pairs are then combined in AND/NAND gates) [column.append([]) for _ in range(column[0])] # Filling column bit pair lists with appropriate bits if column_index <= self.N-1: [column[column[0]-index].append(self.a.get_wire(index)) for index in range(0, column[0])] [column[index+1].append(self.b.get_wire(index)) for index in range(0, column[0])] else: [column[self.a.N-index].append(self.a.get_wire(index)) for index in range(self.a.N-1, self.a.N-column[0]-1, -1)] [column[index-(self.a.N-1-column[0])].append(self.b.get_wire(index)) for index in range(self.a.N-column[0], self.a.N)] # Converting unsigned column pp bit pair lists into AND gates if signed is False: column[1:] = [AndGate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index), parent_component=self) for i in range(1, len(column))] # Converting signed column pp bit pair lists into AND/NAND gates (based on Baugh-Wooley multiplication algorithm) else: # First half of partial product columns contains only AND gates if column_index < self.N-1 or column_index == self.out.N-2: column[1:] = [AndGate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index), parent_component=self) for i in range(1, len(column))] # Second half of partial product columns contains NAND/AND gates else: column[1] = NandGate(a=column[1][0], b=column[1][1], prefix=self.prefix+'_nand_'+str(column[1][0].index)+'_'+str(column[1][1].index), parent_component=self) column[-1] = NandGate(a=column[-1][0], b=column[-1][1], prefix=self.prefix+'_nand_'+str(column[-1][0].index)+'_'+str(column[-1][1].index), parent_component=self) if len(column[2:-1]) != 0: column[2:-1] = [AndGate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index), parent_component=self) for i in range(2, len(column)-1)] return column
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: 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: 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)