diff --git a/arithmetic_circuits_generator.py b/arithmetic_circuits_generator.py index 4d51b7a..d2cb9bb 100644 --- a/arithmetic_circuits_generator.py +++ b/arithmetic_circuits_generator.py @@ -1,6 +1,7 @@ from wire_components import wire, bus -from logic_gates_generator import and_gate, xor_gate, or_gate +from logic_gates_generator import not_gate, and_gate, xor_gate, or_gate, nand_gate, xnor_gate, nor_gate import sys +import itertools """ ARITHMETIC CIRCUITS """ @@ -13,7 +14,6 @@ class arithmetic_circuit(): self.c_data_type = "uint64_t" # TODO delete? - self.input_N = 0 self.carry_out_gate = None self.sum_out_gates = [] @@ -23,6 +23,16 @@ class arithmetic_circuit(): def get_previous_component(self): return self.components[-1] + def get_component_types(self): + return list({type(c): c for c in self.components}.values()) + + def get_unique_types(self): + hier_components = self.all_gates + self.component_types + return list({type(c): c for c in hier_components}.values()) + + def get_gate_types(self): + return list({type(g): g for g in self.all_gates}.values()) + def get_sum_wire(self): return self.out.get_wire(0) @@ -35,34 +45,76 @@ class arithmetic_circuit(): return f"#include \n#include \n\n" def get_prototype_c(self): - return f"uint64_t {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + '\n' + return f"uint64_t {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + "\n" - def get_declaration_c(self): - return f"".join([c.get_declaration_c() for c in self.components]) + def get_declaration_c_flat(self): + return f"".join([c.get_declaration_c_flat() for c in self.components]) - def get_initialization_c(self): - return "".join([c.get_initialization_c() for c in self.components]) + def get_init_c_flat(self): + return "".join([c.get_init_c_flat() for c in self.components]) - def get_function_sum_c(self): - return "".join([c.get_function_sum_c(self.components.index(c)) for c in self.components]) + def get_function_sum_c_flat(self): + return "".join([c.get_function_sum_c_flat(offset=self.components.index(c)) for c in self.components]) - def get_function_carry_c(self): - return f"{self.get_previous_component().get_function_carry_c(offset=self.out.N-1)}" + def get_function_carry_c_flat(self): + return f"{self.get_previous_component().get_function_carry_c_flat(offset=self.out.N-1)}" # Generating flat C code representation of circuit - def get_c_code(self, file_object): + def get_c_code_flat(self, file_object): file_object.write(self.get_includes_c()) file_object.write(self.get_prototype_c()) file_object.write(self.out.get_declaration_c()) - file_object.write(self.get_declaration_c()+"\n") - file_object.write(self.get_initialization_c()+"\n") - file_object.write(self.get_function_sum_c()) - file_object.write(self.get_function_carry_c()) + file_object.write(self.get_declaration_c_flat()+"\n") + file_object.write(self.get_init_c_flat()+"\n") + file_object.write(self.get_function_sum_c_flat()) + file_object.write(self.get_function_carry_c_flat()) file_object.write(f" return {self.out.prefix}"+";\n}") file_object.close() # HIERARCHICAL C GENERATION # - # TODO + def get_function_blocks_c(self): + # Add unique 1-bit adder components (ha, fa) + self.component_types = self.get_component_types() + # Add unique logic gates composing subcomponents + self.all_gates = list(itertools.chain.from_iterable([c.get_component_types() for c in self.component_types])) + self.component_types = self.get_unique_types() + return "".join([c.get_function_block_c() for c in self.component_types]) + + def get_declaration_c_hier(self): + self.cout = bus(N=self.N-1, prefix="cout") + return "".join(self.a.get_wire_declaration_c()) + \ + "".join(self.b.get_wire_declaration_c()) + \ + "".join(self.cout.get_wire_declaration_c()) + + def get_init_sum_c_hier(self): + self.in_wires = self.a.bus + self.b.bus + return ";\n".join([f" {w.name} = " + w.get_wire_value_c(offset=int(w.name[2:])) for w in self.in_wires]) + + def get_init_cout_c_hier(self): + return "\n".join([c.get_invocation_c(wire_n=self.cout.get_wire(self.components.index(c)).name, offset=self.components.index(c)) for c in self.components[:-1]]) + + def get_function_sum_c_hier(self): + return ";\n".join([c.get_adder_sum(offset=self.components.index(c)) for c in self.components])+";\n" + + def get_function_carry_c_hier(self): + return f"{self.get_previous_component().get_adder_cout(offset=self.out.N-1)};\n" + + def get_circuit_c(self): + return f"{self.get_prototype_c()}" + \ + f"{self.out.get_declaration_c()}" + \ + f"{self.get_declaration_c_hier()}\n" + \ + f"{self.get_init_sum_c_hier()};\n" + \ + f"{self.get_init_cout_c_hier()}\n\n" + \ + f"{self.get_function_sum_c_hier()}" + \ + f"{self.get_function_carry_c_hier()}" + \ + f" return {self.out.prefix}"+";\n}" + + # Generating hierarchical C code representation of circuit + def get_c_code_hier(self, file_object): + file_object.write(self.get_includes_c()) + file_object.write(self.get_function_blocks_c()) + file_object.write(self.get_circuit_c()) + file_object.close() class half_adder(arithmetic_circuit): @@ -90,11 +142,11 @@ class half_adder(arithmetic_circuit): # FLAT C GENERATION # # Half adder function prototype with two inputs def get_prototype_c(self): - return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name})" + "{" + '\n' + return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name})" + "{" + "\n" # 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(self): + def get_declaration_c_flat(self): 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)) @@ -109,17 +161,52 @@ class half_adder(arithmetic_circuit): return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) # Half adder wires values initialization - def get_initialization_c(self): + def get_init_c_flat(self): + self.a.prefix = self.a.name if self.a.prefix == "" else self.a.prefix + self.b.prefix = self.b.name if self.b.prefix == "" else self.b.prefix return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \ f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \ - f" {self.components[0].output.name} = {self.components[0].get_initialization_c()};\n" + \ - f" {self.components[1].output.name} = {self.components[1].get_initialization_c()};\n" + f" {self.components[0].output.name} = {self.components[0].get_init_c_flat()};\n" + \ + f" {self.components[1].output.name} = {self.components[1].get_init_c_flat()};\n" - def get_function_sum_c(self, offset: int = 0): - return f" {self.out.prefix} |= {self.components[0].output.return_wire_value_c(offset = offset)};\n" + def get_function_sum_c_flat(self, offset: int = 0): + return f" {self.out.prefix} |= {self.components[0].output.return_wire_value_c(offset=offset)};\n" - def get_function_carry_c(self, offset: int = 1): - return f" {self.out.prefix} |= {self.components[1].output.return_wire_value_c(offset = offset)};\n" + def get_function_carry_c_flat(self, offset: int = 1): + return f" {self.out.prefix} |= {self.components[1].output.return_wire_value_c(offset=offset)};\n" + + # HIERARCHICAL C GENERATION # + def get_function_block_c(self): + self.component_types = self.get_component_types() + self.prefix = "ha" + return f"{self.get_circuit_c()}\n\n" + + def get_function_blocks_c(self): + self.component_types = self.get_component_types() + return "".join([c.get_function_block_c() for c in self.component_types]) + + def get_invocation_c(self, wire_n: str, offset: int = 0): + self.prefix = "ha" if (offset == 0) else "fa" + return f" {wire_n} = ({self.prefix}({self.a.name}, {self.b.name}) >> 1) & 0x01;" + + def get_adder_sum(self, offset: int = 0): + return f" {self.out.prefix} |= (({self.prefix}({self.a.name}, {self.b.name}) >> 0) & 0x01) << {offset}" + + def get_adder_cout(self, offset: int = 1): + return f" {self.out.prefix} |= (({self.prefix}({self.a.name}, {self.b.name}) >> 1) & 0x01) << {offset}" + + 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" + + 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" + + def get_circuit_c(self): + return f"{self.get_prototype_c()}" + \ + f"{self.out.get_declaration_c()}\n" + \ + f"{self.get_function_sum_c_hier()}" + \ + f"{self.get_function_carry_c_hier()}" + \ + f" return {self.out.prefix}"+";\n}" class full_adder(arithmetic_circuit): @@ -162,11 +249,11 @@ class full_adder(arithmetic_circuit): # FLAT C GENERATION # # Full adder function prototype with three inputs def get_prototype_c(self): - return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name}, {self.c_data_type} {self.c.name})" + "{" + '\n' + return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name}, {self.c_data_type} {self.c.name})" + "{" + "\n" # 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(self): + def get_declaration_c_flat(self): 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)) @@ -181,21 +268,77 @@ class full_adder(arithmetic_circuit): return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) # Full adder wires values initialization - def get_initialization_c(self): + def get_init_c_flat(self): + self.a.prefix = self.a.name if self.a.prefix == "" else self.a.prefix + self.b.prefix = self.b.name if self.b.prefix == "" else self.b.prefix + self.c.prefix = self.c.name return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \ f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \ f" {self.components[2].b.name} = {self.c.get_wire_value_c()};\n" + \ - f" {self.components[0].output.name} = {self.components[0].get_initialization_c()};\n" + \ - f" {self.components[1].output.name} = {self.components[1].get_initialization_c()};\n" + \ - f" {self.components[2].output.name} = {self.components[2].get_initialization_c()};\n" + \ - f" {self.components[3].output.name} = {self.components[3].get_initialization_c()};\n" + \ - f" {self.components[4].output.name} = {self.components[4].get_initialization_c()};\n" + f" {self.components[0].output.name} = {self.components[0].get_init_c_flat()};\n" + \ + f" {self.components[1].output.name} = {self.components[1].get_init_c_flat()};\n" + \ + f" {self.components[2].output.name} = {self.components[2].get_init_c_flat()};\n" + \ + f" {self.components[3].output.name} = {self.components[3].get_init_c_flat()};\n" + \ + f" {self.components[4].output.name} = {self.components[4].get_init_c_flat()};\n" - def get_function_sum_c(self, offset: int = 0): - return f" {self.out.prefix} |= {self.components[2].output.return_wire_value_c(offset = offset)};\n" + def get_function_sum_c_flat(self, offset: int = 0): + return f" {self.out.prefix} |= {self.components[2].output.return_wire_value_c(offset=offset)};\n" - def get_function_carry_c(self, offset: int = 1): - return f" {self.out.prefix} |= {self.components[4].output.return_wire_value_c(offset = offset)};\n" + def get_function_carry_c_flat(self, offset: int = 1): + return f" {self.out.prefix} |= {self.components[4].output.return_wire_value_c(offset=offset)};\n" + + # HIERARCHICAL C GENERATION # + def get_function_block_c(self): + self.component_types = self.get_component_types() + self.prefix = "fa" + self.c.name = "cin" + return f"{self.get_circuit_c()}\n\n" + + def get_function_blocks_c(self): + self.component_types = self.get_component_types() + return "".join([c.get_function_block_c() for c in self.component_types]) + + def get_declaration_c_hier(self): + self.component_types[0].a.name = "xor_1" + self.component_types[2].a.name = "and_1" + self.component_types[2].b.name = "and_2" + 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_invocation_c(self.a, self.b)}\n" + \ + f" {self.component_types[2].a.name} = {self.component_types[1].get_invocation_c(self.a, self.b)}\n" + \ + f" {self.component_types[2].b.name} = {self.component_types[1].get_invocation_c(self.component_types[0].a, self.c)}\n" + + def get_invocation_c(self, wire_n: str, offset: int = 0): + self.prefix = "ha" if (offset == 0) else "fa" + self.c.name = "cout_"+str(offset-1) + return f" {wire_n} = ({self.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> 1) & 0x01;" + + def get_adder_sum(self, offset: int = 0): + self.c.name = "cout_"+str(offset-1) + return f" {self.out.prefix} |= (({self.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> 0) & 0x01) << {offset}" + + def get_adder_cout(self, offset: int = 1): + self.c.name = "cout_"+str(offset-2) + return f" {self.out.prefix} |= (({self.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> 1) & 0x01) << {offset}" + + 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" + + 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.component_types[2].a, b=self.component_types[2].b, offset=offset)};\n" + + def get_circuit_c(self): + self.component_types = self.component_types + 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" + \ + f"{self.get_function_sum_c_hier()}" + \ + f"{self.get_function_carry_c_hier()}" + \ + f" return {self.out.prefix}"+";\n}" class signed_ripple_carry_adder(arithmetic_circuit): @@ -204,8 +347,8 @@ class signed_ripple_carry_adder(arithmetic_circuit): self.N = max(a.N, b.N) self.c_data_type = "int64_t" # Bus sign extension in case buses have different lengths - a.sign_extend(self.N) - b.sign_extend(self.N) + a.bus_extend(N=self.N, prefix=a.prefix) + b.bus_extend(N=self.N, prefix=b.prefix) self.a = a self.b = b if prefix == "s_rca": @@ -240,29 +383,49 @@ class signed_ripple_carry_adder(arithmetic_circuit): # FLAT C GENERATION # # Initialization of 1-bit adders and sign extension XOR gates - def get_initialization_c(self): - return f"".join([c.get_initialization_c() for c in self.components[:-2]]) + \ + def get_init_c_flat(self): + self.components[-2].output.prefix = self.components[-2].output.name + self.components[-3].get_carry_wire().prefix = self.components[-3].get_carry_wire().name + return f"".join([c.get_init_c_flat() for c in self.components[:-2]]) + \ f" {self.components[-2].a.name} = {self.a.get_wire_value_c(offset=self.N-1)};\n" + \ f" {self.components[-2].b.name} = {self.b.get_wire_value_c(offset=self.N-1)};\n" + \ - f" {self.components[-2].output.name} = {self.components[-2].get_initialization_c()};\n" + \ + f" {self.components[-2].output.name} = {self.components[-2].get_init_c_flat()};\n" + \ f" {self.components[-1].a.name} = {self.components[-2].output.get_wire_value_c()};\n" + \ f" {self.components[-1].b.name} = {self.components[-3].get_carry_wire().get_wire_value_c()};\n" + \ - f" {self.components[-1].output.name} = {self.components[-1].get_initialization_c()};\n" + f" {self.components[-1].output.name} = {self.components[-1].get_init_c_flat()};\n" - def get_function_sum_c(self): - return "".join([c.get_function_sum_c(self.components.index(c)) for c in self.components[:-2]]) + def get_function_sum_c_flat(self): + return "".join([c.get_function_sum_c_flat(offset=self.components.index(c)) for c in self.components[:-2]]) - def get_function_carry_c(self): + def get_function_carry_c_flat(self): return f" {self.out.prefix} |= {self.get_previous_component().output.return_wire_value_c(offset = self.N)};\n" + # HIERARCHICAL C GENERATION # + def get_declaration_c_hier(self): + self.cout = bus(N=self.N, prefix="cout") + return "".join(self.a.get_wire_declaration_c()) + \ + "".join(self.b.get_wire_declaration_c()) + \ + "".join(self.cout.get_wire_declaration_c()) + \ + f"{self.components[-2].output.get_declaration_c()}" + + def get_init_cout_c_hier(self): + return "\n".join([c.get_invocation_c(wire_n=self.cout.get_wire(self.components.index(c)).name, offset=self.components.index(c)) for c in self.components[:-2]]) + \ + f"\n {self.components[-2].output.name} = {self.components[-2].get_invocation_c(a=self.a.bus[-1], b=self.b.bus[-1])}" + + def get_function_sum_c_hier(self): + return ";\n".join([c.get_adder_sum(offset=self.components.index(c)) for c in self.components[:-2]])+";\n" + + def get_function_carry_c_hier(self): + return f" {self.out.prefix} |= {self.get_previous_component().get_gate_output_c(a=self.components[-2].output, b=self.cout.bus[-1], offset=self.out.N-1)};\n" + class unsigned_ripple_carry_adder(arithmetic_circuit): def __init__(self, a: bus, b: bus, prefix: str = "u_rca"): super().__init__() self.N = max(a.N, b.N) - # Bus sign extension in case buses have different lengths - a.sign_extend(self.N) - b.sign_extend(self.N) + # Bus sign extension in ase buses have different lengths + a.bus_extend(N=self.N, prefix=a.prefix) + b.bus_extend(N=self.N, prefix=b.prefix) self.a = a self.b = b if prefix == "u_rca": @@ -293,28 +456,14 @@ class unsigned_ripple_carry_adder(arithmetic_circuit): if __name__ == "__main__": a = bus(N=8, prefix="a") b = bus(N=8, prefix="b") - rca = signed_ripple_carry_adder(a, b) - rca.get_c_code(open("s_rca8.c", "w")) + rca = unsigned_ripple_carry_adder(a, b) + + # rca.get_c_code_hier(open("h_u_rca8.c", "w")) w1 = wire(name="a") w2 = wire(name="b") - w3 = wire(name="cin") - fa = full_adder(w1, w2, w3) - fa.get_c_code(open("fa.c", "w")) + w3 = wire(name="cout") + fa = full_adder(w1, w2, w3, prefix="h_fa") + ha = half_adder(w1, w2, prefix="h_ha") - """ - # Generation of 8-bit rca - a = bus(N=8, prefix="a") - b = bus(N=8, prefix="b") - rca = ripple_carry_adder(a, b) - # Export to C code (flat) and save to file - rca.get_c_code(open("rca_8.c", "w")) - - # Generation of OR logic gate - # Values just for testing functionality within Python - a1 = wire(name="a", value=1) - b1 = wire(name="b", value=0) - xor = xor_gate(a1, b1) - # Export to C code (flat) and display to stdout - xor.get_c_code(sys.stdout) - """ + # ha.get_c_code_hier(open("h_ha.c","w")) diff --git a/logic_gates_generator.py b/logic_gates_generator.py index 25f5255..8c5b281 100644 --- a/logic_gates_generator.py +++ b/logic_gates_generator.py @@ -6,28 +6,33 @@ from wire_components import wire class logic_gate(): def __init__(self, a: wire, b: wire, prefix: str = "w"): - self.a = wire(prefix+"_"+a.name.replace(prefix+"_", ''), a.value) - self.b = wire(prefix+"_"+b.name.replace(prefix+"_", ''), b.value) + self.a = wire(name=prefix+"_"+a.name.replace(prefix+"_", ""), value=a.value) + self.b = wire(name=prefix+"_"+b.name.replace(prefix+"_", ""), value=b.value) self.prefix = prefix + def get_component_types(self): + return list([self]) + # FLAT C GENERATION # @staticmethod def get_includes_c(): return f"#include \n#include \n\n" def get_prototype_c(self): - return f"uint8_t {self.gate_type}(uint8_t a, uint8_t b)" + "{" + '\n' + self.a.name = self.a.name.replace(self.prefix+"_", "") + self.b.name = self.b.name.replace(self.prefix+"_", "") + return f"uint8_t {self.gate_type}(uint8_t {self.a.name}, uint8_t {self.b.name})" + "{" + "\n" - def get_declaration_c(self): + def get_declaration_c_flat(self): return f"{self.a.get_declaration_c()}{self.b.get_declaration_c()}{self.output.get_declaration_c()}" - def get_initialization_c(self): + def get_init_c_flat(self): return f"{self.a.name} {self.operator} {self.b.name}" def get_function_c(self): - self.a.name = self.a.name.replace(self.prefix+"_", '') - self.b.name = self.b.name.replace(self.prefix+"_", '') - return f"{self.a.get_wire_value_c()} {self.operator} {self.b.get_wire_value_c(0)}" + self.a.prefix = self.a.name.replace(self.prefix+"_", "") + self.b.prefix = self.b.name.replace(self.prefix+"_", "") + return f"{self.a.get_wire_value_c()} {self.operator} {self.b.get_wire_value_c()}" # Generating flat C code representation of separate logic gate # (i.e. not as a component of bigger circuit) @@ -38,15 +43,25 @@ class logic_gate(): file_object.close() # HIERARCHICAL C GENERATION # - # TODO + def get_function_block_c(self): + self.a.name = "a" + self.b.name = "b" + return f"{self.get_prototype_c()}" + \ + f" return "+(self.get_function_c())+";\n}\n\n" + + def get_invocation_c(self, a: wire, b: wire): + return f"{self.gate_type}({a.name}, {b.name});" + + def get_gate_output_c(self, a: wire, b: wire, offset: int = 0): + return f"({self.gate_type}({a.name}, {b.name}) & 0x01) << {offset}" # Single-input class not_gate(logic_gate): def __init__(self, a: wire, prefix: str = "w", outid: int = 0): - self.gate_type = 'not_gate' - self.operator = '~' - self.a = wire(prefix+"_"+a.name.replace(prefix+"_", ''), a.value) + self.gate_type = "not_gate" + self.operator = "~" + self.a = wire(prefix+"_"+a.name.replace(prefix+"_", ""), a.value) self.prefix = prefix if self.a.value == 1: @@ -54,26 +69,39 @@ class not_gate(logic_gate): else: self.output = wire(name=prefix+"_y"+str(outid), value=1) + # FLAT C GENERATION # def get_prototype_c(self): - return f"uint8_t {self.gate_type}(uint8_t a)" + "{" + '\n' + return f"uint8_t {self.gate_type}(uint8_t a)" + "{" + "\n" def get_declaration_c(self): return f"{self.a.get_declaration_c()}{self.output.get_declaration_c()}" - def get_initialization_c(self): + def get_init_c_flat(self): return f"{self.operator}{self.a.name}" def get_function_c(self): - self.a.name = self.a.name.replace(self.prefix+"_", '') + self.a.prefix = self.a.name.replace(self.prefix+"_", "") return f"{self.operator}{self.a.get_wire_value_c()} & 0x01 << 0" + # HIERARCHICAL C GENERATION # + def get_function_block_c(self): + self.a.name = "a" + return f"{self.get_prototype_c()}" + \ + f" return "+(self.get_function_c())+";\n}\n\n" + + def get_invocation_c(self, a: wire): + return f"{self.gate_type}({a.name});" + + def get_gate_output_c(self, a: wire, offset: int = 0): + return f"({self.gate_type}({a.name}) & 0x01) << {offset}" + # Two-input class and_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'and_gate' - self.operator = '&' + self.gate_type = "and_gate" + self.operator = "&" if a.value == 1 and b.value == 1: self.output = wire(name=prefix+"_y"+str(outid), value=1) @@ -84,8 +112,8 @@ class and_gate(logic_gate): class nand_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'nand_gate' - self.operator = '&' + self.gate_type = "nand_gate" + self.operator = "&" if (self.a.value == 1 and self.b.value == 1): self.output = wire(name=prefix+"_y"+str(outid), value=0) @@ -99,8 +127,8 @@ class nand_gate(logic_gate): class or_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'or_gate' - self.operator = '|' + self.gate_type = "or_gate" + self.operator = "|" if self.a.value == 1 or self.b.value == 1: self.output = wire(name=prefix+"_y"+str(outid), value=1) @@ -111,8 +139,8 @@ class or_gate(logic_gate): class nor_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'nor_gate' - self.operator = '|' + self.gate_type = "nor_gate" + self.operator = "|" if self.a.value == 1 or self.b.value == 1: self.output = wire(name=prefix+"_y"+str(outid), value=0) @@ -126,8 +154,8 @@ class nor_gate(logic_gate): class xor_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'xor_gate' - self.operator = '^' + self.gate_type = "xor_gate" + self.operator = "^" if (a.value == 1 and b.value == 0) or (a.value == 0 and b.value == 1): self.output = wire(name=prefix+"_y"+str(outid), value=1) @@ -138,8 +166,8 @@ class xor_gate(logic_gate): class xnor_gate(logic_gate): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): super().__init__(a, b, prefix) - self.gate_type = 'xnor_gate' - self.operator = '^' + self.gate_type = "xnor_gate" + self.operator = "^" if (self.a.value == 1 and self.b.value == 0) or (self.a.value == 0 and self.b.value == 1): self.output = wire(name=prefix+"_y"+str(outid), value=0) diff --git a/wire_components.py b/wire_components.py index d44d206..1a4a1bc 100644 --- a/wire_components.py +++ b/wire_components.py @@ -2,16 +2,18 @@ class wire(): - def __init__(self, name: str, value: int = 0, index: int = 0): + def __init__(self, name: str = "w", value: int = 0, index: int = 0): self.name = name + self.prefix = name[0:int(name.rfind(str(index))-1)] self.value = value self.index = index + # C GENERATION # def get_declaration_c(self): return f" uint8_t {self.name} = 0;\n" def get_wire_value_c(self, offset: int = 0): - return f"(({self.name} >> {offset}) & 0x01)" + return f"(({self.prefix} >> {offset}) & 0x01)" def return_wire_value_c(self, offset: int = 0): return f"({self.name} & 0x01) << {offset}" @@ -19,7 +21,7 @@ class wire(): class bus(): def __init__(self, prefix: str = "bus", N: int = 1): - self.bus = [wire(name=prefix, index=i) for i in range(N)] + self.bus = [wire(name=prefix+"_"+str(i), index=i) for i in range(N)] self.prefix = prefix self.N = N @@ -31,21 +33,25 @@ class bus(): def connect(self, out_wire_index: int, inner_component_out_wire: wire): self.bus[out_wire_index] = inner_component_out_wire + def get_wire(self, wire_index: int): + return self.bus[wire_index] + + def bus_extend(self, N: int, prefix: str = "bus"): + self.bus = [wire(name=prefix+"_"+str(i), index=i) for i in range(N)] + self.N = N + + # C GENERATION # def get_wire_value_c(self, offset: int = 0): return self.bus[offset].get_wire_value_c(offset=offset) def return_wire_value_c(self, offset: int = 0): self.bus[offset].return_wire_value_c(offset) + def get_wire_declaration_c(self): + return [w.get_declaration_c() for w in self.bus] + 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(self, wire_index: int): - return self.bus[wire_index] - - def sign_extend(self, N: int): - self.bus = [wire(name=self.prefix, index=i) for i in range(N)] - self.N = N