mirror of
https://github.com/ehw-fit/ariths-gen.git
synced 2025-04-10 17:22:11 +01:00
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:
parent
d86ddcac09
commit
792d0c5db1
@ -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())
|
||||
|
@ -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"))
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
Loading…
x
Reference in New Issue
Block a user