From fffb9288753df796a70412db929ef1e3ea9bd5fe Mon Sep 17 00:00:00 2001
From: Vojta Mrazek <mrazek@fit.vutbr.cz>
Date: Tue, 7 Sep 2021 08:32:52 +0200
Subject: [PATCH] auto test MAC

---
 .github/workflows/generate.yml |  7 ++++
 generate_mac.py                | 60 ++++++++++++++++++++++++++++++++++
 tests/mac.c                    | 23 +++++++++++++
 tests/test_mac.sh              | 35 ++++++++++++++++++++
 4 files changed, 125 insertions(+)
 create mode 100644 generate_mac.py
 create mode 100644 tests/mac.c
 create mode 100644 tests/test_mac.sh

diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml
index 1da9788..ae1a56e 100644
--- a/.github/workflows/generate.yml
+++ b/.github/workflows/generate.yml
@@ -30,6 +30,8 @@ jobs:
       run: python -c "import sys; print(sys.version)"
     - name: Run generating
       run: python generate_test.py
+    - name: Run generating
+      run: python generate_mac.py
     - name: Upload results
       uses: actions/upload-artifact@v1.0.0
       with:
@@ -62,6 +64,11 @@ jobs:
         cd tests
         bash test_circuits_cgp.sh
         cd ..
+    - name: Run MAC testing
+      run: |
+        cd tests
+        bash test_mac.sh
+        cd ..
 
   # Only on main thread 
   documentation:
diff --git a/generate_mac.py b/generate_mac.py
new file mode 100644
index 0000000..173bad0
--- /dev/null
+++ b/generate_mac.py
@@ -0,0 +1,60 @@
+
+from ariths_gen.core.arithmetic_circuits import GeneralCircuit
+from ariths_gen.wire_components import Bus, Wire
+from ariths_gen.multi_bit_circuits.adders import UnsignedRippleCarryAdder
+from ariths_gen.multi_bit_circuits.multipliers import UnsignedArrayMultiplier
+import os
+
+class MAC(GeneralCircuit):
+    def __init__(self, A:Bus, B:Bus, R:Bus):
+        self.prefix = "mac"
+        super().__init__([A, B, R])
+        assert A.N == B.N
+        assert R.N == 2 * A.N
+
+
+        if False:
+            # Je zapotřebí zajistit ještě unikátnost jmen podkomponent a jejich vodičů pro správné generování
+            mul_a = Bus(prefix=f"{self.prefix}_mul_a", wires_list=A.bus)
+            mul_b = Bus(prefix=f"{self.prefix}_mul_b", wires_list=B.bus)
+            self.mul = self.add_component(UnsignedArrayMultiplier(a=mul_a, b=mul_b, prefix=f"{self.prefix}_mul"))
+
+            add_a = Bus(prefix=f"{self.prefix}_add_a", N=self.mul.out.N)
+            add_b = Bus(prefix=f"{self.prefix}_add_b", wires_list=R.bus)
+            # Kvůli správnému generování je potřeba správně napojit vodiče mezi mul a add
+            [add_a.connect(o, self.mul.out.get_wire(o), inserted_wire_desired_index=o) for o in range(0, self.mul.out.N)]
+
+            self.add = self.add_component(UnsignedRippleCarryAdder(a=add_a, b=add_b, prefix=f"{self.prefix}_add"))
+
+            # Bylo potřeba upravit definici pro výstupní sběrnici (vázanou na název top level obvodu ("ma") a mající délku jako výstup z adderu)
+            self.out = Bus(self.prefix+"_out", self.add.out.N)
+            
+            # Nakonec je potřeba napojit výstup adderu na výstup mac
+            [self.out.connect(o, self.add.out.get_wire(o), inserted_wire_desired_index=o) for o in range(0, self.out.N)]
+
+        else:
+            # Je zapotřebí zajistit ještě unikátnost jmen podkomponent a jejich vodičů pro správné generování
+            mul_prefix = self.prefix + "_" + UnsignedArrayMultiplier(a=A, b=B).prefix + str(A.N)
+            mul_a = Bus(prefix=f"{mul_prefix}_a", wires_list=A.bus)
+            mul_b = Bus(prefix=f"{mul_prefix}_b", wires_list=B.bus)
+            self.mul = self.add_component(UnsignedArrayMultiplier(a=mul_a, b=mul_b, prefix=mul_prefix))
+
+            add_prefix = self.prefix + "_" + UnsignedRippleCarryAdder(a=R, b=self.mul.out).prefix + str(R.N)
+            add_a = Bus(prefix=f"{add_prefix}_a", N=self.mul.out.N)
+            add_b = Bus(prefix=f"{add_prefix}_b", wires_list=R.bus)
+            # Kvůli správnému generování je potřeba správně napojit vodiče mezi mul a add
+            [add_a.connect(o, self.mul.out.get_wire(o), inserted_wire_desired_index=o) for o in range(0, self.mul.out.N)]
+
+            self.add = self.add_component(UnsignedRippleCarryAdder(a=add_a, b=add_b, prefix=add_prefix))
+
+            # Bylo potřeba upravit definici pro výstupní sběrnici (vázanou na název top level obvodu ("ma") a mající délku jako výstup z adderu)
+            self.out = Bus(self.prefix+"_out", self.add.out.N)
+            
+            # Nakonec je potřeba napojit výstup adderu na výstup mac
+            [self.out.connect(o, self.add.out.get_wire(o), inserted_wire_desired_index=o) for o in range(0, self.out.N)]
+# usage
+os.makedirs("test_circuits/mac", exist_ok=True)
+mymac = MAC(Bus("a",8), Bus("b", 8), Bus("acc", 16))
+mymac.get_v_code_hier(open("test_circuits/mac/mac_hier.v", "w"))
+mymac.get_c_code_hier(open("test_circuits/mac/mac_hier.c", "w"))
+mymac.get_c_code_flat(open("test_circuits/mac/mac_flat.c", "w"))
diff --git a/tests/mac.c b/tests/mac.c
new file mode 100644
index 0000000..653a6a9
--- /dev/null
+++ b/tests/mac.c
@@ -0,0 +1,23 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+uint64_t mac(uint64_t a,uint64_t b,uint64_t acc);
+
+
+int main() {
+  int result = 0;
+
+  srand(42);
+  for(int i = 0; i < 10000; i++) {
+      uint64_t a, b, acc;
+      a = rand() % 256;
+      b = rand() % 256;
+      acc = rand() % 65536;
+      result = (a * b) + acc;
+  
+      assert(result == mac(a, b, acc));
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/tests/test_mac.sh b/tests/test_mac.sh
new file mode 100644
index 0000000..04d9d9d
--- /dev/null
+++ b/tests/test_mac.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/bash
+
+valid=1
+
+test_circuit_mac () {
+    local type=$1
+
+
+
+    for mode in "flat" "hier"; do
+        echo -e "===== Testing \e[33m$circuit\e[0m ($mode) ======"
+
+        g++ -std=c++11 -pedantic -g -std=c++11 -pedantic -DCNAME="$circuit" $type.c ../test_circuits/mac/mac_$mode.c -o tmp.exe
+        if ./tmp.exe ; then
+            echo -e "[\e[32mok\e[0m]"
+        else
+            echo -e "[\e[31mfail\e[0m]"
+            valid=0
+        fi
+    done
+}
+
+
+
+test_circuit_mac "mac"
+
+
+
+if [ $valid -eq 1 ]; then
+    echo "all tests passed"
+    exit 0
+else 
+    echo "some of tests failed"
+    exit 1
+fi