218 lines
12 KiB
Python

from ariths_gen.multi_bit_circuits.adders.ripple_carry_adder import UnsignedRippleCarryAdder
from ariths_gen.wire_components import(
Wire,
Bus
)
from ariths_gen.core import(
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
HalfAdder,
ConstantWireValue0,
ConstantWireValue1,
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
LogicGate,
AndGate,
NandGate,
OrGate,
NorGate,
XorGate,
XnorGate,
NotGate
)
class UnsignedDaddaMultiplier(MultiplierCircuit):
def __init__(self, a: Bus, b: Bus, prefix: str = "u_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
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
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 gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = HalfAdder(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=HalfAdder)))
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 gates if neccesarry (via get_column_wire invocation) into list of circuit components
obj_adder = FullAdder(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=FullAdder)))
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
if self.N == 1:
constant_wire_0 = ConstantWireValue0(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 = HalfAdder(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=HalfAdder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
obj_ha = HalfAdder(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=HalfAdder)))
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:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_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_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_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 SignedDaddaMultiplier(MultiplierCircuit):
def __init__(self, a: Bus, b: Bus, prefix: str = "s_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
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 = ConstantWireValue1(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 = HalfAdder(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=HalfAdder)))
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 = FullAdder(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=FullAdder)))
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 = ConstantWireValue0(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 = HalfAdder(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=HalfAdder)))
self.add_component(obj_ha)
self.out.connect(1, obj_ha.get_sum_wire())
obj_ha = HalfAdder(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=HalfAdder)))
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:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_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_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_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 = XorGate(constant_wire_1.out.get_wire(), self.out.get_wire(self.out.N-1), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=XorGate)))
self.add_component(obj_xor)
self.out.connect(self.out.N-1, obj_xor.out)