mirror of
https://github.com/ehw-fit/ariths-gen.git
synced 2025-04-21 22:31:22 +01:00
218 lines
12 KiB
Python
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)
|