from ariths_gen.wire_components import ( Wire, ConstantWireValue0, ConstantWireValue1, Bus ) from ariths_gen.core.arithmetic_circuits import GeneralCircuit from ariths_gen.multi_bit_circuits.adders import ( UnsignedCarryLookaheadAdder, UnsignedPGRippleCarryAdder, UnsignedRippleCarryAdder, SignedCarryLookaheadAdder, SignedPGRippleCarryAdder, SignedRippleCarryAdder, UnsignedCarrySkipAdder, SignedCarrySkipAdder, ) from ariths_gen.multi_bit_circuits.multipliers import ( UnsignedDaddaMultiplier, UnsignedArrayMultiplier, UnsignedWallaceMultiplier, UnsignedCarrySaveMultiplier, SignedArrayMultiplier, SignedDaddaMultiplier, SignedWallaceMultiplier, SignedCarrySaveMultiplier ) from ariths_gen.multi_bit_circuits.approximate_multipliers import ( UnsignedTruncatedArrayMultiplier, UnsignedTruncatedCarrySaveMultiplier, UnsignedBrokenArrayMultiplier, UnsignedBrokenCarrySaveMultiplier ) from ariths_gen.one_bit_circuits.logic_gates import ( AndGate, NandGate, OrGate, NorGate, XorGate, XnorGate, NotGate ) import numpy as np def test_unsigned_approxmul(values = False): """ Test unsigned approximate multipliers """ N = 7 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") av = np.arange(2**N) bv = av.reshape(-1, 1) expected = av * bv for c in [UnsignedBrokenArrayMultiplier, UnsignedBrokenCarrySaveMultiplier, UnsignedTruncatedArrayMultiplier, UnsignedTruncatedCarrySaveMultiplier]: if c == UnsignedTruncatedArrayMultiplier or c == UnsignedTruncatedCarrySaveMultiplier: mul = c(a=a, b=b, truncation_cut=2) elif c == UnsignedBrokenArrayMultiplier or c == UnsignedBrokenCarrySaveMultiplier: mul = c(a=a, b=b, horizontal_cut=1, vertical_cut=2) r = mul(av, bv) # WCE – worst case error; used for approximate multiplier error measurement WCE = np.amax(abs(np.subtract(r, expected))) # WCRE – worst case relative error; used for approximate multiplier error measurement np.seterr(divide='ignore', invalid='ignore') WCRE = np.max(np.nan_to_num(abs(np.subtract(r, expected)) / expected)) if isinstance(mul, UnsignedTruncatedArrayMultiplier) or isinstance(mul, UnsignedTruncatedCarrySaveMultiplier): # WCE_TM(n,k) = (2^k - 1) * (2^(n+1) - 2^k - 1) expected_WCE = (2 ** mul.truncation_cut - 1) * (2 ** (mul.a.N+1) - 2 ** mul.truncation_cut - 1) elif isinstance(mul, UnsignedBrokenArrayMultiplier) or isinstance(mul, UnsignedBrokenCarrySaveMultiplier): # WCE_BAM(n,h,v) = (2^n - 1) * {SUM_i0_to_h-1}(2^i) + 2^h * {SUM_i0_to_v-h-1}(2^(v-h) - 2^i) sum_1 = sum([2**i for i in range(0, mul.horizontal_cut)]) sum_2 = sum([2**(mul.vertical_cut-mul.horizontal_cut) - 2**i for i in range(0, mul.vertical_cut-mul.horizontal_cut)]) expected_WCE = (2 ** mul.N - 1) * sum_1 + 2 ** mul.horizontal_cut * sum_2 # Test expected result assert expected_WCE == WCE if values is True: np.testing.assert_array_equal(expected, r) def test_unsigned_mul(): """ Test unsigned multipliers """ N = 7 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") av = np.arange(2**N) bv = av.reshape(-1, 1) expected = av * bv for c in [UnsignedDaddaMultiplier, UnsignedArrayMultiplier, UnsignedCarrySaveMultiplier, UnsignedWallaceMultiplier]: mul = c(a, b) assert mul(0, 0) == 0 r = mul(av, bv) np.testing.assert_array_equal(expected, r) # For array wallace tree implementation mul = UnsignedWallaceMultiplier(a, b, use_csa=False) assert mul(0, 0) == 0 r = mul(av, bv) np.testing.assert_array_equal(expected, r) def test_signed_mul(): """ Test signed multipliers """ N = 7 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") av = np.arange(-(2**(N-1)), 2**(N-1)) bv = av.reshape(-1, 1) expected = av * bv for c in [SignedDaddaMultiplier, SignedArrayMultiplier, SignedWallaceMultiplier, SignedCarrySaveMultiplier]: mul = c(a, b) r = mul(av, bv) assert mul(0, 0) == 0 np.testing.assert_array_equal(expected, r) # For array wallace tree implementation mul = SignedWallaceMultiplier(a, b, use_csa=False) r = mul(av, bv) assert mul(0, 0) == 0 np.testing.assert_array_equal(expected, r) def test_unsigned_add(): """ Test unsigned adders """ N = 7 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") av = np.arange(2**N) bv = av.reshape(-1, 1) expected = av + bv for c in [UnsignedCarryLookaheadAdder, UnsignedPGRippleCarryAdder, UnsignedRippleCarryAdder, UnsignedCarrySkipAdder]: mul = c(a, b) r = mul(av, bv) np.testing.assert_array_equal(expected, r) def test_signed_add(): """ Test signed adders """ N = 7 a = Bus(N=N, prefix="a") b = Bus(N=N, prefix="b") av = np.arange(-(2**(N-1)), 2**(N-1)) bv = av.reshape(-1, 1) expected = av + bv for c in [SignedCarryLookaheadAdder, SignedPGRippleCarryAdder, SignedRippleCarryAdder, SignedCarrySkipAdder]: mul = c(a, b) r = mul(av, bv) np.testing.assert_array_equal(expected, r) def test_mac(): class MAC(GeneralCircuit): def __init__(self, a: Bus, b: Bus, r: Bus, prefix: str = "", name: str = "mac", **kwargs): super().__init__(prefix=prefix, name=name, out_N=2*a.N+1, inputs=[a, b, r], **kwargs) assert a.N == b.N assert r.N == 2 * a.N self.mul = self.add_component(UnsignedArrayMultiplier(a=a, b=b, prefix=self.prefix, name=f"u_arrmul{a.N}", inner_component=True)) self.add = self.add_component(UnsignedRippleCarryAdder(a=r, b=self.mul.out, prefix=self.prefix, name=f"u_rca{r.N}", inner_component=True)) self.out.connect_bus(connecting_bus=self.add.out) # usage mymac = MAC(Bus("a", 4), Bus("b", 4), Bus("acc", 8)) av = np.arange(2**4) bv = np.arange(2**4).reshape(-1, 1) cv = np.arange(2**8).reshape(-1, 1, 1) r = mymac(av, bv, cv) expected = (av * bv) + cv np.testing.assert_array_equal(r, expected) def test_direct(): class err_circuit(GeneralCircuit): def __init__(self, prefix: str = "", name: str = "adder", inner_component: bool = True, a: Bus = Bus(), b: Bus = Bus()): super().__init__(prefix = prefix, name=name, out_N = (a.N + 1), inner_component=inner_component, inputs = [a, b]) self.N = 1 self.prefix = prefix self.a = Bus(prefix=a.prefix, wires_list=a.bus) self.b = Bus(prefix=b.prefix, wires_list=b.bus) self.out = Bus(self.prefix+"_out", self.N+1) a_0 = self.a[0] b_0 = self.b.get_wire(0) or_1 = OrGate(a_0, b_0, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=OrGate)), parent_component=self) self.add_component(or_1) self.out.connect(0, a_0) self.out.connect(1, or_1.out) av = np.arange(0, 4).reshape(1, -1) bv = np.arange(0, 4).reshape(-1, 1) example = err_circuit(prefix = "err_circuit", a = Bus("a", 2) , b = Bus("b", 2)) r = example(av, bv) expected = np.array([[0, 3, 0, 3], [2, 3 ,2, 3], [0, 3, 0, 3], [2, 3, 2, 3]]) np.testing.assert_equal(r, expected) print(r)