Did some code refactoring concerning one bit circuits generation. Added multiple one/multi bit circuits. TBD: Generate and test different circuits, implement divider circuits, comment code, add verification/optimization of Verilog/BLIF files using yosys tool.

This commit is contained in:
honzastor 2021-03-22 00:22:01 +01:00
parent d86ddcac09
commit 792d0c5db1
4 changed files with 763 additions and 321 deletions

View File

@ -9,6 +9,7 @@ class arithmetic_circuit():
def __init__(self):
self.components = []
self.circuit_wires = []
self.inputs = []
self.circuit_gates = []
self.c_data_type = "uint64_t"
self.N = 1
@ -75,6 +76,9 @@ class arithmetic_circuit():
if not [item for item in self.circuit_wires if item[1] == component.out.name]:
self.circuit_wires.append((component.out, component.out.name, len(self.circuit_wires)))
# Get unique names of all inner input circuits (mainly used in one bit circuits)
self.inputs = [i[0] for i in self.circuit_wires if i[0] not in [o.out for o in self.components]]
# Search for circuit's wire unique index for cgp chromosome generation
def get_circuit_wire_index(self, wire: wire):
for w in self.circuit_wires:
@ -223,10 +227,10 @@ class arithmetic_circuit():
def get_inits_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"
"".join([c.get_assign_v_flat() if isinstance(c, logic_gate) else c.get_init_v_flat() for c in self.components])
def get_init_v_flat(self):
return "".join([c.get_assign_v_flat() if isinstance(c, logic_gate) else c.get_init_v_flat() for c in self.components]) + "\n"
return "".join([c.get_assign_v_flat() if isinstance(c, logic_gate) else c.get_init_v_flat() for c in self.components])
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])
@ -235,7 +239,7 @@ class arithmetic_circuit():
def get_v_code_flat(self, file_object):
file_object.write(self.get_prototype_v())
file_object.write(self.get_declarations_v_flat()+"\n")
file_object.write(self.get_inits_v_flat())
file_object.write(self.get_inits_v_flat() + "\n")
file_object.write(self.get_function_out_v_flat())
file_object.write(f"endmodule")
file_object.close()
@ -417,7 +421,7 @@ class multiplier_circuit(arithmetic_circuit):
if d >= initial_value:
return stage, max_height
def init_column_heights(self):
def init_column_heights(self, signed=False):
columns = [[num] if num <= self.N else [num - (num - self.N)*2] for num in range(1, self.out.N)]
columns = [self.add_column_wires(column=col, column_index=columns.index(col)) for col in columns]
return columns
@ -431,7 +435,22 @@ class multiplier_circuit(arithmetic_circuit):
[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)]
column[1:] = [and_gate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(1, len(column))]
# TODO check and refactor
# Filling unsigned pp matrix with AND gates
if self.__class__.__name__ == "unsigned_dadda_multiplier" or self.__class__.__name__ == "unsigned_wallace_multiplier":
column[1:] = [and_gate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(1, len(column))]
# Filling signed pp matrix with 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:] = [and_gate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(1, len(column))]
# Second half of partial product columns contains NAND/AND gates
else:
column[1] = nand_gate(a=column[1][0], b=column[1][1], prefix=self.prefix+'_nand_'+str(column[1][0].index)+'_'+str(column[1][1].index))
column[-1] = nand_gate(a=column[-1][0], b=column[-1][1], prefix=self.prefix+'_nand_'+str(column[-1][0].index)+'_'+str(column[-1][1].index))
if len(column[2:-1]) != 0:
column[2:-1] = [and_gate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(2, len(column)-1)]
return column
def get_column_height(self, column_num: int):
@ -443,7 +462,7 @@ class multiplier_circuit(arithmetic_circuit):
self.columns[next_column][0] = self.get_column_height(next_column)+next_height_change
def get_column_wire(self, column: int, bit: int):
if isinstance(self.columns[column][bit], and_gate):
if isinstance(self.columns[column][bit], and_gate) or isinstance(self.columns[column][bit], nand_gate):
self.add_component(self.columns[column][bit])
return self.get_previous_component(1).out
else:
@ -460,6 +479,5 @@ class multiplier_circuit(arithmetic_circuit):
self.columns[curr_column].pop(1)
self.columns[curr_column].insert(self.get_column_height(curr_column), adder.get_sum_wire())
# Add carry out from previous column's component to top of column wires
if next_column-1 == curr_column:
self.columns[next_column].insert(1, adder.get_carry_wire())

View File

@ -1,7 +1,7 @@
from wire_components import wire, bus
from logic_gates import logic_gate, and_gate, nand_gate, or_gate, nor_gate, xor_gate, xnor_gate, not_gate
from one_bit_circuits import half_adder, full_adder
from multi_bit_circuits import unsigned_ripple_carry_adder, signed_ripple_carry_adder, unsigned_array_multiplier, signed_array_multiplier, unsigned_dadda_multiplier, unsigned_carry_lookahead_adder, signed_carry_lookahead_adder
from one_bit_circuits import constant_wire_value_1, constant_wire_value_0, half_adder, full_adder
from multi_bit_circuits import unsigned_ripple_carry_adder, signed_ripple_carry_adder, unsigned_pg_ripple_carry_adder, signed_pg_ripple_carry_adder, unsigned_array_multiplier, signed_array_multiplier, unsigned_dadda_multiplier, signed_dadda_multiplier, unsigned_wallace_multiplier, signed_wallace_multiplier, unsigned_carry_lookahead_adder, signed_carry_lookahead_adder
import sys
@ -9,14 +9,21 @@ import sys
if __name__ == "__main__":
a = bus(N=8, prefix="a")
b = bus(N=1, prefix="b")
rca = signed_ripple_carry_adder(a, b)
pg_rca = signed_pg_ripple_carry_adder(a, b)
pg_rca.get_c_code_flat(open("cla_test_flat.c", "w"))
pg_rca.get_c_code_hier(open("cla_test_hier.c", "w"))
pg_rca.get_cgp_code(open("cla_test.chr", "w"))
#cla = unsigned_carry_lookahead_adder(a, b)
#rca = signed_ripple_carry_adder(a, b)
#rca.get_c_code_flat(open("rca_test.c", "w"))
#rca.get_v_code_flat(open("rca_test.v", "w"))
#rca.get_blif_code_flat(open("rca_test.blif", "w"))
#rca.get_blif_code_hier(open("h_rca2_test.blif", "w"))
#rca.get_cgp_code(open("rca_test.chr", "w"))
arrmul = signed_array_multiplier(a, b)
#arrmul = signed_array_multiplier(a, b)
#arrmul.get_c_code_flat(open("arrmul_test.c", "w"))
#arrmul.get_cgp_code(open("arrmul_test.chr", "w"))
#arrmul.get_v_code_flat(open("arrmul_test.v", "w"))
@ -27,14 +34,28 @@ if __name__ == "__main__":
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 = half_adder(w1, w2, prefix="ha")
fa = full_adder(w1, w2, w3, prefix="fa")
fa.get_v_code_flat(open("f_fa.v", "w"))
fa.get_v_code_hier(open("h_fa.v", "w"))
fa.get_c_code_flat(open("f_fa.c", "w"))
fa.get_c_code_hier(open("h_fa.c", "w"))
fa.get_blif_code_flat(open("f_fa.blif", "w"))
fa.get_blif_code_hier(open("h_fa.blif", "w"))
fa.get_cgp_code(open("fa.chr", "w"))
#fa.get_v_code_hier(open("h_fa.v", "w"))
#fa.get_blif_code_hier(open("h_fa2.blif", "w"))
ha.get_cgp_code(open(f"ha.chr", "w"))
fa.get_cgp_code(open(f"fa.chr", "w"))
#ha.get_cgp_code(open(f"ha.chr", "w"))
#fa.get_cgp_code(open(f"fa.chr", "w"))
fa.get_c_code_flat(open("f_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_blif_code_hier(open("h_ha.blif","w"))
@ -63,8 +84,36 @@ if __name__ == "__main__":
#gate.get_cgp_code(open("and_gate.chr","w"))
"""
dadda = unsigned_dadda_multiplier(a, b, prefix="h_u_dadda_mul2")
#dadda = unsigned_dadda_multiplier(a, b, prefix="h_u_dadda_mul2")
#dadda.get_v_code_hier(open("h_u_dadda_mul2.v", "w"))
#dadda.get_c_code_hier(open("h_u_dadda_mul2.c", "w"))
#dadda.get_blif_code_hier(open("h_u_dadda_mul2.blif", "w"))
#dadda.get_cgp_code(open("u_dadda_mul2.chr", "w"))
s_dadda = signed_dadda_multiplier(a, b, prefix="dadda_s_mul8")
s_dadda.get_v_code_hier(open("dadda_s_mul8.v", "w"))
s_dadda.get_c_code_hier(open("dadda_s_mul82.c", "w"))
s_dadda.get_c_code_flat(open("f_dadda_s_mul82.c", "w"))
s_dadda.get_blif_code_hier(open("dadda_s_mul8.blif", "w"))
s_dadda.get_cgp_code(open("dadda_s_mul8.chr", "w"))
#dadda = unsigned_dadda_multiplier(a, b, prefix="h_f_dadda_mul3")
#dadda.get_c_code_hier(open("test_dadda_mul8.c", "w"))
test = signed_carry_lookahead_adder(a, b, prefix="test")
test.get_c_code_hier(open("htest.c", "w"))
test.get_c_code_flat(open("ftest.c", "w"))
test.get_v_code_flat(open("ftest.v", "w"))
test.get_v_code_hier(open("htest.v", "w"))
test.get_blif_code_flat(open("ftest.blif", "w"))
test.get_blif_code_hier(open("htest.blif", "w"))
test.get_cgp_code(open("test.chr", "w"))

View File

@ -1,6 +1,7 @@
from itertools import combinations_with_replacement
from typing import ClassVar
from arithmetic_circuits import arithmetic_circuit, multiplier_circuit
from one_bit_circuits import half_adder, full_adder
from one_bit_circuits import half_adder, full_adder, constant_wire_value_0, constant_wire_value_1, full_adder_pg, pg_logic_block
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
@ -12,6 +13,7 @@ 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)
self.prefix = prefix
self.a = bus(prefix=a.prefix, wires_list=a.bus)
self.b = bus(prefix=b.prefix, wires_list=b.bus)
@ -19,19 +21,12 @@ class unsigned_ripple_carry_adder(arithmetic_circuit):
self.a.bus_extend(N=self.N, prefix=a.prefix)
self.b.bus_extend(N=self.N, prefix=b.prefix)
if prefix == "u_rca" or prefix == "s_rca":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Output wires for N sum bits and additional cout bit
self.out = bus("out", self.N+1)
# TODO replace ha for fa???
# Gradual addition of 1-bit adder components
for input_index in range(self.N):
# First one is a half adder
# First adder is a half adder
if input_index == 0:
obj_ha = half_adder(self.a.get_wire(input_index), self.b.get_wire(input_index), prefix=self.prefix+"_ha")
self.add_component(obj_ha)
@ -39,7 +34,7 @@ class unsigned_ripple_carry_adder(arithmetic_circuit):
if input_index == (self.N-1):
self.out.connect(self.N, obj_ha.get_carry_wire())
# Rest are full adders
# Rest adders are full adders
else:
obj_fa = full_adder(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa)
@ -47,7 +42,7 @@ class unsigned_ripple_carry_adder(arithmetic_circuit):
if input_index == (self.N-1):
self.out.connect(self.N, obj_fa.get_carry_wire())
class signed_ripple_carry_adder(unsigned_ripple_carry_adder, arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "s_rca"):
@ -62,11 +57,11 @@ class signed_ripple_carry_adder(unsigned_ripple_carry_adder, arithmetic_circuit)
self.out.connect(self.N, sign_xor_2.out)
# TODO CHANGE!!! test, think about proper P/G gates generation
class unsigned_carry_lookahead_adder(arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "u_cla"):
class unsigned_pg_ripple_carry_adder(arithmetic_circuit):
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)
@ -74,53 +69,146 @@ class unsigned_carry_lookahead_adder(arithmetic_circuit):
self.a.bus_extend(N=self.N, prefix=a.prefix)
self.b.bus_extend(N=self.N, prefix=b.prefix)
if prefix == "u_cla" or prefix == "s_cla":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Output wires for N sum bits and additional cout bit
self.out = bus("out", self.N+1)
# Gradual addition of 1-bit adder components
for input_index in range(self.N):
if input_index == 0:
# Constant wire with value 0 for cin 0
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
obj_fa_cla = full_adder_pg(self.a.get_wire(input_index), self.b.get_wire(input_index), constant_wire_0.out.get_wire(), prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa_cla)
self.out.connect(input_index, obj_fa_cla.get_sum_wire())
else:
obj_fa_cla = full_adder_pg(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().out, prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa_cla)
self.out.connect(input_index, obj_fa_cla.get_sum_wire())
obj_and = and_gate(self.get_previous_component().c, self.get_previous_component().get_propagate_wire(), prefix=self.prefix+"_and"+str(input_index))
obj_or = or_gate(obj_and.out, self.get_previous_component().get_generate_wire(), prefix=self.prefix+"_or"+str(input_index))
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)
class signed_pg_ripple_carry_adder(unsigned_pg_ripple_carry_adder, arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "s_pg_rca"):
super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t"
# Additional XOR gates to ensure correct sign extension in case of sign addition
sign_xor_1 = xor_gate(self.a.get_wire(self.N-1), self.b.get_wire(self.N-1), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(sign_xor_1)
sign_xor_2 = xor_gate(sign_xor_1.out, self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(sign_xor_2)
self.out.connect(self.N, sign_xor_2.out)
class unsigned_carry_lookahead_adder(arithmetic_circuit):
def __init__(self, a: bus, b: bus, 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)
# Lists containing all propagate/generate wires
self.propagate = []
self.generate = []
# Output wires for N sum bits and additional cout bit
self.out = bus("out", self.N+1)
# Generating wire with constant logic value 0 (output of the nor gate), used as cin to first fa
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_nor = nor_gate(obj_xor.out, obj_xnor.out, prefix=self.prefix+"_nor_constant_wire")
obj_nor.out.name = "constant_wire"
obj_nor.out.prefix = "constant_wire"
self.add_component(obj_xor)
self.add_component(obj_xnor)
self.add_component(obj_nor)
# Gradual addition of 1-bit adder components
# Constant wire with value 0 for cin 0
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
# Used as a first generate wire for obtaining next carry bits
self.generate.append(constant_wire_0.out.get_wire())
# Gradual addition of propagate/generate logic blocks and AND/OR gates for Cout bits generation, XOR gates for Sum bits generation
for input_index in range(self.N):
obj_fa = full_adder(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().out, prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa)
self.out.connect(input_index, obj_fa.get_sum_wire())
pg_block = pg_logic_block(self.a.get_wire(input_index), self.b.get_wire(input_index), prefix=self.prefix+"_pg_logic"+str(input_index))
self.propagate.append(pg_block.get_propagate_wire())
self.generate.append(pg_block.get_generate_wire())
self.add_component(pg_block)
if input_index == (self.N-1):
self.out.connect(self.N, obj_fa.get_carry_wire())
else:
obj_and = and_gate(self.get_previous_component().get_carry_wire(), self.get_previous_component().propagate.out, prefix=self.prefix+"_and"+str(input_index))
obj_xor = xor_gate(obj_and.out, self.get_previous_component().generate.out, prefix=self.prefix+"_xor"+str(input_index))
if input_index == 0:
obj_sum_xor = xor_gate(pg_block.get_sum_wire(), constant_wire_0.out.get_wire(), prefix=self.prefix+"_xor"+str(input_index))
self.add_component(obj_sum_xor)
self.out.connect(input_index, obj_sum_xor.out)
self.add_component(self.get_previous_component().propagate)
self.add_component(self.get_previous_component(2).generate)
# Carry propagation calculation
obj_and = and_gate(self.propagate[input_index], self.generate[input_index], prefix=self.prefix+"_and"+str(self.get_instance_num(cls=and_gate)))
self.add_component(obj_and)
self.add_component(obj_xor)
# Carry bit generation
obj_cout_or = or_gate(pg_block.get_generate_wire(), self.get_previous_component().out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=or_gate)))
self.add_component(obj_cout_or)
else:
obj_sum_xor = xor_gate(pg_block.get_sum_wire(), self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(input_index))
self.add_component(obj_sum_xor)
self.out.connect(input_index, obj_sum_xor.out)
# For each pg pair values algorithmically combine two input AND gates to replace multiple input gates (resolves fan-in issue)
composite_and_gates = []
# And combine AND gate pairs into OR gates
composite_or_gates = []
# Carry propagation calculation
for g_index in range(len(self.generate)-1):
for p_index in range(g_index, len(self.propagate)):
# No gate to cascade with, add to list
if len(composite_and_gates) == 0:
obj_and = and_gate(self.propagate[p_index], self.generate[g_index], prefix=self.prefix+"_and"+str(self.get_instance_num(cls=and_gate)))
# Combine 2 gates into another one to cascade them
else:
# Create new AND gate
obj_and = and_gate(self.propagate[p_index], self.generate[g_index], prefix=self.prefix+"_and"+str(self.get_instance_num(cls=and_gate)))
self.add_component(obj_and)
# Combine new gate with previous one stored in list
obj_and = and_gate(self.get_previous_component(1).out, self.get_previous_component(2).out, prefix=self.prefix+"_and"+str(self.get_instance_num(cls=and_gate)))
composite_and_gates.pop(composite_and_gates.index(self.get_previous_component(2)))
# Add gate to circuit components and to list of composite AND gates for this pg pair value
self.add_component(obj_and)
composite_and_gates.append(obj_and)
composite_or_gates.append(composite_and_gates.pop())
# Final OR gates cascade using generated AND gates representing multiple input AND gates (cascade of multiple two input ones)
for a in range(len(composite_or_gates)-1):
obj_or = or_gate(self.get_previous_component().out, composite_or_gates[a].out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=or_gate)))
self.add_component(obj_or)
# Carry bit generation
obj_cout_or = or_gate(pg_block.get_generate_wire(), self.get_previous_component().out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=or_gate)))
self.add_component(obj_cout_or)
# Connecting last output bit to last cout
if input_index == (self.N-1):
self.out.connect(self.N, obj_cout_or.out)
# TODO CHANGE!!!
class signed_carry_lookahead_adder(unsigned_carry_lookahead_adder, arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "s_cla"):
super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t"
# Additional XOR gates to ensure correct sign extension in case of sign addition
sign_xor_1 = xor_gate(self.get_previous_component(1).a, self.get_previous_component(1).b, prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
sign_xor_1 = xor_gate(self.a.get_wire(self.N-1), self.b.get_wire(self.N-1), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(sign_xor_1)
sign_xor_2 = xor_gate(sign_xor_1.out, self.get_previous_component(2).get_carry_wire(), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
sign_xor_2 = xor_gate(sign_xor_1.out, self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(sign_xor_2)
self.out.connect(self.N, sign_xor_2.out)
@ -130,6 +218,7 @@ 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)
self.prefix = prefix
self.a = bus(prefix=a.prefix, wires_list=a.bus)
self.b = bus(prefix=b.prefix, wires_list=b.bus)
@ -137,11 +226,6 @@ class unsigned_array_multiplier(multiplier_circuit):
self.a.bus_extend(N=self.N, prefix=a.prefix)
self.b.bus_extend(N=self.N, prefix=b.prefix)
if prefix == "u_arr_mul":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Output wires for multiplication product
self.out = bus("out", self.N*2)
@ -177,16 +261,10 @@ class unsigned_array_multiplier(multiplier_circuit):
# 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)
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
self.out.connect(a_multiplicand_index+1, obj_and.out)
self.out.connect(a_multiplicand_index+1, constant_wire_0.out.get_wire())
elif b_multiplier_index == self.N-1:
self.out.connect(b_multiplier_index + a_multiplicand_index, obj_adder.get_sum_wire())
@ -200,6 +278,7 @@ class signed_array_multiplier(multiplier_circuit):
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)
@ -207,28 +286,16 @@ class signed_array_multiplier(multiplier_circuit):
self.a.bus_extend(N=self.N, prefix=a.prefix)
self.b.bus_extend(N=self.N, prefix=b.prefix)
if prefix == "s_arr_mul":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Output wires for multiplication product
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)
# Generating wire with constant logic value 1
constant_wire_1 = constant_wire_value_1(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_1)
# 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
# we add offset equal to first block in circuits components list (used for generation of wire with constant value 1)
components_offset = 1
# Gradual generation of partial products
for b_multiplier_index in range(self.N):
@ -253,7 +320,7 @@ class signed_array_multiplier(multiplier_circuit):
# FA generation
else:
if a_multiplicand_index == self.N-1 and b_multiplier_index == 1:
previous_product = obj_or.out
previous_product = constant_wire_1.out.get_wire()
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)
@ -264,7 +331,7 @@ class signed_array_multiplier(multiplier_circuit):
# 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")
obj_nor = nor_gate(constant_wire_1.out.get_wire(), 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)
@ -273,16 +340,17 @@ class signed_array_multiplier(multiplier_circuit):
self.out.connect(b_multiplier_index + a_multiplicand_index, obj_adder.get_sum_wire())
if a_multiplicand_index == self.N-1:
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))
obj_xor = xor_gate(self.get_previous_component().get_carry_wire(), constant_wire_1.out.get_wire(), 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_xor.out)
class unsigned_dadda_multiplier(multiplier_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "u_dadda_mul"):
class unsigned_wallace_multiplier(multiplier_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "u_wallace_rca", unsigned_adder_class_name: str = unsigned_ripple_carry_adder):
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)
@ -290,16 +358,191 @@ class unsigned_dadda_multiplier(multiplier_circuit):
self.a.bus_extend(N=self.N, prefix=a.prefix)
self.b.bus_extend(N=self.N, prefix=b.prefix)
if prefix == "u_dadda_mul" or prefix == "s_dadda_mul":
self.prefix = prefix+str(self.N)
# Output wires for multiplication product
self.out = bus("out", self.N*2)
# Initialize all columns partial products forming AND gates matrix
self.columns = self.init_column_heights()
# Perform reduction until all columns have 2 or less bits in them
while not all(height <= 2 for (height, *_) in self.columns):
col = 0
while col < len(self.columns):
# If column has exactly 3 bits in height and all previous columns has maximum of 2 bits in height, combine them in a half adder
if self.get_column_height(col) == 3 and all(height <= 2 for (height, *_) in self.columns[0:col-1]):
# Add half adder and also AND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = half_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-1, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add ha's generated sum to the bottom of current column
# add ha's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
# If column has more than 3 bits in height, combine them in a full adder
elif self.get_column_height(col) > 3:
# Add full adder and also AND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = full_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), self.get_column_wire(column=col, bit=3), prefix=self.prefix+"_fa"+str(self.get_instance_num(cls=full_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-2, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add fa's generated sum to the bottom of current column
# add fa's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
col += 1
# Output generation
# First output bit from single first pp AND gate
self.out.connect(0, self.get_column_wire(column=0, bit=1))
# Final addition of remaining bits
# 1 bit multiplier case
if self.N == 1:
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
self.out.connect(1, constant_wire_0.out.get_wire())
# 2 bit multiplier case
elif self.N == 2:
obj_ha = half_adder(self.get_column_wire(column=1, bit=1), self.get_column_wire(column=1, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
obj_ha = half_adder(self.get_previous_component().get_carry_wire(), self.get_column_wire(column=2, bit=1), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(2, obj_ha.get_sum_wire())
self.out.connect(3, obj_ha.get_carry_wire())
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
self.prefix = prefix
adder_type = unsigned_adder_class_name(a=a, b=b)
adder_a = bus(prefix=f"{adder_type.prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = bus(prefix=f"{adder_type.prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
final_adder = unsigned_adder_class_name(a=adder_a, b=adder_b, prefix=self.prefix+f"_{adder_type.prefix}")
self.add_component(final_adder)
[self.out.connect(o, final_adder.out.get_wire(o-1)) for o in range(1, len(self.out.bus))]
class signed_wallace_multiplier(multiplier_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "s_wallace_rca", unsigned_adder_class_name: str = unsigned_ripple_carry_adder):
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("out", self.N*2)
# Initialize all columns partial products forming AND/NAND gates matrix based on Baugh-Wooley multiplication
self.columns = self.init_column_heights()
# Generating wire with constant logic value 1 for signed multiplication
# Based on Baugh-Wooley multiplication algorithm
# Not used for 1 bit multiplier
if self.N != 1:
constant_wire_1 = constant_wire_value_1(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_1)
# Adding constant wire with value 1 to achieve signedness
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
self.columns[self.N].insert(1, constant_wire_1.out.get_wire())
self.update_column_heights(curr_column=self.N, curr_height_change=1)
# Perform reduction until all columns have 2 or less bits in them
while not all(height <= 2 for (height, *_) in self.columns):
col = 0
while col < len(self.columns):
# If column has exactly 3 bits in height and all previous columns has maximum of 2 bits in height, combine them in a half adder
if self.get_column_height(col) == 3 and all(height <= 2 for (height, *_) in self.columns[0:col-1]):
# Add half adder and also AND/NAND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = half_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-1, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add ha's generated sum to the bottom of current column
# add ha's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
# If column has more than 3 bits in height, combine them in a full adder
elif self.get_column_height(col) > 3:
# Add full adder and also AND/NAND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = full_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), self.get_column_wire(column=col, bit=3), prefix=self.prefix+"_fa"+str(self.get_instance_num(cls=full_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-2, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add fa's generated sum to the bottom of current column
# add fa's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
col += 1
# Output generation
# First output bit from single first pp AND gate
self.out.connect(0, self.get_column_wire(column=0, bit=1))
# Final addition of remaining bits
# 1 bit multiplier case
if self.N == 1:
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
self.out.connect(1, constant_wire_0.out.get_wire())
return
# 2 bit multiplier case
elif self.N == 2:
obj_ha = half_adder(self.get_column_wire(column=1, bit=1), self.get_column_wire(column=1, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
obj_ha = half_adder(self.get_previous_component().get_carry_wire(), self.get_column_wire(column=2, bit=1), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(2, obj_ha.get_sum_wire())
self.out.connect(3, obj_ha.get_carry_wire())
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
adder_type = unsigned_adder_class_name(a=a, b=b)
adder_a = bus(prefix=f"{adder_type.prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = bus(prefix=f"{adder_type.prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
final_adder = unsigned_adder_class_name(a=adder_a, b=adder_b, prefix=self.prefix+f"_{adder_type.prefix}")
self.add_component(final_adder)
[self.out.connect(o, final_adder.out.get_wire(o-1)) for o in range(1, len(self.out.bus))]
# Final XOR to ensure proper sign extension
obj_xor = xor_gate(constant_wire_1.out.get_wire(), self.out.get_wire(self.out.N-1), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(obj_xor)
self.out.connect(self.out.N-1, obj_xor.out)
class unsigned_dadda_multiplier(multiplier_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "u_dadda_rca", unsigned_adder_class_name: str = unsigned_ripple_carry_adder):
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("out", self.N*2)
# Get starting stage and maximum possible column height
self.stage, self.d = self.get_maximum_height(initial_value=min(self.a.N, self.b.N))
# Initialize all columns partial products forming AND gates matrix
self.columns = self.init_column_heights()
# Perform reduction until stage 0
@ -307,7 +550,7 @@ class unsigned_dadda_multiplier(multiplier_circuit):
col = 0
while col < len(self.columns):
if self.get_column_height(col) == self.d + 1:
# Add half adder and also and gates if neccesarry (via get_column_wire invocation) into list of circuits components
# Add half adder and also AND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = half_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_adder)
@ -320,7 +563,7 @@ class unsigned_dadda_multiplier(multiplier_circuit):
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
elif self.get_column_height(col) > self.d:
# Add full adder and also and gates if neccesarry (via get_column_wire invocation) into list of circuits components
# Add full adder and also AND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = full_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), self.get_column_wire(column=col, bit=3), prefix=self.prefix+"_fa"+str(self.get_instance_num(cls=full_adder)))
self.add_component(obj_adder)
@ -339,22 +582,16 @@ class unsigned_dadda_multiplier(multiplier_circuit):
_, self.d = self.get_maximum_height(stage)
# Output generation
# Final addition of remaining bits using RCA # TODO add CLA
# First output bit from single first pp AND gate
self.out.connect(0, self.get_column_wire(column=0, bit=1))
# Final addition of remaining bits
# 1 bit multiplier case
if 1 == self.N:
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(1, obj_and.out)
if self.N == 1:
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
self.out.connect(1, constant_wire_0.out.get_wire())
# 2 bit multiplier case
elif 2 == self.N:
elif self.N == 2:
obj_ha = half_adder(self.get_column_wire(column=1, bit=1), self.get_column_wire(column=1, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
@ -363,13 +600,114 @@ class unsigned_dadda_multiplier(multiplier_circuit):
self.add_component(obj_ha)
self.out.connect(2, obj_ha.get_sum_wire())
self.out.connect(3, obj_ha.get_carry_wire())
# Final addition of remaining bits using RCA # TODO add CLA
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
rca_a = bus(prefix="rca_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
rca_b = bus(prefix="rca_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
rca = unsigned_ripple_carry_adder(a=rca_a, b=rca_b, prefix=self.prefix+"_u_rca"+str(len(self.columns)-1))
self.add_component(rca)
adder_type = unsigned_adder_class_name(a=a, b=b)
adder_a = bus(prefix=f"{adder_type.prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = bus(prefix=f"{adder_type.prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
final_adder = unsigned_adder_class_name(a=adder_a, b=adder_b, prefix=self.prefix+f"_{adder_type.prefix}")
self.add_component(final_adder)
[self.out.connect(o, rca.out.get_wire(o-1)) for o in range(1, len(self.out.bus))]
[self.out.connect(o, final_adder.out.get_wire(o-1)) for o in range(1, len(self.out.bus))]
# TODO signed dadda_multiplier
class signed_dadda_multiplier(multiplier_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "s_dadda_rca", unsigned_adder_class_name: str = unsigned_ripple_carry_adder):
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("out", self.N*2)
# Get starting stage and maximum possible column height
self.stage, self.d = self.get_maximum_height(initial_value=min(self.a.N, self.b.N))
# Initialize all columns partial products forming AND/NAND gates matrix based on Baugh-Wooley multiplication
self.columns = self.init_column_heights()
# Generating wire with constant logic value 1 for signed multiplication
# Based on Baugh-Wooley multiplication algorithm
# Not used for 1 bit multiplier
if self.N != 1:
constant_wire_1 = constant_wire_value_1(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_1)
# Adding constant wire with value 1 to achieve signedness
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
self.columns[self.N].insert(1, constant_wire_1.out.get_wire())
self.update_column_heights(curr_column=self.N, curr_height_change=1)
# Perform reduction until stage 0
for stage in range(self.stage, 0, -1):
col = 0
while col < len(self.columns):
if self.get_column_height(col) == self.d + 1:
# Add half adder and also AND/NAND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = half_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-1, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add ha's generated sum to the bottom of current column
# add ha's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
elif self.get_column_height(col) > self.d:
# Add full adder and also AND/NAND gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = full_adder(self.get_column_wire(column=col, bit=1), self.get_column_wire(column=col, bit=2), self.get_column_wire(column=col, bit=3), prefix=self.prefix+"_fa"+str(self.get_instance_num(cls=full_adder)))
self.add_component(obj_adder)
# Update the number of current and next column wires
self.update_column_heights(curr_column=col, curr_height_change=-2, next_column=col+1, next_height_change=1)
# Update current and next column wires arrangement
# add fa's generated sum to the bottom of current column
# add fa's generated cout to the top of next column
self.update_column_wires(curr_column=col, next_column=col+1, adder=self.get_previous_component(1))
# Next iteration with same column in case there is need for further reduction
col -= 1
col += 1
# Update maximum possible column height
_, self.d = self.get_maximum_height(stage)
# Output generation
# First output bit from single first pp AND gate
self.out.connect(0, self.get_column_wire(column=0, bit=1))
# Final addition of remaining bits
# 1 bit multiplier case (no sign extension)
if self.N == 1:
constant_wire_0 = constant_wire_value_0(self.a.get_wire(), self.b.get_wire())
self.add_component(constant_wire_0)
self.out.connect(1, constant_wire_0.out.get_wire())
return
# 2 bit multiplier case
elif self.N == 2:
obj_ha = half_adder(self.get_column_wire(column=1, bit=1), self.get_column_wire(column=1, bit=2), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
obj_ha = half_adder(self.get_previous_component().get_carry_wire(), self.get_column_wire(column=2, bit=1), prefix=self.prefix+"_ha"+str(self.get_instance_num(cls=half_adder)))
self.add_component(obj_ha)
self.out.connect(2, obj_ha.get_sum_wire())
self.out.connect(3, obj_ha.get_carry_wire())
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
adder_type = unsigned_adder_class_name(a=a, b=b)
adder_a = bus(prefix=f"{adder_type.prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = bus(prefix=f"{adder_type.prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
final_adder = unsigned_adder_class_name(a=adder_a, b=adder_b, prefix=self.prefix+f"_{adder_type.prefix}")
self.add_component(final_adder)
[self.out.connect(o, final_adder.out.get_wire(o-1)) for o in range(1, len(self.out.bus))]
# Final XOR to ensure proper sign extension
obj_xor = xor_gate(constant_wire_1.out.get_wire(), self.out.get_wire(self.out.N-1), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=xor_gate)))
self.add_component(obj_xor)
self.out.connect(self.out.N-1, obj_xor.out)

View File

@ -5,7 +5,7 @@ from wire_components import wire, bus
""" ONE BIT CIRCUITS """
class one_bit_circuit(arithmetic_circuit):
class two_input_one_bit_circuit(arithmetic_circuit):
def __init__(self):
super().__init__()
@ -18,10 +18,9 @@ class one_bit_circuit(arithmetic_circuit):
# Unique declaration of all circuit's interconnections
return "".join([c[0].get_declaration_c() for c in self.circuit_wires])
# Half adder (2 inputs adder) wires values initialization
# Wires values initialization and assignment
def get_init_c_flat(self):
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))}" + \
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_",""))) for i in self.inputs]) + \
"".join([f" {c.out.name} = {c.get_init_c_flat()};\n" for c in self.components])
# Generating flat C code representation of circuit
@ -36,116 +35,111 @@ class one_bit_circuit(arithmetic_circuit):
file_object.close()
# HIERARCHICAL C #
# Subcomponent generation
def get_function_block_c(self):
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"))
adder_block = self.__class__()
return f"{adder_block.get_circuit_c()}\n\n"
def get_wire_declaration_c_hier(self):
return f"{self.out.get_wire_declaration_c()}"
def get_out_invocation_c(self, **kwargs):
return self.get_sum_invocation_c()+"\n" + \
self.get_cout_invocation_c()+"\n"
circuit_class = self.__class__()
return "".join([f' {o.name} = ({circuit_class.prefix}({self.a.name}, {self.b.name}) >> {self.out.bus.index(o)}) & 0x01;\n' for o in self.out.bus])
def get_sum_invocation_c(self):
return f" {self.get_sum_wire().name} = (ha({self.a.name}, {self.b.name}) >> 0) & 0x01;"
# Self circuit hierarchical generation
def get_declaration_c_hier(self):
self.get_circuit_wires()
# Unique declaration of all circuit's interconnections
return "".join([c[0].get_declaration_c() for c in self.circuit_wires])
def get_cout_invocation_c(self):
return f" {self.get_carry_wire().name} = (ha({self.a.name}, {self.b.name}) >> 1) & 0x01;"
def get_init_c_hier(self):
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_",""))) for i in self.inputs]) + \
"".join([f" {c.out.name} = {c.get_gate_invocation_c(remove_prefix=False)}" for c in self.components])
def get_function_sum_c_hier(self, offset: int = 0):
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.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()}" + \
f"{self.out.get_declaration_c()}" + \
f"{self.get_function_sum_c_hier()}" + \
f"{self.get_function_carry_c_hier()}" + \
f" return {self.out.prefix}"+";\n}"
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])
""" VERILOG CODE GENERATION """
# FLAT VERILOG #
def get_prototype_v(self):
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"
return f"module {self.prefix}(input {self.a.name}, input {self.b.name}{''.join([f', output {o.name}' for o in self.out.bus])});\n"
def get_declaration_v_flat(self):
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 (2 inputs adder) wires values initialization
# Wires values initialization and assignment
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"
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_","")) for i in self.inputs]) + \
"".join([f" assign {c.out.name} = {c.get_init_v_flat()};\n" for c in self.components])
# Not used in 1 bit circuits (no effect when calling while generating)
def get_function_out_v_flat(self):
return ""
# Generating flat Verilog code representation of 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())
file_object.write(f"endmodule")
file_object.close()
# HIERARCHICAL VERILOG #
# Subcomponent generation
def get_function_block_v(self):
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"))
adder_block = self.__class__()
return f"{adder_block.get_circuit_v()}\n\n"
def get_wire_declaration_v_hier(self):
return f"{self.out.get_wire_declaration_v()}"
def get_invocation_v(self, **kwargs):
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"
circuit_class = self.__class__()
return f" {circuit_class.prefix} {circuit_class.prefix}_{self.out.get_wire().name}({self.a.name}, {self.b.name}{''.join([f', {o.name}' for o in self.out.bus])});\n"
def get_function_sum_v_hier(self):
return f"{self.components[0].get_gate_invocation_v()}"
# Self circuit hierarchical generation
def get_declaration_v_hier(self):
self.get_circuit_wires()
# Unique declaration of all circuit's interconnections
return "".join([c.get_declaration_v() for c in self.inputs])
def get_function_carry_v_hier(self):
return f"{self.components[1].get_gate_invocation_v()}"
def get_init_v_hier(self):
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_","")) for i in self.inputs])
def get_circuit_v(self):
return f"{self.get_prototype_v()}" + \
f"{self.get_function_sum_v_hier()}" + \
f"{self.get_function_carry_v_hier()}" + \
f"endmodule"
def get_function_out_v_hier(self):
return "".join([f"{c.get_gate_invocation_v(remove_prefix=False)}" for c in self.components])
""" BLIF CODE GENERATION """
# FLAT BLIF #
def get_declaration_blif(self):
return f".inputs {self.a.name} {self.b.name}" + \
f"\n.outputs" + \
"".join([f" {w.name}" for w in self.out.bus])+"\n"
return f".inputs {self.a.name} {self.b.name}\n" + \
f".outputs{self.out.get_wire_declaration_blif()}\n"
def get_wire_mapping_blif(self):
# For unique mapping of all circuit's input interconnections
self.get_circuit_wires()
return "".join([c[0].get_assign_blif(name=c[0].name.replace(self.prefix+'_', '')) for c in self.circuit_wires[:self.out.N]])
return "".join([i.get_assign_blif(name=i.name.replace(self.prefix+"_","")) for i in self.inputs])
def get_function_blif_flat(self):
return f"{self.get_wire_mapping_blif()}"+"".join([c.get_function_blif_flat() for c in self.components])
# Not needed in 1-bit circuits
def get_function_out_blif(self):
return ""
return f"{self.out.get_wire_assign_blif(output=True)}"
# HIERARCHICAL BLIF #
# Subcomponent generation
def get_function_block_blif(self):
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"))
adder_block = self.__class__()
return f"{adder_block.get_circuit_blif()}"
def get_function_blif_hier(self):
return "".join(c.get_invocation_blif_hier(init=False) for c in self.components)
def get_invocation_blif_hier(self, **kwargs):
circuit_class = self.__class__()
return f"{self.get_wire_mapping_blif()}" + \
f".subckt ha a={self.circuit_wires[0][0].name} b={self.circuit_wires[1][0].name} ha_y0={self.out.get_wire(0).name} ha_y1={self.out.get_wire(1).name}\n"
f".subckt {circuit_class.prefix} a={self.inputs[0].name} b={self.inputs[1].name}{''.join([f' {self.out.prefix}[{circuit_class.out.bus.index(o)}]={self.out.get_wire(circuit_class.out.bus.index(o)).name}' for o in circuit_class.out.bus])}\n"
# Self circuit hierarchical generation
def get_function_blif_hier(self):
return f"{self.get_wire_mapping_blif()}"+"".join(c.get_invocation_blif_hier(init=False) for c in self.components)
def get_circuit_blif(self):
return f"{self.get_prototype_blif()}" + \
f"{self.get_declaration_blif()}" + \
f"{self.get_wire_mapping_blif()}" + \
f"{self.get_function_blif_hier()}" + \
f".end\n"
""" CGP CODE GENERATION """
# FLAT CGP #
def get_parameters_cgp(self):
@ -153,8 +147,59 @@ class one_bit_circuit(arithmetic_circuit):
return f"{{2,2,1,{len(self.circuit_gates)},2,1,0}}"
class half_adder(one_bit_circuit):
def __init__(self, a: wire, b: wire, prefix: str = "ha"):
class three_input_one_bit_circuit(two_input_one_bit_circuit):
def __init__(self):
super().__init__()
""" C CODE GENERATION """
# FLAT C #
# Function prototype with three inputs
def get_prototype_c(self):
return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix}, {self.c_data_type} {self.c.prefix})" + "{" + "\n"
# HIERARCHICAL C #
# Subcomponent generation (3 inputs)
def get_out_invocation_c(self, **kwargs):
circuit_class = self.__class__()
return "".join([f' {o.name} = ({circuit_class.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> {self.out.bus.index(o)}) & 0x01;\n' for o in self.out.bus])
""" VERILOG CODE GENERATION """
# FLAT VERILOG #
# Module prototype with three inputs
def get_prototype_v(self):
return f"module {self.prefix}(input {self.a.name}, input {self.b.name}, input {self.c.name}{''.join([f', output {o.name}' for o in self.out.bus])});\n"
# HIERARCHICAL VERILOG #
# Subcomponent generation (3 inputs)
def get_invocation_v(self, **kwargs):
circuit_class = self.__class__()
return f" {circuit_class.prefix} {circuit_class.prefix}_{self.out.get_wire().name}({self.a.name}, {self.b.name}, {self.c.name}{''.join([f', {o.name}' for o in self.out.bus])});\n"
""" BLIF CODE GENERATION """
# FLAT BLIF #
# Model prototype with three inputs
def get_declaration_blif(self):
return f".inputs {self.a.name} {self.b.name} {self.c.name}\n" + \
f".outputs{self.out.get_wire_declaration_blif()}\n"
# HIERARCHICAL BLIF #
# Subcomponent generation (3 inputs)
def get_invocation_blif_hier(self, **kwargs):
circuit_class = self.__class__()
return f"{self.get_wire_mapping_blif()}" + \
f".subckt {circuit_class.prefix} a={self.inputs[0].name} b={self.inputs[1].name} cin={self.inputs[2].name}{''.join([f' {self.out.prefix}[{circuit_class.out.bus.index(o)}]={self.out.get_wire(circuit_class.out.bus.index(o)).name}' for o in circuit_class.out.bus])}\n"
""" CGP CODE GENERATION """
# FLAT CGP #
# Chromosome prototype with three inputs
def get_parameters_cgp(self):
self.circuit_gates = self.get_circuit_gates()
return f"{{3,2,1,{len(self.circuit_gates)},2,1,0}}"
# TWO INPUT CIRCUITS
class half_adder(two_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), prefix: str = "ha"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
@ -165,19 +210,100 @@ class half_adder(one_bit_circuit):
# Sum
# XOR gate for calculation of 1-bit sum
obj_xor_gate = xor_gate(a, b, prefix, outid=0)
self.add_component(obj_xor_gate)
self.out.connect(0, obj_xor_gate.out)
obj_xor = xor_gate(a, b, prefix=self.prefix, outid=0)
self.add_component(obj_xor)
self.out.connect(0, obj_xor.out)
# Cout
# AND gate for calculation of 1-bit cout
obj_and_gate = and_gate(a, b, prefix, outid=1)
self.add_component(obj_and_gate)
self.out.connect(1, obj_and_gate.out)
obj_and = and_gate(a, b, prefix=self.prefix, outid=1)
self.add_component(obj_and)
self.out.connect(1, obj_and.out)
class full_adder(one_bit_circuit):
def __init__(self, a: wire, b: wire, c: wire, prefix: str = "fa"):
class pg_logic_block(two_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), prefix: str = "pg_logic"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
self.a = a
self.b = b
# 3 wires for component's bus output (propagate, generate, sum)
self.out = bus("out", self.N+2)
# PG logic
propagate_or = or_gate(a, b, prefix=self.prefix, outid=0)
self.add_component(propagate_or)
generate_and = and_gate(a, b, prefix=self.prefix, outid=1)
self.add_component(generate_and)
sum_xor = xor_gate(a, b, prefix=self.prefix, outid=2)
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 get_propagate_wire(self):
return self.out.get_wire(0)
def get_generate_wire(self):
return self.out.get_wire(1)
def get_sum_wire(self):
return self.out.get_wire(2)
class constant_wire_value_0(two_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), prefix: str = "constant_wire_value_0"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
self.a = a
self.b = b
# 1 wire for component's bus output (constant wire)
self.out = bus("out", self.N)
# Generation of wire with constant value 0
obj_xor = xor_gate(self.a, self.b, prefix=self.prefix, outid=0)
obj_xnor = xnor_gate(self.a, self.b, prefix=self.prefix, outid=1)
obj_nor = nor_gate(obj_xor.out, obj_xnor.out, prefix=self.prefix, outid=2)
obj_nor.out.name = "constant_wire_0"
obj_nor.out.prefix = "constant_wire_0"
self.add_component(obj_xor)
self.add_component(obj_xnor)
self.add_component(obj_nor)
# Constant wire output
self.out.connect(0, obj_nor.out)
class constant_wire_value_1(two_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), prefix: str = "constant_wire_value_1"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
self.a = a
self.b = b
# 1 wire for component's bus output (constant wire)
self.out = bus("out", self.N)
# Generation of wire with constant value 1
obj_xor = xor_gate(self.a, self.b, prefix=self.prefix, outid=0)
obj_xnor = xnor_gate(self.a, self.b, prefix=self.prefix, outid=1)
obj_or = or_gate(obj_xor.out, obj_xnor.out, prefix=self.prefix, outid=2)
obj_or.out.name = "constant_wire_1"
obj_or.out.prefix = "constant_wire_1"
self.add_component(obj_xor)
self.add_component(obj_xnor)
self.add_component(obj_or)
# Constant wire output
self.out.connect(0, obj_or.out)
# THREE INPUT CIRCUITS
class full_adder(three_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), c: wire = wire(name="cin"), prefix: str = "fa"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
@ -188,147 +314,58 @@ class full_adder(one_bit_circuit):
self.out = bus("out", self.N+1)
# PG logic
propagate_xor_gate1 = xor_gate(a, b, prefix, outid=0)
self.add_component(propagate_xor_gate1)
generate_and_gate1 = and_gate(a, b, prefix, outid=1)
self.add_component(generate_and_gate1)
propagate_xor = xor_gate(a, b, prefix=self.prefix, outid=0)
self.add_component(propagate_xor)
generate_and = and_gate(a, b, prefix=self.prefix, outid=1)
self.add_component(generate_and)
# Sum
# XOR gate for calculation of 1-bit sum
obj_xor_gate2 = xor_gate(propagate_xor_gate1.out, c, prefix, outid=2)
self.add_component(obj_xor_gate2)
self.out.connect(0, obj_xor_gate2.out)
obj_xor = xor_gate(propagate_xor.out, c, prefix=self.prefix, outid=2)
self.add_component(obj_xor)
self.out.connect(0, obj_xor.out)
# Cout
# AND gate for calculation of 1-bit cout
obj_and_gate2 = and_gate(propagate_xor_gate1.out, c, prefix, outid=3)
self.add_component(obj_and_gate2)
obj_and = and_gate(propagate_xor.out, c, prefix=self.prefix, outid=3)
self.add_component(obj_and)
obj_or_gate = or_gate(generate_and_gate1.out, obj_and_gate2.out, prefix, outid=4)
self.add_component(obj_or_gate)
obj_or = or_gate(generate_and.out, obj_and.out, prefix=self.prefix, outid=4)
self.add_component(obj_or)
self.out.connect(1, obj_or_gate.out)
self.out.connect(1, obj_or.out)
# TODO delete?
# Storing PG logic gates for better accessibility
self.propagate = propagate_xor_gate1
self.generate = generate_and_gate1
""" C CODE GENERATION """
# FLAT C #
# 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.prefix}, {self.c_data_type} {self.b.prefix}, {self.c_data_type} {self.c.prefix})" + "{" + "\n"
class full_adder_pg(three_input_one_bit_circuit):
def __init__(self, a: wire = wire(name="a"), b: wire = wire(name="b"), c: wire = wire(name="cin"), prefix: str = "fa_cla"):
super().__init__()
self.c_data_type = "uint8_t"
self.prefix = prefix
self.a = a
self.b = b
self.c = c
# 3 wires for component's bus output (sum, propagate, generate)
self.out = bus("out", self.N+2)
# Full adder wires values initialization
def get_init_c_flat(self):
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])
# PG logic
propagate_xor = xor_gate(a, b, prefix=self.prefix, outid=0)
self.add_component(propagate_xor)
self.out.connect(0, propagate_xor.out)
# 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()}"
generate_and = and_gate(a, b, prefix=self.prefix, outid=1)
self.add_component(generate_and)
self.out.connect(1, generate_and.out)
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)}"
# Sum output
sum_xor = xor_gate(propagate_xor.out, c, prefix=self.prefix, outid=2)
self.add_component(sum_xor)
self.out.connect(2, sum_xor.out)
def get_propagate_wire(self):
return self.out.get_wire(0)
def get_sum_invocation_c(self):
return f" {self.get_sum_wire().name} = (fa({self.a.name}, {self.b.name}, {self.c.name}) >> 0) & 0x01;"
def get_generate_wire(self):
return self.out.get_wire(1)
def get_cout_invocation_c(self):
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.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 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()}" + \
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}"
""" VERILOG CODE GENERATION """
# FLAT VERILOG #
def get_prototype_v(self):
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):
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, **kwargs):
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[2].get_gate_invocation_v(remove_prefix=False)}"
def get_function_carry_v_hier(self):
# 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()}" + \
f"{self.get_declaration_v_hier()}\n" + \
f"{self.get_init_v_hier()}\n" + \
f"{self.get_function_sum_v_hier()}" + \
f"{self.get_function_carry_v_hier()}" + \
f"endmodule"
""" BLIF CODE GENERATION """
# FLAT BLIF #
def get_declaration_blif(self):
return f".inputs {self.a.name} {self.b.name} {self.c.name}" + \
f"\n.outputs" + \
"".join([f" {w.name}" for w in self.out.bus])+"\n"
def get_wire_mapping_blif(self):
# For unique mapping of all circuit's input interconnections
self.get_circuit_wires()
# getting desired inner wires and selecting first element from list of tuples containing wires and other info
return f"{self.circuit_wires[0][0].get_assign_blif(name=self.circuit_wires[0][0].name.replace(self.prefix+'_', ''))}" + \
f"{self.circuit_wires[1][0].get_assign_blif(name=self.circuit_wires[1][0].name.replace(self.prefix+'_', ''))}" + \
f"{self.circuit_wires[4][0].get_assign_blif(name=self.circuit_wires[4][0].name.replace(self.prefix+'_', ''))}"
# HIERARCHICAL BLIF #
def get_invocation_blif_hier(self, **kwargs):
return f"{self.get_wire_mapping_blif()}" + \
f".subckt fa a={self.circuit_wires[0][0].name} b={self.circuit_wires[1][0].name} cin={self.circuit_wires[4][0].name} fa_y2={self.out.get_wire(0).name} fa_y4={self.out.get_wire(1).name}\n"
""" CGP CODE GENERATION """
# FLAT CGP #
def get_parameters_cgp(self):
self.circuit_gates = self.get_circuit_gates()
return f"{{3,2,1,{len(self.circuit_gates)},2,1,0}}"
def get_sum_wire(self):
return self.out.get_wire(2)