From f28069da5fc118e98a8508b4db84d7dda1344266 Mon Sep 17 00:00:00 2001 From: honzastor Date: Thu, 4 Mar 2021 18:57:32 +0100 Subject: [PATCH] Refactored code and made some small bugfixes for generating exports. --- arithmetic_circuits.py | 127 ++++++++--------------------- arithmetic_circuits_generator.py | 111 ++++---------------------- logic_gates.py | 126 ++++++++++------------------- multi_bit_circuits.py | 63 +++++++++++---- one_bit_circuits.py | 132 +++++++++++++++---------------- wire_components.py | 51 ++++++------ 6 files changed, 227 insertions(+), 383 deletions(-) diff --git a/arithmetic_circuits.py b/arithmetic_circuits.py index 549135a..68fd183 100644 --- a/arithmetic_circuits.py +++ b/arithmetic_circuits.py @@ -13,10 +13,6 @@ class arithmetic_circuit(): self.c_data_type = "uint64_t" self.N = 1 - # TODO delete? - self.carry_out_gate = None - self.sum_out_gates = [] - def add_component(self, component): self.components.append(component) @@ -33,15 +29,6 @@ class arithmetic_circuit(): def get_gate_types(self): return list({type(g): g for g in self.components_gates}.values()) - def get_previous_partial_product(self, a_index: int, b_index: int): - index = ((b_index-2) * (self.N*2)) + ((self.N-1)+2*(a_index+2)) - - if a_index == self.N-1: - index = index-2 - return self.components[index].get_carry_wire() - else: - return self.components[index].get_sum_wire() - def get_sum_wire(self): return self.out.get_wire(0) @@ -49,6 +36,7 @@ class arithmetic_circuit(): return self.out.get_wire(1) def get_circuit_wires(self): + self.circuit_wires = [] for component in self.components: if not [item for item in self.circuit_wires if item[1] == component.a.name]: self.circuit_wires.append((component.a, component.a.name, len(self.circuit_wires))) @@ -68,13 +56,6 @@ class arithmetic_circuit(): # Get list of all gates present in circuit def get_circuit_gates(self): gates = [] - # TODO CHANGE SIGNED MULTIPLIER IMPLEMENTATION (REPLACE CONSTANT WIRE FOR EXTRA GATES) FOR THIS TO BE DELETED - if hasattr(self, 'constant_wire'): - gates.append(xor_gate(a=self.a.get_wire(), b=self.b.get_wire(), prefix=self.prefix+"_xor_constant_wire")) - gates.append(xnor_gate(a=self.a.get_wire(), b=self.b.get_wire(), prefix=self.prefix+"_xnor_constant_wire")) - gates.append(or_gate(a=gates[0].out, b=gates[1].out, prefix=self.prefix+"_or_constant_wire")) - gates[2].out.name = "constant_wire" - for c in self.components: if isinstance(c, logic_gate): gates.append(c) @@ -84,6 +65,7 @@ class arithmetic_circuit(): # Get list of all wires in circuit along with their index position for cgp chromosome generation def get_cgp_wires(self): + self.circuit_wires = [] if isinstance(self.a, bus): [self.circuit_wires.append((w, f"_{w.name}", len(self.circuit_wires))) for w in self.a.bus] [self.circuit_wires.append((w, f"_{w.name}", len(self.circuit_wires))) for w in self.b.bus] @@ -113,10 +95,14 @@ class arithmetic_circuit(): return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + "\n" def get_declaration_c_flat(self): - return f"".join([c.get_declaration_c_flat() for c in self.components]) + return f"{self.a.get_wire_declaration_c()}" + \ + f"{self.b.get_wire_declaration_c()}" + \ + f"".join([c.get_declaration_c_flat() for c in self.components]) def get_init_c_flat(self): - return "".join([c.get_assign_c_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix) if isinstance(c, logic_gate) else c.get_init_c_flat() for c in self.components]) + return f"{self.a.get_wire_assign_c()}" + \ + f"{self.b.get_wire_assign_c()}" + \ + "".join([c.get_assign_c_flat() if isinstance(c, logic_gate) else c.get_init_c_flat() for c in self.components]) def get_function_out_c_flat(self): return "".join([f" {self.out.prefix} |= {o.return_wire_value_c(offset=self.out.bus.index(o))};\n" for o in self.out.bus]) @@ -147,9 +133,9 @@ class arithmetic_circuit(): "".join([c.out.get_declaration_c() if isinstance(c, logic_gate) else c.out.get_wire_declaration_c() for c in self.components]) def get_init_c_hier(self): - return ";\n".join([f" {w.name} = " + w.get_wire_value_c(offset=w.index, prefix=w.prefix) for w in self.a.bus]) + ";\n" + \ - ";\n".join([f" {w.name} = " + w.get_wire_value_c(offset=w.index, prefix=w.prefix) for w in self.b.bus]) + ";\n" + \ - "\n".join([f" {c.out.name} = {c.get_gate_invocation_c(a=c.a, b=c.b, get_index=True)}" if isinstance(c, logic_gate) else c.get_out_invocation_c() for c in self.components]) + return f"{self.a.get_wire_assign_c()}" + \ + f"{self.b.get_wire_assign_c()}" + \ + "".join([f" {c.out.name} = {c.get_gate_invocation_c()}" if isinstance(c, logic_gate) else c.get_out_invocation_c() for c in self.components]) def get_function_out_c_hier(self): return "".join([f" {self.out.prefix} |= {o.return_wire_value_c(offset=self.out.bus.index(o))};\n" for o in self.out.bus]) @@ -158,7 +144,7 @@ class arithmetic_circuit(): return f"{self.get_prototype_c()}" + \ f"{self.out.get_declaration_c()}" + \ f"{self.get_declaration_c_hier()}\n" + \ - f"{self.get_init_c_hier()}\n\n" + \ + f"{self.get_init_c_hier()}\n" + \ f"{self.get_function_out_c_hier()}" + \ f" return {self.out.prefix}"+";\n}" @@ -175,10 +161,14 @@ class arithmetic_circuit(): return f"module {self.prefix}(input [{self.N-1}:0] {self.a.prefix}, input [{self.N-1}:0] {self.b.prefix}, output [{self.out.N-1}:0] {self.out.prefix});\n" def get_declaration_v_flat(self): - return f"".join([c.get_declaration_v_flat() for c in self.components]) + return f"{self.a.get_wire_declaration_v()}" + \ + f"{self.b.get_wire_declaration_v()}" + \ + f"".join([c.get_declaration_v_flat() for c in self.components]) - def get_init_v_flat(self, offset: int = 0, array: bool = False): - return "\n".join([c.get_assign_v_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix, offset=offset, array=True) if isinstance(c, logic_gate) else c.get_init_v_flat(offset=self.components.index(c), array=array) for c in self.components]) + "\n" + def get_init_v_flat(self): + return f"{self.a.get_wire_assign_v()}" + \ + f"{self.b.get_wire_assign_v()}" + \ + "".join([c.get_assign_v_flat() if isinstance(c, logic_gate) else c.get_init_v_flat() for c in self.components]) + "\n" def get_function_out_v_flat(self): return "".join([f" assign {self.out.prefix}[{self.out.bus.index(o)}] = {o.prefix};\n" for o in self.out.bus]) @@ -187,7 +177,7 @@ class arithmetic_circuit(): def get_v_code_flat(self, file_object): file_object.write(self.get_prototype_v()) file_object.write(self.get_declaration_v_flat()+"\n") - file_object.write(self.get_init_v_flat(array=False)+"\n") + file_object.write(self.get_init_v_flat()) file_object.write(self.get_function_out_v_flat()) file_object.write(f"endmodule") file_object.close() @@ -207,9 +197,9 @@ class arithmetic_circuit(): "".join([c.out.get_declaration_v() if isinstance(c, logic_gate) else c.out.get_wire_declaration_v() for c in self.components]) def get_init_v_hier(self): - return ";\n".join([f" assign {w.name} = " + w.get_wire_value_v(offset=w.index, prefix=w.prefix, array=True) for w in self.a.bus]) + ";\n" + \ - ";\n".join([f" assign {w.name} = " + w.get_wire_value_v(offset=w.index, prefix=w.prefix, array=True) for w in self.b.bus]) + ";\n" + \ - "\n".join([f"{c.get_gate_invocation_v(a=c.a, b=c.b, out=c.out, get_index=True)}" if isinstance(c, logic_gate) else c.get_invocation_v() for c in self.components]) + "\n" + return f"{self.a.get_wire_assign_v()}" + \ + f"{self.b.get_wire_assign_v()}" + \ + "".join([f"{c.get_gate_invocation_v()}" if isinstance(c, logic_gate) else c.get_invocation_v() for c in self.components]) def get_function_out_v_hier(self): return "".join([f" assign {self.out.prefix}[{self.out.bus.index(o)}] = {o.name};\n" for o in self.out.bus]) @@ -247,68 +237,21 @@ class arithmetic_circuit(): file_object.close() -""" SIGNED ARITHMETIC CIRCUITS """ +""" MULTIPLIER CIRCUITS """ -class signed_adder_circuit(arithmetic_circuit): +class multiplier_circuit(arithmetic_circuit): def __init__(self): super().__init__() - # TODO TRY TO THINK ABOUT A WAY TO MORE EFFICIENTLY GENERATE OUTPUT FORMATS FOR EXTRA SIGN XOR INVOCATIONS - """ C CODE GENERATION """ - # FLAT C # - # Initialization of 1-bit adders and sign extension XOR gates - def get_init_c_flat(self): - return "".join([c.get_init_c_flat() for c in self.components if isinstance(c, arithmetic_circuit)]) + \ - f"{self.get_previous_component(number=2).get_assign_c_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix, offset=self.N-1)}" + \ - f"{self.get_previous_component().get_assign_c_flat(prefix_a=self.get_previous_component(number=2).out.prefix, prefix_b=self.get_previous_component(number=3).get_carry_wire().prefix)}" + def get_previous_partial_product(self, a_index: int, b_index: int, offset: int = 0): + # To get the index of previous row's connecting adder and its generated pp + index = ((b_index-2) * (self.N*2)) + ((self.N-1)+2*(a_index+2)) + offset - # HIERARCHICAL C # - def get_init_c_hier(self): - return ";\n".join([f" {w.name} = " + w.get_wire_value_c(offset=w.index, prefix=w.prefix) for w in self.a.bus]) + ";\n" + \ - ";\n".join([f" {w.name} = " + w.get_wire_value_c(offset=w.index, prefix=w.prefix) for w in self.b.bus]) + ";\n" + \ - "\n".join([f" {c.out.name} = {c.get_gate_invocation_c(a=c.a, b=c.b, get_index=True)}" if isinstance(c, logic_gate) else c.get_out_invocation_c() for c in self.components[:-1]]) + "\n" + \ - f" {self.get_previous_component().out.name} = {self.get_previous_component().get_gate_invocation_c(a=self.get_previous_component(number=2).out, b=self.get_previous_component(number=3).get_carry_wire())}" - - """ VERILOG CODE GENERATION """ - # FLAT VERILOG # - # Initialization of 1-bit adders and sign extension XOR gates - def get_init_v_flat(self, offset: int = 0, array: bool = False): - return f"\n".join([c.get_init_v_flat(offset=self.components.index(c), array=True) for c in self.components[:-2]]) + "\n" + \ - f"{self.get_previous_component(number=2).get_assign_v_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix, offset=self.N-1, array=True)}" + \ - f"{self.get_previous_component().get_assign_v_flat(prefix_a=self.get_previous_component(number=2).out.name, prefix_b=self.get_previous_component(number=3).get_carry_wire().name, offset=offset, array=array)}" - - # HIERARCHICAL VERILOG # - def get_init_v_hier(self): - return ";\n".join([f" assign {w.name} = " + w.get_wire_value_v(offset=w.index, prefix=w.prefix, array=True) for w in self.a.bus]) + ";\n" + \ - ";\n".join([f" assign {w.name} = " + w.get_wire_value_v(offset=w.index, prefix=w.prefix, array=True) for w in self.b.bus]) + ";\n" + \ - "\n".join([f"{c.get_gate_invocation_v(a=c.a, b=c.b, out=c.out, get_index=True)}" if isinstance(c, logic_gate) else c.get_invocation_v() for c in self.components[:-1]]) + "\n" + \ - f"{self.get_previous_component().get_gate_invocation_v(a=self.get_previous_component(number=2).out, b=self.get_previous_component(number=3).get_carry_wire(), out=self.get_previous_component().out)}\n" - - -class signed_multiplier_circuit(arithmetic_circuit): - def __init__(self): - super().__init__() - - # TODO CHANGE SIGNED MULTIPLIER CIRCUIT (REPLACE CONSTANT WIRE WITH LOGIC GATES) - # C CODE GENERATION - # FLAT C # - def get_declaration_c_flat(self): - return super().get_declaration_c_flat() + \ - f"{self.constant_wire.get_declaration_c()}" - - # HIERARCHICAL C # - def get_declaration_c_hier(self): - return super().get_declaration_c_hier() + \ - f"{self.constant_wire.get_declaration_c()}" - - # VERILOG CODE GENERATION - # FLAT VERILOG # - def get_declaration_v_flat(self): - return super().get_declaration_v_flat() + \ - f"{self.constant_wire.get_declaration_init_v()}" - - # HIERARCHICAL V # - def get_declaration_v_hier(self): - return super().get_declaration_v_hier() + \ - f"{self.constant_wire.get_declaration_init_v()}" + # Get carry wire as input for the last adder in current row + if a_index == self.N-1: + index = index-2 + return self.components[index].get_carry_wire() + # Get sum wire as input for current adder + else: + return self.components[index].get_sum_wire() diff --git a/arithmetic_circuits_generator.py b/arithmetic_circuits_generator.py index a945da5..89053a5 100644 --- a/arithmetic_circuits_generator.py +++ b/arithmetic_circuits_generator.py @@ -7,119 +7,38 @@ import sys """ TESTING """ if __name__ == "__main__": - - a = bus(N=20, prefix="a") + a = bus(N=10, prefix="a") b = bus(N=1, prefix="b") - rca = signed_ripple_carry_adder(a, b, prefix="f_s_rca2") + rca = unsigned_ripple_carry_adder(a, b, prefix="h_u_rca8") - rca.get_cgp_code(open("s_rca2.chr","w")) - #rca.get_v_code_hier(open("h_s_rca6.v", "w")) - #rca.get_v_code_flat(open("FLATTEST_u_rca3.v", "w")) - """ - rca.get_c_code_hier(open("h_s_rca8.c", "w")) - rca.get_c_code_flat(open("f_s_rca8.c", "w")) - rca.get_c_code_hier(open("h_s_rca8.c", "w")) - rca.get_c_code_flat(open("f_s_rca8.c", "w")) - + # rca.get_v_code_hier(open("h_u_rca8.v", "w")) + # rca.get_c_code_hier(open("h_u_rca8.c", "w")) - rca.get_c_code_hier(open("h_s_rca8.c", "w")) - rca.get_v_code_hier(open("h_s_rca8.v", "w")) - rca.get_c_code_flat(open("f_s_rca8.c", "w")) - rca.get_v_code_flat(open("f_s_rca8.v", "w")) - """ + arrmul = unsigned_array_multiplier(a, b, prefix="f_u_arr_mul10") + arrmul.get_c_code_flat(open("f_u_arr_mul10.c", "w")) + arrmul.get_v_code_flat(open("f_u_arr_mul10.v", "w")) - #arrmul = signed_array_multiplier(a, b, prefix="f_s_arr_mul3") - u_arrmul = unsigned_array_multiplier(a, b, prefix="h_u_arr_mul5") - #u_arrmul.get_cgp_code(open("u_arr_mul5.chr","w")) - - s_arrmul = signed_array_multiplier(a, b) - s_arrmul.get_v_code_hier(open("testhier4.v","w")) - s_arrmul.get_v_code_flat(open("testflat4.v","w")) - - s_arrmul.get_cgp_code(open("s_arr_mul20.chr","w")) - #s_arrmul.get_v_code_hier(open("h_s_arr_mul3.v","w")) - - - s_arrmul.get_c_code_hier(open("h_s_arr_mul5.c","w")) - s_arrmul.get_c_code_flat(open("f_s_arr_mul5.c","w")) - s_arrmul.get_v_code_hier(open("h_s_arr_mul5.v","w")) - s_arrmul.get_v_code_flat(open("f_s_arr_mul5.v","w")) - s_arrmul.get_c_code_hier(open("h_s_arr_mul5.c","w")) - s_arrmul.get_c_code_flat(open("f_s_arr_mul5.c","w")) - s_arrmul.get_v_code_hier(open("h_s_arr_mul5.v","w")) - s_arrmul.get_v_code_flat(open("f_s_arr_mul5.v","w")) - - - #u_arrmul.get_v_code_hier(open("h_u_arr_mul3.v","w")) - #s_arrmul.get_v_code_hier(open("h_s_arr_mul3.v","w")) - - """ - arrmul.get_c_code_hier(open("h_s_arr_mul6.c","w")) - arrmul.get_c_code_flat(open("ff_s_arr_mul6.c","w")) - arrmul.get_c_code_hier(open("h_s_arr_mul6.c","w")) - arrmul.get_c_code_flat(open("ff_s_arr_mul6.c","w")) - """ - - - """ - rca.get_v_code_hier(open("h_s_rca8.v", "w")) - rca.get_v_code_flat(open("f_s_rca8.v", "w")) - - rca.get_c_code_hier(open("h_s_rca2.c", "w")) - rca.get_v_code_hier(open("h_s_rca2.v", "w")) - rca.get_c_code_flat(open("f_s_rca2.c", "w")) - rca.get_v_code_flat(open("f_s_rca2.v", "w")) - """ - #rca.get_v_code_hier(open("h_u_rca3.v", "w")) - #rca.get_c_code_flat(open("f_u_rca3.c", "w")) - - - #rca.get_c_code_hier(open("hier_srca8.c", "w")) - #rca.get_c_code_flat(open("flat_srca8.c", "w")) + # arrmul.get_cgp_code_hier(open("s_arr_mul5.chr", "w")) + # rca.get_cgp_code_hier(open("s_rca5.chr", "w")) w1 = wire(name="a") w2 = wire(name="b") w3 = wire(name="cin") + ha = half_adder(w1, w2, prefix="f_ha") fa = full_adder(w1, w2, w3, prefix="f_fa") - #ha.get_cgp_code(open("ha.chr","w")) - #fa.get_cgp_code(open("fa.chr","w")) - """ - ha.get_c_code_flat(open("f_ha.c","w")) - ha.get_v_code_flat(open("f_ha.v","w")) - fa.get_c_code_flat(open("f_fa.c","w")) - fa.get_v_code_hier(open("f_fa.v","w")) - """ - ha.get_v_code_hier(open("h_ha.v","w")) - fa.get_v_code_hier(open("h_fa.v","w")) - - """ + ha.get_v_code_flat(open("f_ha.v","w")) ha.get_c_code_hier(open("h_ha.c","w")) ha.get_c_code_flat(open("f_ha.c","w")) - ha.get_c_code_hier(open("h_ha.c","w")) - ha.get_c_code_flat(open("f_ha.c","w")) - - fa.get_c_code_hier(open("h_fa.c","w")) - fa.get_c_code_flat(open("f_fa.c","w")) - fa.get_c_code_hier(open("h_fa.c","w")) - fa.get_c_code_flat(open("f_fa.c","w")) - - ha.get_v_code_hier(open("h_ha.v","w")) - ha.get_v_code_flat(open("f_ha.v","w")) - ha.get_v_code_hier(open("h_ha.v","w")) - ha.get_v_code_flat(open("f_ha.v","w")) - - fa.get_v_code_hier(open("h_fa.v","w")) - fa.get_v_code_flat(open("f_fa.v","w")) - fa.get_v_code_hier(open("h_fa.v","w")) - fa.get_v_code_flat(open("f_fa.v","w")) + ha.get_cgp_code(open("ha.chr","w")) """ gate = and_gate(w1, w2) - #gate.get_cgp_code(open("and_gate.chr","w")) + """ #gate.get_c_code(open("and_gate.c","w")) #gate.get_v_code(open("and_gate.v","w")) - \ No newline at end of file + #gate.get_cgp_code(open("and_gate.chr","w")) + """ diff --git a/logic_gates.py b/logic_gates.py index 53d0af7..f17e26b 100644 --- a/logic_gates.py +++ b/logic_gates.py @@ -31,10 +31,10 @@ class logic_gate(): def get_init_c_flat(self): return f"{self.a.name} {self.operator} {self.b.name}" - def get_assign_c_flat(self, prefix_a: str = "a", prefix_b: str = "b", offset: int = 0): - return f" {self.a.name} = {self.a.get_wire_value_c(prefix=prefix_a, offset=offset)};\n" + \ - f" {self.b.name} = {self.b.get_wire_value_c(prefix=prefix_b, offset=offset)};\n" + \ - f" {self.out.prefix} = {self.a.name} {self.operator} {self.b.name};\n" + def get_assign_c_flat(self): + return f"{self.a.get_assign_c(name=self.a.name.replace(self.prefix+'_', ''))}" + \ + f"{self.b.get_assign_c(name=self.b.name.replace(self.prefix+'_', ''))}" + \ + f" {self.out.prefix} = {self.get_init_c_flat()};\n" # Generating flat C code representation of the logic gate itself # (i.e. not as a component of bigger circuit) @@ -46,20 +46,17 @@ class logic_gate(): # HIERARCHICAL C # def get_function_block_c(self): - return f"{self.get_prototype_c()}" + \ - f" return "+(self.get_function_c())+";\n}\n\n" + gate_block = not_gate(a=wire(name="a")) if isinstance(self, not_gate) else type(self)(a=wire(name="a"), b=wire(name="b")) + return f"{gate_block.get_prototype_c()}" + \ + f" return "+(gate_block.get_function_c())+";\n}\n\n" - def get_gate_invocation_c(self, a: wire, b: wire, sign: bool = False, get_index: bool = False): - a_name = a.prefix if sign is False else a.name - b_name = b.prefix if sign is False else b.name - a_name = a_name if get_index is False else "a" + a.name[a.name.rfind("_"):] - b_name = b_name if get_index is False else "b" + b.name[b.name.rfind("_"):] - return f"{self.gate_type}({a_name}, {b_name});" + def get_gate_invocation_c(self, remove_prefix: bool = True): + a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name + b_name = self.b.name.replace(self.prefix+"_", "") if remove_prefix is True else self.b.name + return f"{self.gate_type}({a_name}, {b_name});\n" - def get_gate_output_c(self, a: wire, b: wire, offset: int = 0, sign: bool = False): - a_name = a.prefix if sign is False else a.name - b_name = b.prefix if sign is False else b.name - return f"({self.gate_type}({a_name}, {b_name}) & 0x01) << {offset}" + def get_gate_output_c(self, a: wire, b: wire, offset: int = 0): + return f"({self.gate_type}({a.name}, {b.name}) & 0x01) << {offset}" """ VERILOG CODE GENERATION """ # FLAT VERILOG # @@ -72,10 +69,10 @@ class logic_gate(): def get_init_v_flat(self): return f"{self.a.name} {self.operator} {self.b.name}" - def get_assign_v_flat(self, prefix_a: str = "a", prefix_b: str = "b", offset: int = 0, array: bool = False): - return f" assign {self.a.name} = {self.a.get_wire_value_v(prefix=prefix_a, offset=offset, array=array)};\n" + \ - f" assign {self.b.name} = {self.b.get_wire_value_v(prefix=prefix_b, offset=offset, array=array)};\n" + \ - f" assign {self.out.prefix} = {self.a.name} {self.operator} {self.b.name};" + def get_assign_v_flat(self): + return f"{self.a.get_assign_v(name=self.a.name.replace(self.prefix+'_', ''))}" + \ + f"{self.b.get_assign_v(name=self.b.name.replace(self.prefix+'_', ''))}" + \ + f" assign {self.out.prefix} = {self.get_init_v_flat()};\n" # Generating flat Verilog code representation of the logic gate itself # (i.e. not as a component of bigger circuit) @@ -87,16 +84,15 @@ class logic_gate(): # HIERARCHICAL VERILOG # def get_function_block_v(self): - return f"{self.get_prototype_v()}" + \ - f" assign {self.out.name} = {self.get_init_v_flat()};\n" + \ + gate_block = not_gate(a=wire(name="a")) if isinstance(self, not_gate) else type(self)(a=wire(name="a"), b=wire(name="b")) + return f"{gate_block.get_prototype_v()}" + \ + f" assign {gate_block.out.name} = {gate_block.get_init_v_flat()};\n" + \ f"endmodule\n\n" - def get_gate_invocation_v(self, a: wire, b: wire, out: wire, sign: bool = False, get_index: bool = False, out_array: bool = False, offset: int = 0): - a_name = a.prefix if sign is False else a.name - b_name = b.prefix if sign is False else b.name - a_name = a_name if get_index is False else "a" + a.name[a.name.rfind("_"):] - b_name = b_name if get_index is False else "b" + b.name[b.name.rfind("_"):] - return f" {self.gate_type} {self.gate_type}_{out.name}({a_name}, {b_name}, {out.get_wire_value_v(offset=offset, array=out_array)});" + def get_gate_invocation_v(self, remove_prefix: bool = True): + a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name + b_name = self.b.name.replace(self.prefix+"_", "") if remove_prefix is True else self.b.name + return f" {self.gate_type} {self.gate_type}_{self.out.name}({a_name}, {b_name}, {self.out.name});\n" """ CGP CODE GENERATION """ # FLAT CGP # @@ -127,6 +123,9 @@ class inverted_logic_gate(logic_gate): def get_function_c(self): return "~("+(super().get_function_c())+") & 0x01 << 0" + def get_init_c_flat(self): + return "~("+(super().get_init_c_flat())+")" + """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_init_v_flat(self): @@ -141,26 +140,6 @@ class and_gate(logic_gate): self.operator = "&" self.out = wire(name=prefix+"_y"+str(outid)) - """ C CODE GENERATION """ - # FLAT C # - def get_assign_c_flat(self, prefix_a: str = "a", prefix_b: str = "b"): - indexes = self.prefix[self.prefix.rfind("_", 0, self.prefix.rfind("_"))+1:] - offset_a = indexes[:indexes.rfind("_")] - offset_b = indexes[indexes.rfind("_")+1:] - return f" {self.a.name} = {self.a.get_wire_value_c(prefix=prefix_a, offset=offset_a)};\n" + \ - f" {self.b.name} = {self.b.get_wire_value_c(prefix=prefix_b, offset=offset_b)};\n" + \ - f" {self.out.prefix} = {self.a.name} {self.operator} {self.b.name};\n" - - """ VERILOG CODE GENERATION """ - # FLAT VERILOG # - def get_assign_v_flat(self, prefix_a: str = "a", prefix_b: str = "b", offset: int = 0, array: bool = False): - indexes = self.prefix[self.prefix.rfind("_", 0, self.prefix.rfind("_"))+1:] - offset_a = indexes[:indexes.rfind("_")] - offset_b = indexes[indexes.rfind("_")+1:] - return f" assign {self.a.name} = {self.a.get_wire_value_v(prefix=prefix_a, offset=offset_a, array=array)};\n" + \ - f" assign {self.b.name} = {self.b.get_wire_value_v(prefix=prefix_b, offset=offset_b, array=array)};\n" + \ - f" assign {self.out.prefix} = {self.a.name} {self.operator} {self.b.name};" - class nand_gate(inverted_logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "", outid: int = 0): @@ -170,26 +149,6 @@ class nand_gate(inverted_logic_gate): self.operator = "&" self.out = wire(name=prefix+"_y"+str(outid)) - """ C CODE GENERATION """ - # FLAT C # - def get_assign_c_flat(self, prefix_a: str = "a", prefix_b: str = "b"): - indexes = self.prefix[self.prefix.rfind("_", 0, self.prefix.rfind("_"))+1:] - offset_a = indexes[:indexes.rfind("_")] - offset_b = indexes[indexes.rfind("_")+1:] - return f" {self.a.name} = {self.a.get_wire_value_c(prefix=prefix_a, offset=offset_a)};\n" + \ - f" {self.b.name} = {self.b.get_wire_value_c(prefix=prefix_b, offset=offset_b)};\n" + \ - f" {self.out.prefix} = ~({self.a.name} {self.operator} {self.b.name});\n" - - """ VERILOG CODE GENERATION """ - # FLAT VERILOG # - def get_assign_v_flat(self, prefix_a: str = "a", prefix_b: str = "b", offset: int = 0, array: bool = False): - indexes = self.prefix[self.prefix.rfind("_", 0, self.prefix.rfind("_"))+1:] - offset_a = indexes[:indexes.rfind("_")] - offset_b = indexes[indexes.rfind("_")+1:] - return f" assign {self.a.name} = {self.a.get_wire_value_v(prefix=prefix_a, offset=offset_a, array=array)};\n" + \ - f" assign {self.b.name} = {self.b.get_wire_value_v(prefix=prefix_b, offset=offset_b, array=array)};\n" + \ - f" assign {self.out.prefix} = ~({self.a.name} {self.operator} {self.b.name});" - class or_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "", outid: int = 0): @@ -245,25 +204,23 @@ class not_gate(inverted_logic_gate): def get_function_c(self): return f"{self.operator}{self.a.get_wire_value_c()} & 0x01 << 0" - def get_declaration_c(self): + def get_declaration_c_flat(self): return f"{self.a.get_declaration_c()}{self.out.get_declaration_c()}" def get_init_c_flat(self): return f"{self.operator}{self.a.name}" - def get_assign_c_flat(self, prefix_a: str = "a", offset: int = 0): - return f" {self.a.name} = {self.a.get_wire_value_c(prefix=prefix_a, offset=offset)};\n" + \ - f" {self.out.prefix} = {self.operator}{self.a.name};\n" + def get_assign_c_flat(self): + return f"{self.a.get_assign_c(name=self.a.name.replace(self.prefix+'_', ''))}" + \ + f" {self.out.prefix} = {self.get_init_c_flat()};\n" # HIERARCHICAL C # - def get_gate_invocation_c(self, a: wire, sign: bool = False, get_index: bool = False): - a_name = a.prefix if sign is False else a.name - a_name = a_name if get_index is False else "a" + a.name[a.name.rfind("_"):] + def get_gate_invocation_c(self, remove_prefix: bool = True): + a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name return f"{self.gate_type}({a_name});" - def get_gate_output_c(self, a: wire, offset: int = 0, sign: bool = False): - a_name = a.prefix if sign is False else a.name - return f"({self.gate_type}({a_name}) & 0x01) << {offset}" + def get_gate_output_c(self, a: wire, offset: int = 0): + return f"({self.gate_type}({a.name}) & 0x01) << {offset}" """ VERILOG CODE GENERATION """ # FLAT VERILOG # @@ -276,15 +233,14 @@ class not_gate(inverted_logic_gate): def get_init_v_flat(self): return f"{self.operator}{self.a.name}" - def get_assign_v_flat(self, prefix_a: str = "a", offset: int = 0, array: bool = False): - return f" assign {self.a.name} = {self.a.get_wire_value_v(prefix=prefix_a, offset=offset, array=array)};\n" + \ - f" assign {self.out.prefix} = {self.operator}{self.a.name};" + def get_assign_v_flat(self): + return f"{self.a.get_assign_v(name=self.a.name.replace(self.prefix+'_', ''))}" + \ + f" assign {self.out.prefix} = {self.get_init_v_flat()};\n" # HIERARCHICAL VERILOG # - def get_gate_invocation_v(self, a: wire, out: wire, sign: bool = False, get_index: bool = False, out_array: bool = False, offset: int = 0): - a_name = a.prefix if sign is False else a.name - a_name = a_name if get_index is False else "a" + a.name[a.name.rfind("_"):] - return f" {self.gate_type} {self.gate_type}_{out.name}({a_name}, {out.get_wire_value_v(offset=offset, array=out_array)});" + def get_gate_invocation_v(self, remove_prefix: bool = True): + a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name + return f" {self.gate_type} {self.gate_type}_{self.out.name}({a_name}, {self.out.name});\n" """ CGP CODE GENERATION """ # FLAT CGP # diff --git a/multi_bit_circuits.py b/multi_bit_circuits.py index 8196f78..68fbcfc 100644 --- a/multi_bit_circuits.py +++ b/multi_bit_circuits.py @@ -1,4 +1,4 @@ -from arithmetic_circuits import arithmetic_circuit, signed_adder_circuit, signed_multiplier_circuit +from arithmetic_circuits import arithmetic_circuit, multiplier_circuit from one_bit_circuits import half_adder, full_adder from logic_gates import logic_gate, and_gate, nand_gate, or_gate, nor_gate, xor_gate, xnor_gate, not_gate from wire_components import wire, bus @@ -31,6 +31,9 @@ class unsigned_ripple_carry_adder(arithmetic_circuit): obj_ha = half_adder(a.get_wire(input_index), b.get_wire(input_index), prefix=self.prefix+"_ha") self.add_component(obj_ha) self.out.connect(input_index, obj_ha.get_sum_wire()) + + if input_index == (self.N-1): + self.out.connect(self.N, obj_ha.get_carry_wire()) # Rest are full adders else: obj_fa = full_adder(a.get_wire(input_index), b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index)) @@ -41,7 +44,7 @@ class unsigned_ripple_carry_adder(arithmetic_circuit): self.out.connect(self.N, obj_fa.get_carry_wire()) -class signed_ripple_carry_adder(unsigned_ripple_carry_adder, signed_adder_circuit): +class signed_ripple_carry_adder(unsigned_ripple_carry_adder, arithmetic_circuit): def __init__(self, a: bus, b: bus, prefix: str = "s_rca"): super().__init__(a=a, b=b, prefix=prefix) self.c_data_type = "int64_t" @@ -55,7 +58,7 @@ class signed_ripple_carry_adder(unsigned_ripple_carry_adder, signed_adder_circui # MULTIPLIERS -class unsigned_array_multiplier(arithmetic_circuit): +class unsigned_array_multiplier(multiplier_circuit): def __init__(self, a: bus, b: bus, prefix: str = "u_arr_mul"): super().__init__() self.N = max(a.N, b.N) @@ -70,7 +73,7 @@ class unsigned_array_multiplier(arithmetic_circuit): self.prefix = prefix # Output wires for multiplication product - self.out = bus("out", self.N*2) if self.N > 1 else bus("out", self.N) + self.out = bus("out", self.N*2) # Gradual generation of partial products for b_multiplier_index in range(self.N): @@ -102,6 +105,19 @@ class unsigned_array_multiplier(arithmetic_circuit): 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_xor = xor_gate(self.a.get_wire(), self.b.get_wire(), prefix=self.prefix+"_xor_constant_wire") + obj_xnor = xnor_gate(self.a.get_wire(), self.b.get_wire(), prefix=self.prefix+"_xnor_constant_wire") + obj_and = and_gate(obj_xor.out, obj_xnor.out, prefix=self.prefix+"_and_constant_wire") + obj_and.out.name = "constant_wire" + obj_and.out.prefix = "constant_wire" + self.add_component(obj_xor) + self.add_component(obj_xnor) + self.add_component(obj_and) + + self.out.connect(a_multiplicand_index+1, obj_and.out) + elif b_multiplier_index == self.N-1: self.out.connect(b_multiplier_index + a_multiplicand_index, obj_adder.get_sum_wire()) @@ -109,7 +125,7 @@ class unsigned_array_multiplier(arithmetic_circuit): self.out.connect(self.out.N-1, obj_adder.get_carry_wire()) -class signed_array_multiplier(signed_multiplier_circuit): +class signed_array_multiplier(multiplier_circuit): def __init__(self, a: bus, b: bus, prefix: str = "s_arr_mul"): super().__init__() self.c_data_type = "int64_t" @@ -124,11 +140,23 @@ class signed_array_multiplier(signed_multiplier_circuit): else: self.prefix = prefix - # TODO CHANGE SIGNED MULTIPLIER CIRCUIT (REPLACE CONSTANT WIRE WITH LOGIC GATES) - self.constant_wire = wire(name="constant_wire", value=1) - # Output wires for multiplication product - self.out = bus("out", self.N*2) if self.N > 1 else bus("out", self.N) + self.out = bus("out", self.N*2) + + # Generating wire with constant logic value 1 (output of the or gate) + obj_xor = xor_gate(self.a.get_wire(), self.b.get_wire(), prefix=self.prefix+"_xor_constant_wire") + obj_xnor = xnor_gate(self.a.get_wire(), self.b.get_wire(), prefix=self.prefix+"_xnor_constant_wire") + obj_or = or_gate(obj_xor.out, obj_xnor.out, prefix=self.prefix+"_or_constant_wire") + obj_or.out.name = "constant_wire" + obj_or.out.prefix = "constant_wire" + + self.add_component(obj_xor) + self.add_component(obj_xnor) + self.add_component(obj_or) + + # To adjust proper wire connection between adders and AND/NAND gates + # we add offset equal to first 3 gates in circuits components list (that are present to prevent the need to use constant wire with logic value 1) + components_offset = 3 # Gradual generation of partial products for b_multiplier_index in range(self.N): @@ -142,7 +170,7 @@ class signed_array_multiplier(signed_multiplier_circuit): 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) + previous_product = self.components[a_multiplicand_index + b_multiplier_index + components_offset].out if b_multiplier_index == 1 else self.get_previous_partial_product(a_index=a_multiplicand_index, b_index=b_multiplier_index, offset=components_offset) # HA generation for first 1-bit adder in each row starting from the second one if a_multiplicand_index == 0: obj_adder = half_adder(self.get_previous_component().out, previous_product, prefix=self.prefix+"_ha_"+str(a_multiplicand_index)+"_"+str(b_multiplier_index)) @@ -153,7 +181,7 @@ class signed_array_multiplier(signed_multiplier_circuit): # FA generation else: if a_multiplicand_index == self.N-1 and b_multiplier_index == 1: - previous_product = self.constant_wire + previous_product = obj_or.out obj_adder = full_adder(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) @@ -162,11 +190,18 @@ class signed_array_multiplier(signed_multiplier_circuit): 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 = nor_gate(obj_or.out, self.get_previous_component().out, prefix=self.prefix+"_nor_zero_extend") + 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_adder = half_adder(self.get_previous_component().get_carry_wire(), self.constant_wire, prefix=self.prefix+"_ha_"+str(a_multiplicand_index+1)+"_"+str(b_multiplier_index)) - self.add_component(obj_adder) + obj_xor = xor_gate(self.get_previous_component().get_carry_wire(), obj_or.out, prefix=self.prefix+"_xor_"+str(a_multiplicand_index+1)+"_"+str(b_multiplier_index)) + self.add_component(obj_xor) - self.out.connect(self.out.N-1, obj_adder.get_sum_wire()) + self.out.connect(self.out.N-1, obj_xor.out) diff --git a/one_bit_circuits.py b/one_bit_circuits.py index f52f707..75d191b 100644 --- a/one_bit_circuits.py +++ b/one_bit_circuits.py @@ -14,47 +14,36 @@ class one_bit_circuit(arithmetic_circuit): # Obtaining list of all the unique circuit wires from all contained logic gates # to ensure non-recurring declaration of same wires def get_declaration_c_flat(self): - self.circuit_wires = [] self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) - # 2 bit input adder wire values initialization + # Half adder (2 inputs adder) wires values initialization def get_init_c_flat(self): - return f"{self.components[0].get_assign_c_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix)}" + \ - f" {self.components[1].out.name} = {self.components[1].get_init_c_flat()};\n" + return f"{self.components[0].a.get_assign_c(name=self.components[0].a.get_wire_value_c(name=self.a.name))}" + \ + f"{self.components[0].b.get_assign_c(name=self.components[0].b.get_wire_value_c(name=self.b.name))}" + \ + "".join([f" {c.out.name} = {c.get_init_c_flat()};\n" for c in self.components]) # HIERARCHICAL C # def get_function_block_c(self): - self.component_types = self.get_component_types() - self.prefix = "ha" if isinstance(self, half_adder) else "fa" - return f"{self.get_circuit_c()}\n\n" - - def get_declaration_c_hier(self): - return f"{self.component_types[0].a.get_declaration_c()}" + \ - f"{self.component_types[2].a.get_declaration_c()}" + \ - f"{self.component_types[2].b.get_declaration_c()}" - - def get_init_c_hier(self): - return f" {self.component_types[0].a.name} = {self.component_types[0].get_gate_invocation_c(self.a, self.b)}\n" + \ - f" {self.component_types[2].a.name} = {self.component_types[1].get_gate_invocation_c(self.a, self.b)}\n" + \ - f" {self.component_types[2].b.name} = {self.component_types[1].get_gate_invocation_c(self.component_types[0].a, self.c)}\n" + adder_block = half_adder(a=wire(name="a"), b=wire(name="b")) if isinstance(self, half_adder) else full_adder(a=wire(name="a"), b=wire(name="b"), c=wire(name="cin")) + return f"{adder_block.get_circuit_c()}\n\n" def get_out_invocation_c(self): return self.get_sum_invocation_c()+"\n" + \ - self.get_cout_invocation_c() + self.get_cout_invocation_c()+"\n" def get_sum_invocation_c(self): - return f" {self.get_sum_wire().name} = ({self.prefix}({self.a.name}, {self.b.name}) >> 0) & 0x01;" + return f" {self.get_sum_wire().name} = (ha({self.a.name}, {self.b.name}) >> 0) & 0x01;" def get_cout_invocation_c(self): - return f" {self.get_carry_wire().name} = ({self.prefix}({self.a.name}, {self.b.name}) >> 1) & 0x01;" + return f" {self.get_carry_wire().name} = (ha({self.a.name}, {self.b.name}) >> 1) & 0x01;" def get_function_sum_c_hier(self, offset: int = 0): - return f" {self.out.prefix} |= {self.component_types[0].get_gate_output_c(a=self.a ,b=self.b, offset=offset)};\n" + return f" {self.out.prefix} |= {self.components[0].get_gate_output_c(a=self.a ,b=self.b, offset=offset)};\n" def get_function_carry_c_hier(self, offset: int = 1): - return f" {self.out.prefix} |= {self.component_types[1].get_gate_output_c(a=self.a ,b=self.b, offset=offset)};\n" + return f" {self.out.prefix} |= {self.components[1].get_gate_output_c(a=self.a ,b=self.b, offset=offset)};\n" def get_circuit_c(self): return f"{self.get_prototype_c()}" + \ @@ -69,43 +58,32 @@ class one_bit_circuit(arithmetic_circuit): return f"module {self.prefix}(input {self.a.name}, input {self.b.name}, output {self.out.get_wire(0).name}, output {self.out.get_wire(1).name});\n" def get_declaration_v_flat(self): - self.circuit_wires = [] self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_v() for c in self.circuit_wires]) - # Half adder wires values initialization - def get_init_v_flat(self, offset: int = 0, array: bool = False): - return f"{self.components[0].get_assign_v_flat(prefix_a=self.a.prefix, prefix_b=self.b.prefix, offset=offset, array=array)}\n" + \ - f" assign {self.components[1].out.name} = {self.components[1].get_init_v_flat()};" + # Half adder (2 inputs adder) wires values initialization + def get_init_v_flat(self): + return f"{self.components[0].get_assign_v_flat()}" + \ + f" assign {self.components[1].out.name} = {self.components[1].get_init_v_flat()};\n" + # Not used in 1 bit circuits (no effect when calling while generating) def get_function_out_v_flat(self): return "" # HIERARCHICAL VERILOG # def get_function_block_v(self): - self.component_types = self.get_component_types() - self.prefix = "ha" if isinstance(self, half_adder) else "fa" - return f"{self.get_circuit_v()}\n\n" - - def get_declaration_v_hier(self): - return f"{self.component_types[0].a.get_declaration_v()}" + \ - f"{self.component_types[2].a.get_declaration_v()}" + \ - f"{self.component_types[2].b.get_declaration_v()}" - - def get_init_v_hier(self): - return f" {self.component_types[0].gate_type} {self.component_types[0].gate_type}_{self.component_types[0].a.name}({self.a.name}, {self.b.name}, {self.component_types[0].a.name});\n" + \ - f" {self.component_types[1].gate_type} {self.component_types[1].gate_type}_{self.component_types[2].a.name}({self.a.name}, {self.b.name}, {self.component_types[2].a.name});\n" + \ - f" {self.component_types[1].gate_type} {self.component_types[1].gate_type}_{self.component_types[2].b.name}({self.component_types[0].a.name}, {self.c.name}, {self.component_types[2].b.name});\n" + adder_block = half_adder(a=wire(name="a"), b=wire(name="b")) if isinstance(self, half_adder) else full_adder(a=wire(name="a"), b=wire(name="b"), c=wire(name="cin")) + return f"{adder_block.get_circuit_v()}\n\n" def get_invocation_v(self): - return f" ha ha_{self.get_carry_wire().name}({self.a.name}, {self.b.name}, {self.get_sum_wire().name}, {self.get_carry_wire().name});" + return f" ha ha_{self.get_carry_wire().name}({self.a.name}, {self.b.name}, {self.get_sum_wire().name}, {self.get_carry_wire().name});\n" def get_function_sum_v_hier(self): - return f"{self.components[0].get_gate_invocation_v(a=self.a, b=self.b, out=self.components[0].out, sign=True)}\n" + return f"{self.components[0].get_gate_invocation_v()}" def get_function_carry_v_hier(self): - return f"{self.components[1].get_gate_invocation_v(a=self.a, b=self.b, out=self.components[1].out, sign=True)}\n" + return f"{self.components[1].get_gate_invocation_v()}" def get_circuit_v(self): return f"{self.get_prototype_v()}" + \ @@ -182,27 +160,37 @@ class full_adder(one_bit_circuit): # Full adder wires values initialization def get_init_c_flat(self): - return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index, prefix=self.a.prefix)};\n" + \ - f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index, prefix=self.b.prefix)};\n" + \ - f" {self.components[2].b.name} = {self.c.get_wire_value_c()};\n" + \ - f" {self.components[0].out.name} = {self.components[0].get_init_c_flat()};\n" + \ - f" {self.components[1].out.name} = {self.components[1].get_init_c_flat()};\n" + \ - f" {self.components[2].out.name} = {self.components[2].get_init_c_flat()};\n" + \ - f" {self.components[3].out.name} = {self.components[3].get_init_c_flat()};\n" + \ - f" {self.components[4].out.name} = {self.components[4].get_init_c_flat()};\n" + return f"{self.components[0].a.get_assign_c(name=self.components[0].a.get_wire_value_c(name=self.a.name))}" + \ + f"{self.components[0].b.get_assign_c(name=self.components[0].b.get_wire_value_c(name=self.b.name))}" + \ + f"{self.components[2].b.get_assign_c(name=self.components[2].b.get_wire_value_c(name=self.c.name))}" + \ + "".join([f" {c.out.name} = {c.get_init_c_flat()};\n" for c in self.components]) # HIERARCHICAL C # + def get_declaration_c_hier(self): + return f"{self.components[0].out.get_declaration_c()}" + \ + f"{self.components[1].out.get_declaration_c()}" + \ + f"{self.components[3].out.get_declaration_c()}" + + def get_init_c_hier(self): + # Temporarily change cin name for proper gate invocation + self.components[2].b.name = self.components[3].b.name = self.components[2].b.name.replace(self.prefix+"_", "") + return f" {self.components[0].out.name} = {self.components[0].get_gate_invocation_c()}" + \ + f" {self.components[1].out.name} = {self.components[1].get_gate_invocation_c()}" + \ + f" {self.components[3].out.name} = {self.components[3].get_gate_invocation_c(remove_prefix=False)}" + def get_sum_invocation_c(self): - return f" {self.get_sum_wire().name} = ({self.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> 0) & 0x01;" + return f" {self.get_sum_wire().name} = (fa({self.a.name}, {self.b.name}, {self.c.name}) >> 0) & 0x01;" def get_cout_invocation_c(self): - return f" {self.get_carry_wire().name} = ({self.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> 1) & 0x01;" + return f" {self.get_carry_wire().name} = (fa({self.a.name}, {self.b.name}, {self.c.name}) >> 1) & 0x01;" def get_function_sum_c_hier(self, offset: int = 0): - return f" {self.out.prefix} |= {self.component_types[0].get_gate_output_c(a=self.component_types[0].a, b=self.c, offset=offset)};\n" + return f" {self.out.prefix} |= {self.components[0].get_gate_output_c(a=self.components[0].out, b=self.c, offset=offset)};\n" def get_function_carry_c_hier(self, offset: int = 1): - return f" {self.out.prefix} |= {self.get_previous_component().get_gate_output_c(a=self.component_types[2].a, b=self.component_types[2].b, offset=offset)};\n" + # Return cin name to previous string value for sake of consistency + self.components[2].b.name = self.components[3].b.name = self.prefix+"_"+self.c.name + return f" {self.out.prefix} |= {self.get_previous_component().get_gate_output_c(a=self.components[1].out, b=self.components[3].out, offset=offset)};\n" def get_circuit_c(self): return f"{self.get_prototype_c()}" + \ @@ -219,25 +207,35 @@ class full_adder(one_bit_circuit): return f"module {self.prefix}(input {self.a.name}, input {self.b.name}, input {self.c.name}, output {self.out.get_wire(0).name}, output {self.out.get_wire(1).name});\n" # Full adder wires values initialization - def get_init_v_flat(self, offset: int = 0, array: bool = False): - return f" assign {self.components[0].a.name} = {self.a.get_wire_value_v(offset=offset, prefix=self.a.prefix, array=array)};\n" + \ - f" assign {self.components[0].b.name} = {self.b.get_wire_value_v(offset=offset, prefix=self.b.prefix, array=array)};\n" + \ - f" assign {self.components[2].b.name} = {self.c.get_wire_value_v(offset=offset)};\n" + \ - f" assign {self.components[0].out.name} = {self.components[0].get_init_v_flat()};\n" + \ - f" assign {self.components[1].out.name} = {self.components[1].get_init_v_flat()};\n" + \ - f" assign {self.components[2].out.name} = {self.components[2].get_init_v_flat()};\n" + \ - f" assign {self.components[3].out.name} = {self.components[3].get_init_v_flat()};\n" + \ - f" assign {self.components[4].out.name} = {self.components[4].get_init_v_flat()};\n" + def get_init_v_flat(self): + return f"{self.components[0].a.get_assign_v(name=self.components[0].a.name.replace(self.prefix+'_', ''))}" + \ + f"{self.components[0].b.get_assign_v(name=self.components[0].b.name.replace(self.prefix+'_', ''))}" + \ + f"{self.components[2].b.get_assign_v(name=self.components[2].b.name.replace(self.prefix+'_', ''))}" + \ + "".join([f" assign {c.out.name} = {c.get_init_v_flat()};\n" for c in self.components]) # HIERARCHICAL VERILOG # def get_invocation_v(self): - return f" fa fa_{self.get_carry_wire().name}({self.a.name}, {self.b.name}, {self.c.name}, {self.get_sum_wire().name}, {self.get_carry_wire().name});" + return f" fa fa_{self.get_carry_wire().name}({self.a.name}, {self.b.name}, {self.c.name}, {self.get_sum_wire().name}, {self.get_carry_wire().name});\n" + + def get_declaration_v_hier(self): + return f"{self.components[0].out.get_declaration_v()}" + \ + f"{self.components[1].out.get_declaration_v()}" + \ + f"{self.components[3].out.get_declaration_v()}" + + def get_init_v_hier(self): + # Temporarily change cin name for proper gate invocation + self.components[2].b.name = self.components[3].b.name = self.components[2].b.name.replace(self.prefix+"_", "") + return f"{self.components[0].get_gate_invocation_v()}" + \ + f"{self.components[1].get_gate_invocation_v()}" + \ + f"{self.components[3].get_gate_invocation_v(remove_prefix=False)}" def get_function_sum_v_hier(self): - return f"{self.components[0].get_gate_invocation_v(a=self.component_types[0].a, b=self.c, out=self.out.get_wire(0))}\n" + return f"{self.components[2].get_gate_invocation_v(remove_prefix=False)}" def get_function_carry_v_hier(self): - return f"{self.components[-1].get_gate_invocation_v(a=self.component_types[2].a, b=self.component_types[2].b, out=self.out.get_wire(1))}\n" + # Return cin name to previous string value for sake of consistency + self.components[2].b.name = self.components[3].b.name = self.prefix+"_"+self.c.name + return f"{self.components[4].get_gate_invocation_v(remove_prefix=False)}" def get_circuit_v(self): return f"{self.get_prototype_v()}" + \ diff --git a/wire_components.py b/wire_components.py index a907ed5..ed3ec94 100644 --- a/wire_components.py +++ b/wire_components.py @@ -11,33 +11,29 @@ class wire(): self.value = value self.index = index - # C CODE GENERATION # + """ C CODE GENERATION """ def get_declaration_c(self): return f" uint8_t {self.name} = {self.value};\n" - def get_wire_value_c(self, offset: int = 0, prefix: str = ""): - name = self.name if prefix == "" else prefix - return f"(({name} >> {offset}) & 0x01)" + def get_wire_value_c(self, name: str = "", offset: int = 0): + w_name = self.name if name == "" else name + return f"(({w_name} >> {offset}) & 0x01)" + + def get_assign_c(self, name: str): + return f" {self.name} = {name};\n" def return_wire_value_c(self, offset: int = 0): return f"({self.name} & 0x01) << {offset}" - # VERILOG CODE GENERATION # + """ VERILOG CODE GENERATION """ def get_declaration_v(self): return f" wire {self.name};\n" - def get_declaration_init_v(self): - return f" wire {self.name} = {self.value};\n" - - def get_wire_value_v(self, offset: int = 0, prefix: str = "", array: bool = False): - name = self.name if prefix == "" else prefix + def get_assign_v(self, name: str, offset: int = 0, array: bool = False): if array is True: - return f"{name}[{offset}]" + return f" assign {self.name} = {name}[{offset}];\n" else: - return f"{name}" - - def return_wire_value_v(self): - return f"{self.name}" + return f" assign {self.name} = {name};\n" class bus(): @@ -46,9 +42,6 @@ class bus(): self.prefix = prefix self.N = N - def __index__(self, wire): - return self.bus.index(wire) - # Connecting output wire of the inner circuit component to the input of another component # (or to the wire of the circuit's output bus) def connect(self, out_wire_index: int, inner_component_out_wire: wire): @@ -61,25 +54,25 @@ class bus(): self.bus = [wire(name=prefix+"_"+str(i), index=i) for i in range(N)] self.N = N - # C CODE GENERATION # - def get_wire_value_c(self, offset: int = 0, prefix: str = ""): - return self.get_wire(wire_index=offset).get_wire_value_c(offset=offset, prefix=prefix) - - def get_wire_declaration_c(self): - return "".join([w.get_declaration_c() for w in self.bus]) - + """ C CODE GENERATION """ def get_declaration_c(self): if self.N > 8: return f" uint64_t {self.prefix} = 0;\n" else: return f" uint8_t {self.prefix} = 0;\n" + def get_wire_declaration_c(self): + return "".join([w.get_declaration_c() for w in self.bus]) + + def get_wire_assign_c(self): + return "".join([w.get_assign_c(name=w.get_wire_value_c(name=self.prefix, offset=self.bus.index(w))) for w in self.bus]) + def return_wire_value_c(self, offset: int = 0): self.get_wire(wire_index=offset).return_wire_value_c(offset=offset) - # VERILOG CODE GENERATION # - def get_wire_value_v(self, offset: int = 0, prefix: str = "", array: bool = False): - return self.get_wire(wire_index=offset).get_wire_value_v(offset=offset, prefix=prefix, array=array) - + """ VERILOG CODE GENERATION """ def get_wire_declaration_v(self): return "".join([w.get_declaration_v() for w in self.bus]) + + def get_wire_assign_v(self): + return "".join([w.get_assign_v(name=self.prefix, offset=self.bus.index(w), array=True) for w in self.bus])