Kaynağa Gözat

CMSIS-NN: Add unit test

Adds infrastructure based on Mbed.
Adds generate script that can generate input and reference data.
Adds unit tests for arm_convolve_s8, arm_convolve_1x1_s8_fast,
arm_depthwise_conv_s8 and arm_depthwise_conv_s8_opt.

Change-Id: I4f9f45beef0c2d83d21c6d41ae68560209e3e25c
Måns Nilsson 6 yıl önce
ebeveyn
işleme
eaa2a2457e
54 değiştirilmiş dosya ile 3249 ekleme ve 0 silme
  1. 3 0
      CMSIS/NN/.gitignore
  2. 2 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/bias.txt
  3. 41 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/input.txt
  4. 9 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/kernel.txt
  5. 12 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/params.txt
  6. 2 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/bias.txt
  7. 65 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/input.txt
  8. 5 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/kernel.txt
  9. 12 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/params.txt
  10. 2 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/bias.txt
  11. 50 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/input.txt
  12. 10 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/kernel.txt
  13. 12 0
      CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/params.txt
  14. 10 0
      CMSIS/NN/Tests/UnitTest/Profiles/mbed_app.json
  15. 58 0
      CMSIS/NN/Tests/UnitTest/Profiles/release.json
  16. 67 0
      CMSIS/NN/Tests/UnitTest/README.md
  17. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/biases_data.h
  18. 40 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/config_data.h
  19. 66 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/input_data.h
  20. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_mult_data.h
  21. 46 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_ref_data.h
  22. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_shift_data.h
  23. 28 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/test_data.h
  24. 34 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/weights_data.h
  25. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/biases_data.h
  26. 40 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/config_data.h
  27. 282 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/input_data.h
  28. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_mult_data.h
  29. 90 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_ref_data.h
  30. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_shift_data.h
  31. 28 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/test_data.h
  32. 30 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/weights_data.h
  33. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/biases_data.h
  34. 40 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/config_data.h
  35. 75 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/input_data.h
  36. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_mult_data.h
  37. 42 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_ref_data.h
  38. 27 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_shift_data.h
  39. 28 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/test_data.h
  40. 35 0
      CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/weights_data.h
  41. 51 0
      CMSIS/NN/Tests/UnitTest/TestCases/Utils/validate.h
  42. 47 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_1x1_s8_fast/Unity/unity_test_arm_convolve_1x1_s8_fast.c
  43. 59 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_1x1_s8_fast/test_arm_convolve_1x1_s8_fast.c
  44. 52 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_s8/Unity/unity_test_arm_convolve_s8.c
  45. 106 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_s8/test_arm_convolve_s8.c
  46. 84 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/TestRunner/test_arm_depthwise_conv_s8_runner.c
  47. 52 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/Unity/unity_test_arm_depthwwise_conv_s8.c
  48. 104 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/test_arm_depthwise_conv_s8.c
  49. 85 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/TestRunner/test_arm_depthwise_conv_s8_opt_runner.c
  50. 52 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/Unity/unity_test_arm_depthwise_conv_s8_opt.c
  51. 111 0
      CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/test_arm_depthwise_conv_s8_opt.c
  52. 461 0
      CMSIS/NN/Tests/UnitTest/generate_test_data.py
  53. 51 0
      CMSIS/NN/Tests/UnitTest/requirements.txt
  54. 427 0
      CMSIS/NN/Tests/UnitTest/unittest_targets.py

+ 3 - 0
CMSIS/NN/.gitignore

@@ -0,0 +1,3 @@
+Tests/UnitTest/TestCases/*/Unity/TestRunner/*
+Tests/UnitTest/Output/*
+Tests/Unity/*

+ 2 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/bias.txt

@@ -0,0 +1,2 @@
+# 1
+0.000000000000000000e+00

+ 41 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/input.txt

@@ -0,0 +1,41 @@
+# 1,8,5,1
+-4.000000000000000000e+00
+4.000000000000000000e+00
+3.000000000000000000e+00
+-1.000000000000000000e+00
+0.000000000000000000e+00
+-6.000000000000000000e+00
+-4.000000000000000000e+00
+3.000000000000000000e+00
+-7.000000000000000000e+00
+-2.000000000000000000e+00
+2.000000000000000000e+00
+3.000000000000000000e+00
+-3.000000000000000000e+00
+-7.000000000000000000e+00
+-3.000000000000000000e+00
+-3.000000000000000000e+00
+4.000000000000000000e+00
+-3.000000000000000000e+00
+-3.000000000000000000e+00
+3.000000000000000000e+00
+-4.000000000000000000e+00
+-6.000000000000000000e+00
+-7.000000000000000000e+00
+-6.000000000000000000e+00
+-3.000000000000000000e+00
+-5.000000000000000000e+00
+-3.000000000000000000e+00
+-5.000000000000000000e+00
+-2.000000000000000000e+00
+-2.000000000000000000e+00
+4.000000000000000000e+00
+-6.000000000000000000e+00
+6.000000000000000000e+00
+0.000000000000000000e+00
+0.000000000000000000e+00
+2.000000000000000000e+00
+1.000000000000000000e+00
+1.000000000000000000e+00
+3.000000000000000000e+00
+-2.000000000000000000e+00

+ 9 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/kernel.txt

@@ -0,0 +1,9 @@
+# 4,2,1,1
+-2.000000000000000000e+00
+-1.000000000000000000e+00
+2.000000000000000000e+00
+-7.000000000000000000e+00
+0.000000000000000000e+00
+0.000000000000000000e+00
+6.000000000000000000e+00
+-6.000000000000000000e+00

+ 12 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/basic/params.txt

@@ -0,0 +1,12 @@
+1
+1
+5
+8
+2
+4
+1
+1
+0
+0
+1
+0

+ 2 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/bias.txt

@@ -0,0 +1,2 @@
+# 1
+4.000000000000000000e+00

+ 65 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/input.txt

@@ -0,0 +1,65 @@
+# 1,8,8,4
+0.000000000000000000e+00,-1.000000000000000000e+00,-5.000000000000000000e+00,-6.000000000000000000e+00
+1.000000000000000000e+00,-5.000000000000000000e+00,0.000000000000000000e+00,5.000000000000000000e+00
+2.000000000000000000e+00,-6.000000000000000000e+00,1.000000000000000000e+00,-1.000000000000000000e+00
+6.000000000000000000e+00,-2.000000000000000000e+00,-1.000000000000000000e+00,2.000000000000000000e+00
+6.000000000000000000e+00,5.000000000000000000e+00,6.000000000000000000e+00,-1.000000000000000000e+00
+2.000000000000000000e+00,-2.000000000000000000e+00,4.000000000000000000e+00,4.000000000000000000e+00
+3.000000000000000000e+00,-5.000000000000000000e+00,-6.000000000000000000e+00,3.000000000000000000e+00
+-4.000000000000000000e+00,-4.000000000000000000e+00,-6.000000000000000000e+00,-3.000000000000000000e+00
+-6.000000000000000000e+00,5.000000000000000000e+00,-3.000000000000000000e+00,2.000000000000000000e+00
+0.000000000000000000e+00,-2.000000000000000000e+00,0.000000000000000000e+00,-5.000000000000000000e+00
+-3.000000000000000000e+00,-2.000000000000000000e+00,1.000000000000000000e+00,4.000000000000000000e+00
+2.000000000000000000e+00,4.000000000000000000e+00,-3.000000000000000000e+00,-5.000000000000000000e+00
+4.000000000000000000e+00,1.000000000000000000e+00,-1.000000000000000000e+00,6.000000000000000000e+00
+-1.000000000000000000e+00,4.000000000000000000e+00,-7.000000000000000000e+00,6.000000000000000000e+00
+-7.000000000000000000e+00,1.000000000000000000e+00,-3.000000000000000000e+00,-3.000000000000000000e+00
+-6.000000000000000000e+00,3.000000000000000000e+00,-6.000000000000000000e+00,-1.000000000000000000e+00
+-4.000000000000000000e+00,1.000000000000000000e+00,-6.000000000000000000e+00,-3.000000000000000000e+00
+6.000000000000000000e+00,3.000000000000000000e+00,-3.000000000000000000e+00,-1.000000000000000000e+00
+-5.000000000000000000e+00,1.000000000000000000e+00,-4.000000000000000000e+00,-7.000000000000000000e+00
+0.000000000000000000e+00,-4.000000000000000000e+00,-5.000000000000000000e+00,2.000000000000000000e+00
+0.000000000000000000e+00,4.000000000000000000e+00,-3.000000000000000000e+00,-3.000000000000000000e+00
+1.000000000000000000e+00,0.000000000000000000e+00,-4.000000000000000000e+00,-4.000000000000000000e+00
+-4.000000000000000000e+00,6.000000000000000000e+00,-5.000000000000000000e+00,-1.000000000000000000e+00
+-5.000000000000000000e+00,-2.000000000000000000e+00,1.000000000000000000e+00,-5.000000000000000000e+00
+3.000000000000000000e+00,-7.000000000000000000e+00,-7.000000000000000000e+00,4.000000000000000000e+00
+-6.000000000000000000e+00,-7.000000000000000000e+00,4.000000000000000000e+00,2.000000000000000000e+00
+0.000000000000000000e+00,-6.000000000000000000e+00,-7.000000000000000000e+00,4.000000000000000000e+00
+-4.000000000000000000e+00,0.000000000000000000e+00,6.000000000000000000e+00,5.000000000000000000e+00
+4.000000000000000000e+00,-1.000000000000000000e+00,-2.000000000000000000e+00,4.000000000000000000e+00
+-2.000000000000000000e+00,-6.000000000000000000e+00,-3.000000000000000000e+00,2.000000000000000000e+00
+5.000000000000000000e+00,-5.000000000000000000e+00,1.000000000000000000e+00,-7.000000000000000000e+00
+-1.000000000000000000e+00,2.000000000000000000e+00,-6.000000000000000000e+00,3.000000000000000000e+00
+-3.000000000000000000e+00,-3.000000000000000000e+00,-3.000000000000000000e+00,5.000000000000000000e+00
+1.000000000000000000e+00,-2.000000000000000000e+00,-3.000000000000000000e+00,6.000000000000000000e+00
+1.000000000000000000e+00,3.000000000000000000e+00,5.000000000000000000e+00,-6.000000000000000000e+00
+-1.000000000000000000e+00,-1.000000000000000000e+00,2.000000000000000000e+00,6.000000000000000000e+00
+-5.000000000000000000e+00,-3.000000000000000000e+00,3.000000000000000000e+00,-1.000000000000000000e+00
+-6.000000000000000000e+00,-6.000000000000000000e+00,-6.000000000000000000e+00,4.000000000000000000e+00
+5.000000000000000000e+00,0.000000000000000000e+00,-3.000000000000000000e+00,0.000000000000000000e+00
+1.000000000000000000e+00,6.000000000000000000e+00,-4.000000000000000000e+00,-1.000000000000000000e+00
+-5.000000000000000000e+00,-1.000000000000000000e+00,-2.000000000000000000e+00,5.000000000000000000e+00
+-5.000000000000000000e+00,-7.000000000000000000e+00,3.000000000000000000e+00,-6.000000000000000000e+00
+5.000000000000000000e+00,1.000000000000000000e+00,3.000000000000000000e+00,-7.000000000000000000e+00
+4.000000000000000000e+00,5.000000000000000000e+00,3.000000000000000000e+00,1.000000000000000000e+00
+2.000000000000000000e+00,0.000000000000000000e+00,-5.000000000000000000e+00,4.000000000000000000e+00
+-1.000000000000000000e+00,6.000000000000000000e+00,-5.000000000000000000e+00,-1.000000000000000000e+00
+-7.000000000000000000e+00,-4.000000000000000000e+00,4.000000000000000000e+00,4.000000000000000000e+00
+3.000000000000000000e+00,2.000000000000000000e+00,4.000000000000000000e+00,6.000000000000000000e+00
+5.000000000000000000e+00,6.000000000000000000e+00,-6.000000000000000000e+00,5.000000000000000000e+00
+-7.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,-6.000000000000000000e+00
+-5.000000000000000000e+00,4.000000000000000000e+00,6.000000000000000000e+00,3.000000000000000000e+00
+1.000000000000000000e+00,1.000000000000000000e+00,2.000000000000000000e+00,-2.000000000000000000e+00
+3.000000000000000000e+00,-1.000000000000000000e+00,-3.000000000000000000e+00,3.000000000000000000e+00
+2.000000000000000000e+00,0.000000000000000000e+00,-4.000000000000000000e+00,-1.000000000000000000e+00
+-2.000000000000000000e+00,-4.000000000000000000e+00,6.000000000000000000e+00,5.000000000000000000e+00
+6.000000000000000000e+00,-7.000000000000000000e+00,-4.000000000000000000e+00,-2.000000000000000000e+00
+5.000000000000000000e+00,4.000000000000000000e+00,2.000000000000000000e+00,-7.000000000000000000e+00
+6.000000000000000000e+00,-7.000000000000000000e+00,1.000000000000000000e+00,-3.000000000000000000e+00
+2.000000000000000000e+00,2.000000000000000000e+00,-4.000000000000000000e+00,6.000000000000000000e+00
+5.000000000000000000e+00,3.000000000000000000e+00,-3.000000000000000000e+00,2.000000000000000000e+00
+4.000000000000000000e+00,0.000000000000000000e+00,-6.000000000000000000e+00,2.000000000000000000e+00
+-1.000000000000000000e+00,4.000000000000000000e+00,-5.000000000000000000e+00,-1.000000000000000000e+00
+4.000000000000000000e+00,5.000000000000000000e+00,-3.000000000000000000e+00,-1.000000000000000000e+00
+-2.000000000000000000e+00,2.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00

+ 5 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/kernel.txt

@@ -0,0 +1,5 @@
+# 1,1,4,1
+4.000000000000000000e+00
+-2.000000000000000000e+00
+0.000000000000000000e+00
+5.000000000000000000e+00

+ 12 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/kernel1x1/params.txt

@@ -0,0 +1,12 @@
+4
+1
+8
+8
+1
+1
+1
+1
+0
+0
+1
+0

+ 2 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/bias.txt

@@ -0,0 +1,2 @@
+# 1
+2.000000000000000000e+00

+ 50 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/input.txt

@@ -0,0 +1,50 @@
+# 1,7,7,1
+-7.000000000000000000e+00
+-6.000000000000000000e+00
+6.000000000000000000e+00
+-4.000000000000000000e+00
+-7.000000000000000000e+00
+6.000000000000000000e+00
+5.000000000000000000e+00
+0.000000000000000000e+00
+-2.000000000000000000e+00
+-1.000000000000000000e+00
+0.000000000000000000e+00
+-1.000000000000000000e+00
+-3.000000000000000000e+00
+0.000000000000000000e+00
+-7.000000000000000000e+00
+3.000000000000000000e+00
+-5.000000000000000000e+00
+4.000000000000000000e+00
+-2.000000000000000000e+00
+0.000000000000000000e+00
+-4.000000000000000000e+00
+-4.000000000000000000e+00
+-7.000000000000000000e+00
+-6.000000000000000000e+00
+2.000000000000000000e+00
+-6.000000000000000000e+00
+6.000000000000000000e+00
+6.000000000000000000e+00
+-5.000000000000000000e+00
+6.000000000000000000e+00
+-1.000000000000000000e+00
+1.000000000000000000e+00
+-5.000000000000000000e+00
+0.000000000000000000e+00
+-1.000000000000000000e+00
+1.000000000000000000e+00
+6.000000000000000000e+00
+-5.000000000000000000e+00
+0.000000000000000000e+00
+0.000000000000000000e+00
+-6.000000000000000000e+00
+5.000000000000000000e+00
+5.000000000000000000e+00
+-1.000000000000000000e+00
+3.000000000000000000e+00
+-6.000000000000000000e+00
+-4.000000000000000000e+00
+-5.000000000000000000e+00
+5.000000000000000000e+00

+ 10 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/kernel.txt

@@ -0,0 +1,10 @@
+# 3,3,1,1
+-1.000000000000000000e+00
+-5.000000000000000000e+00
+-1.000000000000000000e+00
+0.000000000000000000e+00
+5.000000000000000000e+00
+-6.000000000000000000e+00
+-7.000000000000000000e+00
+-3.000000000000000000e+00
+0.000000000000000000e+00

+ 12 - 0
CMSIS/NN/Tests/UnitTest/PregeneratedData/stride2pad1/params.txt

@@ -0,0 +1,12 @@
+1
+1
+7
+7
+3
+3
+2
+2
+0
+0
+1
+1

+ 10 - 0
CMSIS/NN/Tests/UnitTest/Profiles/mbed_app.json

@@ -0,0 +1,10 @@
+{
+    "target_overrides": {
+        "K64F": {
+            "platform.stdio-baud-rate": 9600
+        }
+    },
+    "requires": [
+        "bare-metal"
+    ]
+}

+ 58 - 0
CMSIS/NN/Tests/UnitTest/Profiles/release.json

@@ -0,0 +1,58 @@
+{
+    "GCC_ARM": {
+        "common": ["-c", "-Wall", "-Wextra",
+                   "-Wno-unused-parameter", "-Wno-missing-field-initializers",
+                   "-fmessage-length=0", "-fno-exceptions",
+                   "-ffunction-sections", "-fdata-sections", "-funsigned-char",
+                   "-MMD", "-fno-delete-null-pointer-checks",
+                   "-fomit-frame-pointer", "-Ofast", "-DNDEBUG", "-g"],
+        "asm": ["-x", "assembler-with-cpp"],
+        "c": ["-std=gnu11"],
+        "cxx": ["-std=gnu++14", "-fno-rtti", "-Wvla"],
+        "ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
+               "-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r", "-Wl,--wrap,_memalign_r",
+               "-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit",
+               "-Wl,-n"]
+    },
+    "ARMC6": {
+        "common": ["-c", "--target=arm-arm-none-eabi", "-mthumb", "-Omax",
+                   "-Wno-armcc-pragma-push-pop", "-Wno-armcc-pragma-anon-unions",
+                   "-Wno-reserved-user-defined-literal", "-Wno-deprecated-register",
+                   "-DMULADDC_CANNOT_USE_R7", "-fdata-sections",
+                   "-fno-exceptions", "-MMD", "-D_LIBCPP_EXTERN_TEMPLATE(...)=",
+                   "-fshort-enums", "-fshort-wchar", "-DNDEBUG"],
+        "asm": [],
+        "c": ["-D__ASSERT_MSG", "-std=gnu11"],
+        "cxx": ["-fno-rtti", "-std=gnu++14"],
+        "ld": ["--show_full_path", "--any_contingency", "--lto",
+               "--keep=os_cb_sections"]
+    },
+    "ARM": {
+        "common": ["-c", "--gnu", "-Ospace", "--split_sections",
+                   "--apcs=interwork", "--brief_diagnostics", "--restrict",
+                   "--multibyte_chars", "-O3", "-DNDEBUG"],
+        "asm": [],
+        "c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
+        "cxx": ["--cpp11", "--no_rtti", "--no_vla"],
+        "ld": ["--show_full_path", "--any_contingency", "--keep=os_cb_sections"]
+    },
+    "uARM": {
+        "common": ["-c", "--gnu", "-Ospace", "--split_sections",
+                   "--apcs=interwork", "--brief_diagnostics", "--restrict",
+                   "--multibyte_chars", "-O3", "-D__MICROLIB",
+                   "--library_type=microlib", "-DMBED_RTOS_SINGLE_THREAD", "-DNDEBUG"],
+        "asm": [],
+        "c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
+        "cxx": ["--cpp11", "--no_rtti", "--no_vla"],
+        "ld": ["--library_type=microlib"]
+    },
+    "IAR": {
+        "common": [
+            "--no_wrap_diagnostics", "-e",
+            "--diag_suppress=Pa050,Pa084,Pa093,Pa082,Pe540", "-Ohz", "-DNDEBUG", "--enable_restrict"],
+        "asm": [],
+        "c": ["--vla", "--diag_suppress=Pe546"],
+        "cxx": ["--guard_calls", "--no_static_destruction"],
+        "ld": ["--skip_dynamic_initialization", "--threaded_lib"]
+    }
+}

+ 67 - 0
CMSIS/NN/Tests/UnitTest/README.md

@@ -0,0 +1,67 @@
+# Unit tests for CMSIS-NN
+Unit test CMSIS-NN functions on any Mbed supported HW.
+
+Mbed are used for building and flashing.
+The Unity test framework is used for running the actual unit tests.
+
+## Requirements
+
+Python3 is required.
+It has been tested with Python 3.6 and it has been tested on Ubuntu 16 and 18.
+
+There is a requirement file that can be used to install the dependencies.
+
+```
+    ``` pip3 install -r requirements.txt```
+
+```
+
+Note that the exact versions are not required, and there are not a lot of packages to install manually.
+The file contains a lot of packages but that is because those are installed when installing some of the other packages.
+To manually install packages, see below.
+
+### Executing unit tests
+
+For executing unit tests, the python3 package pyserial is required. Version 3.4 of pyserial has been tested ok.
+
+```
+    ``` pip3 install pyserial```
+
+```
+
+Other required python packages are mbed-cli and and mbed-ls. It should not matter if those are installed under python2 or python3 as they are command-line tools. These packages have been tested for Python2, with the following versions: mbed-ls(1.7.9) and mbed-cli(1.10.1).
+
+### Generating new test data
+
+For generating new data, the python3 packages tensorflow, numpy and packaging are required. Tensorflow version 2 is required as a minimum.
+
+## Getting started
+Connect any HW (e.g. NUCLEO_F746ZG) that is supported by mbed. Multiple boards are supported. If all requirements are satisfied you can just run:
+
+```
+    ```./unittest_targets.py```
+
+```
+
+Use the -h flag to get more info.
+
+## Generating new test data
+Generating new test data is done with the following script. Use the -h flag to get more info.
+
+```
+    ```./generate_test_data.py -h```
+
+```
+
+The script use a concept of test data sets, i.e. it need a test set data name as input. It will then generate files with that name as prefix. Multiple header files of different test sets can then be included in the actual unit test files.
+
+## Overview of the Folders
+
+- `Output` - This will be created when building.
+- `Profiles` - These are the Mbed settings that are used.
+- `PregeneratedData` - These are tests sets of data that have been previously been generated and are used in the unit tests.
+- `TestCases` - Here are the actual unit tests. For each function under test there is a folder under here.
+- `TestCases/<cmsis-nn function name>` - For each function under test there is a folder with the same name with test_ prepended to the name and it contains a c-file with the actual unit tests. For example for arm_convolve_s8() the file is called test_arm_convolve_s8.c
+- `TestCases/<cmsis-nn function name>/Unity` - This folder contains a Unity file that calls the actual unit tests. For example for arm_convolve_s8() the file is called unity_test_arm_convolve_s8.c.
+- `TestCases/<cmsis-nn function name>/Unity/TestRunner` - This folder will contain the autogenerated Unity test runner.
+- `TestCases/TestData` - This is auto generated test data that the unit tests are using. It is the same data as in the PregenrateData folder but in actual C header format. The advantage of having the same data in two places, is that the data can be easily regenerated (randomized) with the same config. All data can regenerated or only parts of it (e.g. only bias data). Of course even the config can be regenerated. This might be useful during debugging.

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/biases_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t basic_biases[1] =
+{
+  0
+};

+ 40 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/config_data.h

@@ -0,0 +1,40 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#define BASIC_OUT_CH 1
+#define BASIC_IN_CH 1
+#define BASIC_CONV_W 5
+#define BASIC_CONV_H 8
+#define BASIC_FILTER_X 2
+#define BASIC_FILTER_Y 4
+#define BASIC_STRIDE_X 1
+#define BASIC_STRIDE_Y 1
+#define BASIC_PAD_X 0
+#define BASIC_PAD_Y 0
+#define BASIC_OUT_CONV_W 4
+#define BASIC_OUT_CONV_H 5
+#define BASIC_DST_SIZE 20
+#define BASIC_INPUT_SIZE 40
+#define BASIC_INPUT_OFFSET 0
+#define BASIC_OUTPUT_OFFSET 0
+#define BASIC_OUT_ACTIVATION_MIN -128
+#define BASIC_OUT_ACTIVATION_MAX 127
+#define BASIC_INPUT_BATCHES 1

+ 66 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/input_data.h

@@ -0,0 +1,66 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t basic_input[40] =
+{
+  -8,
+  8,
+  6,
+  -2,
+  0,
+  -12,
+  -8,
+  6,
+  -14,
+  -4,
+  4,
+  6,
+  -6,
+  -14,
+  -6,
+  -6,
+  8,
+  -6,
+  -6,
+  6,
+  -8,
+  -12,
+  -14,
+  -12,
+  -6,
+  -10,
+  -6,
+  -10,
+  -4,
+  -4,
+  8,
+  -12,
+  12,
+  0,
+  0,
+  4,
+  2,
+  2,
+  6,
+  -4
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_mult_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t basic_output_mult[1] =
+{
+  1893843847
+};

+ 46 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_ref_data.h

@@ -0,0 +1,46 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t basic_output_ref[20] =
+{
+  -22,
+  2,
+  50,
+  -34,
+  11,
+  38,
+  38,
+  5,
+  -53,
+  38,
+  10,
+  -10,
+  96,
+  -40,
+  73,
+  12,
+  31,
+  48,
+  12,
+  55
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/output_shift_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t basic_output_shift[1] =
+{
+  -5
+};

+ 28 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/test_data.h

@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Generated by generate_test_data.py
+#include "config_data.h"
+#include "output_shift_data.h"
+#include "output_mult_data.h"
+#include "output_ref_data.h"
+#include "biases_data.h"
+#include "weights_data.h"
+#include "input_data.h"

+ 34 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/basic/weights_data.h

@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t basic_weights[8] =
+{
+  -36,
+  -18,
+  36,
+  -127,
+  0,
+  0,
+  109,
+  -109
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/biases_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t kernel1x1_biases[1] =
+{
+  203
+};

+ 40 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/config_data.h

@@ -0,0 +1,40 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#define KERNEL1X1_OUT_CH 1
+#define KERNEL1X1_IN_CH 4
+#define KERNEL1X1_CONV_W 8
+#define KERNEL1X1_CONV_H 8
+#define KERNEL1X1_FILTER_X 1
+#define KERNEL1X1_FILTER_Y 1
+#define KERNEL1X1_STRIDE_X 1
+#define KERNEL1X1_STRIDE_Y 1
+#define KERNEL1X1_PAD_X 0
+#define KERNEL1X1_PAD_Y 0
+#define KERNEL1X1_OUT_CONV_W 8
+#define KERNEL1X1_OUT_CONV_H 8
+#define KERNEL1X1_DST_SIZE 64
+#define KERNEL1X1_INPUT_SIZE 256
+#define KERNEL1X1_INPUT_OFFSET 0
+#define KERNEL1X1_OUTPUT_OFFSET 0
+#define KERNEL1X1_OUT_ACTIVATION_MIN -128
+#define KERNEL1X1_OUT_ACTIVATION_MAX 127
+#define KERNEL1X1_INPUT_BATCHES 1

+ 282 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/input_data.h

@@ -0,0 +1,282 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t kernel1x1_input[256] =
+{
+  0,
+  -2,
+  -10,
+  -12,
+  2,
+  -10,
+  0,
+  10,
+  4,
+  -12,
+  2,
+  -2,
+  12,
+  -4,
+  -2,
+  4,
+  12,
+  10,
+  12,
+  -2,
+  4,
+  -4,
+  8,
+  8,
+  6,
+  -10,
+  -12,
+  6,
+  -8,
+  -8,
+  -12,
+  -6,
+  -12,
+  10,
+  -6,
+  4,
+  0,
+  -4,
+  0,
+  -10,
+  -6,
+  -4,
+  2,
+  8,
+  4,
+  8,
+  -6,
+  -10,
+  8,
+  2,
+  -2,
+  12,
+  -2,
+  8,
+  -14,
+  12,
+  -14,
+  2,
+  -6,
+  -6,
+  -12,
+  6,
+  -12,
+  -2,
+  -8,
+  2,
+  -12,
+  -6,
+  12,
+  6,
+  -6,
+  -2,
+  -10,
+  2,
+  -8,
+  -14,
+  0,
+  -8,
+  -10,
+  4,
+  0,
+  8,
+  -6,
+  -6,
+  2,
+  0,
+  -8,
+  -8,
+  -8,
+  12,
+  -10,
+  -2,
+  -10,
+  -4,
+  2,
+  -10,
+  6,
+  -14,
+  -14,
+  8,
+  -12,
+  -14,
+  8,
+  4,
+  0,
+  -12,
+  -14,
+  8,
+  -8,
+  0,
+  12,
+  10,
+  8,
+  -2,
+  -4,
+  8,
+  -4,
+  -12,
+  -6,
+  4,
+  10,
+  -10,
+  2,
+  -14,
+  -2,
+  4,
+  -12,
+  6,
+  -6,
+  -6,
+  -6,
+  10,
+  2,
+  -4,
+  -6,
+  12,
+  2,
+  6,
+  10,
+  -12,
+  -2,
+  -2,
+  4,
+  12,
+  -10,
+  -6,
+  6,
+  -2,
+  -12,
+  -12,
+  -12,
+  8,
+  10,
+  0,
+  -6,
+  0,
+  2,
+  12,
+  -8,
+  -2,
+  -10,
+  -2,
+  -4,
+  10,
+  -10,
+  -14,
+  6,
+  -12,
+  10,
+  2,
+  6,
+  -14,
+  8,
+  10,
+  6,
+  2,
+  4,
+  0,
+  -10,
+  8,
+  -2,
+  12,
+  -10,
+  -2,
+  -14,
+  -8,
+  8,
+  8,
+  6,
+  4,
+  8,
+  12,
+  10,
+  12,
+  -12,
+  10,
+  -14,
+  0,
+  0,
+  -12,
+  -10,
+  8,
+  12,
+  6,
+  2,
+  2,
+  4,
+  -4,
+  6,
+  -2,
+  -6,
+  6,
+  4,
+  0,
+  -8,
+  -2,
+  -4,
+  -8,
+  12,
+  10,
+  12,
+  -14,
+  -8,
+  -4,
+  10,
+  8,
+  4,
+  -14,
+  12,
+  -14,
+  2,
+  -6,
+  4,
+  4,
+  -8,
+  12,
+  10,
+  6,
+  -6,
+  4,
+  8,
+  0,
+  -12,
+  4,
+  -2,
+  8,
+  -10,
+  -2,
+  8,
+  10,
+  -6,
+  -2,
+  -4,
+  4,
+  2,
+  2
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_mult_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t kernel1x1_output_mult[1] =
+{
+  1352745605
+};

+ 90 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_ref_data.h

@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t kernel1x1_output_ref[64] =
+{
+  -24,
+  43,
+  19,
+  42,
+  13,
+  36,
+  41,
+  -19,
+  -20,
+  -17,
+  16,
+  -21,
+  48,
+  22,
+  -41,
+  -31,
+  -29,
+  17,
+  -53,
+  22,
+  -19,
+  -12,
+  -29,
+  -37,
+  50,
+  4,
+  36,
+  13,
+  42,
+  18,
+  -1,
+  11,
+  23,
+  42,
+  -28,
+  32,
+  -15,
+  12,
+  24,
+  -9,
+  11,
+  -32,
+  -13,
+  15,
+  32,
+  -17,
+  4,
+  42,
+  37,
+  -54,
+  -9,
+  -4,
+  33,
+  7,
+  29,
+  32,
+  -19,
+  27,
+  38,
+  28,
+  30,
+  -13,
+  5,
+  -3
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/output_shift_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t kernel1x1_output_shift[1] =
+{
+  -5
+};

+ 28 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/test_data.h

@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Generated by generate_test_data.py
+#include "config_data.h"
+#include "output_shift_data.h"
+#include "output_mult_data.h"
+#include "output_ref_data.h"
+#include "biases_data.h"
+#include "weights_data.h"
+#include "input_data.h"

+ 30 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/kernel1x1/weights_data.h

@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t kernel1x1_weights[4] =
+{
+  102,
+  -51,
+  0,
+  127
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/biases_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t stride2pad1_biases[1] =
+{
+  73
+};

+ 40 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/config_data.h

@@ -0,0 +1,40 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#define STRIDE2PAD1_OUT_CH 1
+#define STRIDE2PAD1_IN_CH 1
+#define STRIDE2PAD1_CONV_W 7
+#define STRIDE2PAD1_CONV_H 7
+#define STRIDE2PAD1_FILTER_X 3
+#define STRIDE2PAD1_FILTER_Y 3
+#define STRIDE2PAD1_STRIDE_X 2
+#define STRIDE2PAD1_STRIDE_Y 2
+#define STRIDE2PAD1_PAD_X 1
+#define STRIDE2PAD1_PAD_Y 1
+#define STRIDE2PAD1_OUT_CONV_W 4
+#define STRIDE2PAD1_OUT_CONV_H 4
+#define STRIDE2PAD1_DST_SIZE 16
+#define STRIDE2PAD1_INPUT_SIZE 49
+#define STRIDE2PAD1_INPUT_OFFSET 0
+#define STRIDE2PAD1_OUTPUT_OFFSET 0
+#define STRIDE2PAD1_OUT_ACTIVATION_MIN -128
+#define STRIDE2PAD1_OUT_ACTIVATION_MAX 127
+#define STRIDE2PAD1_INPUT_BATCHES 1

+ 75 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/input_data.h

@@ -0,0 +1,75 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t stride2pad1_input[49] =
+{
+  -14,
+  -12,
+  12,
+  -8,
+  -14,
+  12,
+  10,
+  0,
+  -4,
+  -2,
+  0,
+  -2,
+  -6,
+  0,
+  -14,
+  6,
+  -10,
+  8,
+  -4,
+  0,
+  -8,
+  -8,
+  -14,
+  -12,
+  4,
+  -12,
+  12,
+  12,
+  -10,
+  12,
+  -2,
+  2,
+  -10,
+  0,
+  -2,
+  2,
+  12,
+  -10,
+  0,
+  0,
+  -12,
+  10,
+  10,
+  -2,
+  6,
+  -12,
+  -8,
+  -10,
+  10
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_mult_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t stride2pad1_output_mult[1] =
+{
+  1893843847
+};

+ 42 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_ref_data.h

@@ -0,0 +1,42 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t stride2pad1_output_ref[16] =
+{
+  3,
+  73,
+  -66,
+  48,
+  -37,
+  27,
+  4,
+  -75,
+  -35,
+  -1,
+  -1,
+  -12,
+  22,
+  72,
+  18,
+  8
+};

+ 27 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/output_shift_data.h

@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const int32_t stride2pad1_output_shift[1] =
+{
+  -5
+};

+ 28 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/test_data.h

@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Generated by generate_test_data.py
+#include "config_data.h"
+#include "output_shift_data.h"
+#include "output_mult_data.h"
+#include "output_ref_data.h"
+#include "biases_data.h"
+#include "weights_data.h"
+#include "input_data.h"

+ 35 - 0
CMSIS/NN/Tests/UnitTest/TestCases/TestData/stride2pad1/weights_data.h

@@ -0,0 +1,35 @@
+
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+// Generated by generate_test_data.py
+#include <stdint.h>
+
+const q7_t stride2pad1_weights[9] =
+{
+  -18,
+  -91,
+  -18,
+  0,
+  91,
+  -109,
+  -127,
+  -54,
+  0
+};

+ 51 - 0
CMSIS/NN/Tests/UnitTest/TestCases/Utils/validate.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+inline int validate(int8_t *act, const int8_t *ref, int size)
+{
+    int test_passed = true;
+    int count = 0;
+    int total = 0;
+
+    for(int i = 0; i < size; ++i)
+    {
+      total++;
+      if(act[i] != ref[i])
+      {
+        count++;
+        printf("ERROR at pos %d: Act: %d Ref: %d\r\n", i, act[i], ref[i]);
+        test_passed = false;
+      }
+      else
+      {
+        //printf("PASS at pos %d: %d\r\n", i, act[i]);
+      }
+    }
+
+    if (!test_passed)
+    {
+      printf("%d of %d failed\r\n", count, total);
+    }
+
+    return test_passed;
+}

+ 47 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_1x1_s8_fast/Unity/unity_test_arm_convolve_1x1_s8_fast.c

@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "unity.h"
+#include "../test_arm_convolve_1x1_s8_fast.c"
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void setUp(void)
+{
+  /* This is run before EACH TEST */
+}
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void tearDown(void)
+{
+
+}
+
+void test_kernel1x1_arm_convolve_1x1_s8_fast(void)
+{
+  kernel1x1_arm_convolve_1x1_s8_fast();
+}

+ 59 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_1x1_s8_fast/test_arm_convolve_1x1_s8_fast.c

@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arm_nnfunctions.h>
+#include <stdlib.h>
+
+#include "../Utils/validate.h"
+#include "../TestData/kernel1x1/test_data.h"
+
+void kernel1x1_arm_convolve_1x1_s8_fast(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[KERNEL1X1_DST_SIZE] = {0};
+  const int32_t buf_size = arm_convolve_1x1_s8_fast_get_buffer_size(KERNEL1X1_IN_CH);
+  q15_t *bufferA = (q15_t*)malloc(buf_size);
+
+  arm_status result =  arm_convolve_1x1_s8_fast(kernel1x1_input,
+                                                KERNEL1X1_CONV_W,
+                                                KERNEL1X1_CONV_H,
+                                                KERNEL1X1_IN_CH,
+                                                KERNEL1X1_INPUT_BATCHES,
+                                                kernel1x1_weights,
+                                                KERNEL1X1_OUT_CH,
+                                                KERNEL1X1_PAD_X,
+                                                KERNEL1X1_PAD_Y,
+                                                KERNEL1X1_STRIDE_X,
+                                                KERNEL1X1_STRIDE_Y,
+                                                kernel1x1_biases,
+                                                output,
+                                                kernel1x1_output_shift,
+                                                kernel1x1_output_mult,
+                                                KERNEL1X1_OUTPUT_OFFSET,
+                                                KERNEL1X1_INPUT_OFFSET,
+                                                KERNEL1X1_OUT_ACTIVATION_MIN,
+                                                KERNEL1X1_OUT_ACTIVATION_MAX,
+                                                KERNEL1X1_OUT_CONV_W,
+                                                KERNEL1X1_OUT_CONV_H,
+                                                bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, kernel1x1_output_ref, KERNEL1X1_DST_SIZE));
+
+  free(bufferA);
+}

+ 52 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_s8/Unity/unity_test_arm_convolve_s8.c

@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "unity.h"
+#include "../test_arm_convolve_s8.c"
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void setUp(void)
+{
+  /* This is run before EACH TEST */
+}
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void tearDown(void)
+{
+
+}
+
+void test_basic_arm_convolve_s8(void)
+{
+  basic_arm_convolve_s8();
+}
+
+void test_stride2pad1_arm_convolve_s8(void)
+{
+  stride2pad1_arm_convolve_s8();
+}

+ 106 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_convolve_s8/test_arm_convolve_s8.c

@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arm_nnfunctions.h>
+#include <stdlib.h>
+
+#include "../Utils/validate.h"
+#include "../TestData/basic/test_data.h"
+#include "../TestData/stride2pad1/test_data.h"
+
+
+void basic_arm_convolve_s8(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[BASIC_DST_SIZE] = {0};
+
+  const int32_t buf_size = arm_convolve_s8_get_buffer_size(BASIC_IN_CH, BASIC_FILTER_X, BASIC_FILTER_Y);
+  q15_t *bufferA = (q15_t*)malloc(buf_size);
+
+  arm_status result = arm_convolve_s8(basic_input,
+                                      BASIC_CONV_W,
+                                      BASIC_CONV_H,
+                                      BASIC_IN_CH,
+                                      BASIC_INPUT_BATCHES,
+                                      basic_weights,
+                                      BASIC_OUT_CH,
+                                      BASIC_FILTER_X,
+                                      BASIC_FILTER_Y,
+                                      BASIC_PAD_X,
+                                      BASIC_PAD_Y,
+                                      BASIC_STRIDE_X,
+                                      BASIC_STRIDE_Y,
+                                      basic_biases,
+                                      output,
+                                      basic_output_shift,
+                                      basic_output_mult,
+                                      BASIC_OUTPUT_OFFSET,
+                                      BASIC_INPUT_OFFSET,
+                                      BASIC_OUT_ACTIVATION_MIN,
+                                      BASIC_OUT_ACTIVATION_MAX,
+                                      BASIC_OUT_CONV_W,
+                                      BASIC_OUT_CONV_H,
+                                      bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, basic_output_ref, BASIC_DST_SIZE));
+
+  free(bufferA);
+}
+
+
+void stride2pad1_arm_convolve_s8(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[STRIDE2PAD1_DST_SIZE] = {0};
+
+  const int32_t buf_size = arm_convolve_s8_get_buffer_size(STRIDE2PAD1_IN_CH,
+                                                           STRIDE2PAD1_FILTER_X,
+                                                           STRIDE2PAD1_FILTER_Y);
+  q15_t *bufferA = (q15_t*)malloc(buf_size);
+
+  arm_status result = arm_convolve_s8(stride2pad1_input,
+                                      STRIDE2PAD1_CONV_W,
+                                      STRIDE2PAD1_CONV_H,
+                                      STRIDE2PAD1_IN_CH,
+                                      STRIDE2PAD1_INPUT_BATCHES,
+                                      stride2pad1_weights,
+                                      STRIDE2PAD1_OUT_CH,
+                                      STRIDE2PAD1_FILTER_X,
+                                      STRIDE2PAD1_FILTER_Y,
+                                      STRIDE2PAD1_PAD_X,
+                                      STRIDE2PAD1_PAD_Y,
+                                      STRIDE2PAD1_STRIDE_X,
+                                      STRIDE2PAD1_STRIDE_Y,
+                                      stride2pad1_biases,
+                                      output,
+                                      stride2pad1_output_shift,
+                                      stride2pad1_output_mult,
+                                      STRIDE2PAD1_OUTPUT_OFFSET,
+                                      STRIDE2PAD1_INPUT_OFFSET,
+                                      STRIDE2PAD1_OUT_ACTIVATION_MIN,
+                                      STRIDE2PAD1_OUT_ACTIVATION_MAX,
+                                      STRIDE2PAD1_OUT_CONV_W,
+                                      STRIDE2PAD1_OUT_CONV_H,
+                                      bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, stride2pad1_output_ref, STRIDE2PAD1_DST_SIZE));
+
+  free(bufferA);
+}

+ 84 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/TestRunner/test_arm_depthwise_conv_s8_runner.c

@@ -0,0 +1,84 @@
+/* AUTOGENERATED FILE. DO NOT EDIT. */
+
+/*=======Automagically Detected Files To Include=====*/
+#include "unity.h"
+#include "Utils/validate.h"
+#include "basic/test_data.h"
+#include "stride2pad1/test_data.h"
+#include <arm_nnfunctions.h>
+
+/*=======External Functions This Runner Calls=====*/
+extern void setUp(void);
+extern void tearDown(void);
+
+
+/*=======Mock Management=====*/
+static void CMock_Init(void)
+{
+}
+static void CMock_Verify(void)
+{
+}
+static void CMock_Destroy(void)
+{
+}
+
+/*=======Setup (stub)=====*/
+void setUp(void) {}
+
+/*=======Teardown (stub)=====*/
+void tearDown(void) {}
+
+/*=======Test Reset Options=====*/
+void resetTest(void);
+void resetTest(void)
+{
+  tearDown();
+  CMock_Verify();
+  CMock_Destroy();
+  CMock_Init();
+  setUp();
+}
+void verifyTest(void);
+void verifyTest(void)
+{
+  CMock_Verify();
+}
+/*=======Test Runner Used To Run Each Test=====*/
+static void run_test(UnityTestFunction func, const char* name, int line_num)
+{
+    Unity.CurrentTestName = name;
+    Unity.CurrentTestLineNumber = line_num;
+#ifdef UNITY_USE_COMMAND_LINE_ARGS
+    if (!UnityTestMatches())
+        return;
+#endif
+    Unity.NumberOfTests++;
+    UNITY_CLR_DETAILS();
+    UNITY_EXEC_TIME_START();
+    CMock_Init();
+    if (TEST_PROTECT())
+    {
+
+            setUp();
+            func();
+
+    }
+    if (TEST_PROTECT())
+    {
+        tearDown();
+        CMock_Verify();
+    }
+    CMock_Destroy();
+    UNITY_EXEC_TIME_STOP();
+    UnityConcludeTest();
+}
+
+
+/*=======MAIN=====*/
+int main(void)
+{
+  UnityBegin("TestCases/test_arm_depthwise_conv_s8/test_arm_depthwise_conv_s8.c");
+
+  return UnityEnd();
+}

+ 52 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/Unity/unity_test_arm_depthwwise_conv_s8.c

@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "unity.h"
+#include "../test_arm_depthwise_conv_s8.c"
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void setUp(void)
+{
+  /* This is run before EACH TEST */
+}
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void tearDown(void)
+{
+
+}
+
+void test_basic_arm_depthwise_conv_s8(void)
+{
+  basic_arm_depthwise_conv_s8();
+}
+
+void test_stride2pad1_arm_depthwise_conv_s8(void)
+{
+  stride2pad1_arm_depthwise_conv_s8();
+}

+ 104 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/test_arm_depthwise_conv_s8.c

@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arm_nnfunctions.h>
+
+#include "../Utils/validate.h"
+#include "../TestData/basic/test_data.h"
+#include "../TestData/stride2pad1/test_data.h"
+
+
+// Not used
+static const uint16_t dilation = 1;
+static q15_t *bufferA = NULL;
+
+void basic_arm_depthwise_conv_s8(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[BASIC_DST_SIZE] = {0};
+
+  const uint16_t ch_mult =1;
+
+  arm_status result = arm_depthwise_conv_s8(basic_input,
+                                            BASIC_CONV_W,
+                                            BASIC_CONV_H,
+                                            BASIC_IN_CH,
+                                            basic_weights,
+                                            BASIC_OUT_CH,
+                                            ch_mult,
+                                            BASIC_FILTER_X,
+                                            BASIC_FILTER_Y,
+                                            BASIC_PAD_X,
+                                            BASIC_PAD_Y,
+                                            BASIC_STRIDE_X,
+                                            BASIC_STRIDE_Y,
+                                            basic_biases,
+                                            output,
+                                            basic_output_shift,
+                                            basic_output_mult,
+                                            BASIC_OUT_CONV_W,
+                                            BASIC_OUT_CONV_H,
+                                            BASIC_OUTPUT_OFFSET,
+                                            BASIC_INPUT_OFFSET,
+                                            BASIC_OUT_ACTIVATION_MIN,
+                                            BASIC_OUT_ACTIVATION_MAX,
+                                            dilation,
+                                            dilation,
+                                            bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, basic_output_ref, BASIC_DST_SIZE));
+}
+
+void stride2pad1_arm_depthwise_conv_s8(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[STRIDE2PAD1_DST_SIZE] = {0};
+
+  const uint16_t ch_mult =1;
+
+  arm_status result = arm_depthwise_conv_s8(stride2pad1_input,
+                                            STRIDE2PAD1_CONV_W,
+                                            STRIDE2PAD1_CONV_H,
+                                            STRIDE2PAD1_IN_CH,
+                                            stride2pad1_weights,
+                                            STRIDE2PAD1_OUT_CH,
+                                            ch_mult,
+                                            STRIDE2PAD1_FILTER_X,
+                                            STRIDE2PAD1_FILTER_Y,
+                                            STRIDE2PAD1_PAD_X,
+                                            STRIDE2PAD1_PAD_Y,
+                                            STRIDE2PAD1_STRIDE_X,
+                                            STRIDE2PAD1_STRIDE_Y,
+                                            stride2pad1_biases,
+                                            output,
+                                            stride2pad1_output_shift,
+                                            stride2pad1_output_mult,
+                                            STRIDE2PAD1_OUT_CONV_W,
+                                            STRIDE2PAD1_OUT_CONV_H,
+                                            STRIDE2PAD1_OUTPUT_OFFSET,
+                                            STRIDE2PAD1_INPUT_OFFSET,
+                                            STRIDE2PAD1_OUT_ACTIVATION_MIN,
+                                            STRIDE2PAD1_OUT_ACTIVATION_MAX,
+                                            dilation,
+                                            dilation,
+                                            bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, stride2pad1_output_ref, STRIDE2PAD1_DST_SIZE));
+}

+ 85 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/TestRunner/test_arm_depthwise_conv_s8_opt_runner.c

@@ -0,0 +1,85 @@
+/* AUTOGENERATED FILE. DO NOT EDIT. */
+
+/*=======Automagically Detected Files To Include=====*/
+#include "unity.h"
+#include "Utils/validate.h"
+#include "basic/test_data.h"
+#include "stride2pad1/test_data.h"
+#include <arm_nnfunctions.h>
+#include <stdlib.h>
+
+/*=======External Functions This Runner Calls=====*/
+extern void setUp(void);
+extern void tearDown(void);
+
+
+/*=======Mock Management=====*/
+static void CMock_Init(void)
+{
+}
+static void CMock_Verify(void)
+{
+}
+static void CMock_Destroy(void)
+{
+}
+
+/*=======Setup (stub)=====*/
+void setUp(void) {}
+
+/*=======Teardown (stub)=====*/
+void tearDown(void) {}
+
+/*=======Test Reset Options=====*/
+void resetTest(void);
+void resetTest(void)
+{
+  tearDown();
+  CMock_Verify();
+  CMock_Destroy();
+  CMock_Init();
+  setUp();
+}
+void verifyTest(void);
+void verifyTest(void)
+{
+  CMock_Verify();
+}
+/*=======Test Runner Used To Run Each Test=====*/
+static void run_test(UnityTestFunction func, const char* name, int line_num)
+{
+    Unity.CurrentTestName = name;
+    Unity.CurrentTestLineNumber = line_num;
+#ifdef UNITY_USE_COMMAND_LINE_ARGS
+    if (!UnityTestMatches())
+        return;
+#endif
+    Unity.NumberOfTests++;
+    UNITY_CLR_DETAILS();
+    UNITY_EXEC_TIME_START();
+    CMock_Init();
+    if (TEST_PROTECT())
+    {
+
+            setUp();
+            func();
+
+    }
+    if (TEST_PROTECT())
+    {
+        tearDown();
+        CMock_Verify();
+    }
+    CMock_Destroy();
+    UNITY_EXEC_TIME_STOP();
+    UnityConcludeTest();
+}
+
+
+/*=======MAIN=====*/
+int main(void)
+{
+  UnityBegin("TestCases/test_arm_depthwise_conv_s8_opt/test_arm_depthwise_conv_s8_opt.c");
+
+  return UnityEnd();
+}

+ 52 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/Unity/unity_test_arm_depthwise_conv_s8_opt.c

@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "unity.h"
+#include "../test_arm_depthwise_conv_s8_opt.c"
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void setUp(void)
+{
+  /* This is run before EACH TEST */
+}
+
+/* This function is called from the autogenerated file.
+ * The name must be exactly like this
+ */
+void tearDown(void)
+{
+
+}
+
+void test_basic_arm_depthwise_conv_s8_opt(void)
+{
+  basic_arm_depthwise_conv_s8_opt();
+}
+
+void test_stride2pad1_arm_depthwise_conv_s8_opt(void)
+{
+  stride2pad1_arm_depthwise_conv_s8_opt();
+}

+ 111 - 0
CMSIS/NN/Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8_opt/test_arm_depthwise_conv_s8_opt.c

@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arm_nnfunctions.h>
+#include <stdlib.h>
+
+#include "../Utils/validate.h"
+#include "../TestData/basic/test_data.h"
+#include "../TestData/stride2pad1/test_data.h"
+
+
+void basic_arm_depthwise_conv_s8_opt(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[BASIC_DST_SIZE] = {0};
+
+  const int32_t buf_size = arm_depthwise_conv_s8_opt_get_buffer_size(BASIC_IN_CH, BASIC_FILTER_X, BASIC_FILTER_Y);
+  q15_t *bufferA = (q15_t*)malloc(buf_size);
+
+  // Not used
+  const uint16_t dilation = 1;
+
+  arm_status result = arm_depthwise_conv_s8_opt(basic_input,
+                                                BASIC_CONV_W,
+                                                BASIC_CONV_H,
+                                                BASIC_IN_CH,
+                                                basic_weights,
+                                                BASIC_OUT_CH,
+                                                BASIC_FILTER_X,
+                                                BASIC_FILTER_Y,
+                                                BASIC_PAD_X,
+                                                BASIC_PAD_Y,
+                                                BASIC_STRIDE_X,
+                                                BASIC_STRIDE_Y,
+                                                basic_biases,
+                                                output,
+                                                basic_output_shift,
+                                                basic_output_mult,
+                                                BASIC_OUT_CONV_W,
+                                                BASIC_OUT_CONV_H,
+                                                BASIC_OUTPUT_OFFSET,
+                                                BASIC_INPUT_OFFSET,
+                                                BASIC_OUT_ACTIVATION_MIN,
+                                                BASIC_OUT_ACTIVATION_MAX,
+                                                dilation,
+                                                dilation,
+                                                bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, basic_output_ref, BASIC_DST_SIZE));
+
+  free(bufferA);
+}
+
+void stride2pad1_arm_depthwise_conv_s8_opt(void)
+{
+  arm_status expected = ARM_MATH_SUCCESS;
+  q7_t output[STRIDE2PAD1_DST_SIZE] = {0};
+
+  const int32_t buf_size = arm_depthwise_conv_s8_opt_get_buffer_size(BASIC_IN_CH, BASIC_FILTER_X, BASIC_FILTER_Y);
+  q15_t *bufferA = (q15_t*)malloc(buf_size);
+
+  // Not used
+  const uint16_t dilation = 1;
+
+  arm_status result = arm_depthwise_conv_s8_opt(stride2pad1_input,
+                                                STRIDE2PAD1_CONV_W,
+                                                STRIDE2PAD1_CONV_H,
+                                                STRIDE2PAD1_IN_CH,
+                                                stride2pad1_weights,
+                                                STRIDE2PAD1_OUT_CH,
+                                                STRIDE2PAD1_FILTER_X,
+                                                STRIDE2PAD1_FILTER_Y,
+                                                STRIDE2PAD1_PAD_X,
+                                                STRIDE2PAD1_PAD_Y,
+                                                STRIDE2PAD1_STRIDE_X,
+                                                STRIDE2PAD1_STRIDE_Y,
+                                                stride2pad1_biases,
+                                                output,
+                                                stride2pad1_output_shift,
+                                                stride2pad1_output_mult,
+                                                STRIDE2PAD1_OUT_CONV_W,
+                                                STRIDE2PAD1_OUT_CONV_H,
+                                                STRIDE2PAD1_OUTPUT_OFFSET,
+                                                STRIDE2PAD1_INPUT_OFFSET,
+                                                STRIDE2PAD1_OUT_ACTIVATION_MIN,
+                                                STRIDE2PAD1_OUT_ACTIVATION_MAX,
+                                                dilation,
+                                                dilation,
+                                                bufferA);
+
+  TEST_ASSERT_EQUAL(expected, result);
+  TEST_ASSERT_TRUE(validate(output, stride2pad1_output_ref, STRIDE2PAD1_DST_SIZE));
+
+  free(bufferA);
+}

+ 461 - 0
CMSIS/NN/Tests/UnitTest/generate_test_data.py

@@ -0,0 +1,461 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os
+import sys
+import argparse
+import math
+import numpy as np
+import warnings as w
+
+from abc import ABC, abstractmethod
+from packaging import version
+
+w.filterwarnings('ignore', category=FutureWarning)
+try:
+    import tensorflow as tf
+except Exception as e:
+    sys.exit(e)
+
+REQUIRED_MINIMUM_TENSORFLOW_VERSION = version.parse("2.0.0b0")
+DEFAULT_TESTDATA_SET = 'basic'
+LICENSE = """
+/*
+ * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+"""
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(description="Generate input and refererence output data for unittests."
+                                     "It can regenerate all or load all data/input or only parts of it, "
+                                     "which may be useful when debugging.")
+    parser.add_argument('--dataset', type=str, default=DEFAULT_TESTDATA_SET, help="Name of generated test set")
+    parser.add_argument('--regenerate-weights', action='store_true', help="Regenerate and store new weights")
+    parser.add_argument('--regenerate-input', action='store_true', help="Regenerate and store new input")
+    parser.add_argument('--regenerate-biases', action='store_true', help="Regenerate and store new biases")
+    parser.add_argument('-a', '--regenerate-all', action='store_true', help="Regenerate and store all data")
+    parser.add_argument('-t', '--type', type=str, default='conv', choices=['conv', 'pooling'], help='Type of test.')
+
+    args = parser.parse_args()
+    return args
+
+
+class TestSettings(ABC):
+
+    OUTDIR = 'TestCases/TestData/'
+    PREGEN = 'PregeneratedData/'
+
+    INT_MAX = 32767
+    INT_MIN = -32767
+
+    def __init__(self, args, randmin, randmax, in_ch, out_ch, x_in, y_in, w_x, w_y, stride_x, stride_y, batches, pad,
+                 input_scale, output_scale, in_zero_point, out_zero_point):
+
+        self.minrange = -128
+        self.maxrange = 127
+
+        # Randomization interval
+        self.mins = randmin
+        self.maxs = randmax
+
+        self.input_ch = in_ch
+        self.output_ch = out_ch
+        self.x_input = x_in
+        self.y_input = y_in
+        self.filter_x = w_x
+        self.filter_y = w_y
+        self.stride_x = stride_x
+        self.stride_y = stride_y
+        self.batches = batches
+
+        self.has_padding = pad
+        self.padding = 'VALID'
+        self.pad_x = 0
+        self.pad_y = 0
+        self.x_output = 0
+        self.y_output = 0
+
+        self.scaling_factors = []
+
+        self.input_scale = input_scale
+        self.output_scale = output_scale
+        self.input_zero_point = in_zero_point
+        self.output_zero_point = out_zero_point
+
+        self.generated_header_files = []
+        self.pregenerated_data_dir = self.PREGEN
+        self.testdataset = DEFAULT_TESTDATA_SET
+
+        self.testdataset = args.dataset
+        self.kernel_table_file = self.pregenerated_data_dir + self.testdataset + '/' + 'kernel.txt'
+        self.inputs_table_file = self.pregenerated_data_dir + self.testdataset + '/' + 'input.txt'
+        self.bias_table_file = self.pregenerated_data_dir + self.testdataset + '/' + 'bias.txt'
+        self.parameters_file = self.pregenerated_data_dir + self.testdataset + '/' + 'params.txt'
+
+        self.regenerate_new_weights = args.regenerate_weights
+        self.regenerate_new_input = args.regenerate_input
+        self.regenerate_new_bias = args.regenerate_biases
+        if not os.path.exists(self.parameters_file) or args.regenerate_all:
+            self.regenerate_new_bias = True
+            self.regenerate_new_weights = True
+            self.regenerate_new_input = True
+            self.save_parameters()
+        else:
+            self.load_parameters()
+
+        self.headers_dir = self.OUTDIR + self.testdataset + '/'
+
+        self.set_padding_and_output_width_heigth()
+
+    def save_multiple_dim_array_in_txt(self, file, data):
+        header = ','.join(map(str, data.shape))
+        np.savetxt(file, data.reshape(-1, data.shape[-1]), header=header,
+                   delimiter=',')
+
+    def load_multiple_dim_array_from_txt(self, file):
+        with open(file) as f:
+            shape = list(map(int, next(f)[1:].split(',')))
+            data = np.genfromtxt(f, delimiter=',').reshape(shape)
+        return data.astype(np.float32)
+
+    def save_parameters(self):
+        regendir = os.path.dirname(self.parameters_file)
+        if not os.path.exists(regendir):
+            os.makedirs(regendir)
+        params = np.array([self.input_ch, self.output_ch, self.x_input, self.y_input, self.filter_x, self.filter_y,
+                           self.stride_x, self.stride_y, self.pad_x, self.pad_y, self.batches, self.has_padding])
+        np.savetxt(self.parameters_file, params, fmt='%i')
+
+    def load_parameters(self):
+        params = np.loadtxt(self.parameters_file).astype(int)
+        (self.input_ch, self.output_ch, self.x_input, self.y_input, self.filter_x, self.filter_y,
+         self.stride_x, self.stride_y, self.pad_x, self.pad_y, self.batches, self.has_padding) = \
+            (map(lambda x: x, params))
+
+    def convert_tensor_np(self, tensor_in, converter):
+        w = tensor_in.numpy()
+        shape = w.shape
+        w = w.ravel()
+        fw = converter(w)
+        fw.shape = shape
+        return tf.convert_to_tensor(fw)
+
+    def convert_tensor(self, tensor_in, converter):
+        w = tensor_in.numpy()
+        shape = w.shape
+        w = w.ravel()
+        normal = np.array(w)
+        float_normal = []
+
+        for i in normal:
+            float_normal.append(converter(i))
+
+        np_float_array = np.asarray(float_normal)
+        np_float_array.shape = shape
+
+        return tf.convert_to_tensor(np_float_array)
+
+    def get_data(self, dims, npfile, regenerate):
+        if not os.path.exists(npfile) or regenerate:
+            regendir = os.path.dirname(npfile)
+            if not os.path.exists(regendir):
+                os.makedirs(regendir)
+            data = tf.Variable(tf.random.uniform(dims, minval=self.mins, maxval=self.maxs, dtype=tf.dtypes.int32))
+            data = tf.cast(data, dtype=tf.float32)
+            print("Saving data to {}".format(npfile))
+            self.save_multiple_dim_array_in_txt(npfile, data.numpy())
+        else:
+            print("Loading data from {}".format(npfile))
+            data = tf.convert_to_tensor(self.load_multiple_dim_array_from_txt(npfile))
+        return data
+
+    def write_c_header_wrapper(self):
+        filename = "test_data.h"
+        filepath = self.headers_dir + filename
+
+        print("Generating C header wrapper {}...".format(filepath))
+        with open(filepath, 'w+') as f:
+            f.write("{}\n\n".format(LICENSE))
+            f.write("// Generated by {}\n".format(os.path.basename(__file__)))
+            while len(self.generated_header_files) > 0:
+                f.write('#include "{}"\n'.format(self.generated_header_files.pop()))
+
+    def write_c_config_header(self):
+        filename = "config_data.h"
+
+        self.generated_header_files.append(filename)
+        filepath = self.headers_dir + filename
+
+        prefix = self.testdataset.upper()
+
+        print("Writing C header with config data {}...".format(filepath))
+        with open(filepath, "w+") as f:
+            f.write("{}\n".format(LICENSE))
+            f.write("#pragma once\n")
+            f.write("// Generated by {}\n".format(os.path.basename(__file__)))
+            f.write("#define {}_OUT_CH {}\n".format(prefix, self.output_ch))
+            f.write("#define {}_IN_CH {}\n".format(prefix, self.input_ch))
+            f.write("#define {}_CONV_W {}\n".format(prefix, self.x_input))
+            f.write("#define {}_CONV_H {}\n".format(prefix, self.y_input))
+            f.write("#define {}_FILTER_X {}\n".format(prefix, self.filter_x))
+            f.write("#define {}_FILTER_Y {}\n".format(prefix, self.filter_y))
+            f.write("#define {}_STRIDE_X {}\n".format(prefix, self.stride_x))
+            f.write("#define {}_STRIDE_Y {}\n".format(prefix, self.stride_y))
+            f.write("#define {}_PAD_X {}\n".format(prefix, self.pad_x))
+            f.write("#define {}_PAD_Y {}\n".format(prefix, self.pad_y))
+            f.write("#define {}_OUT_CONV_W {}\n".format(prefix, self.x_output))
+            f.write("#define {}_OUT_CONV_H {}\n".format(prefix, self.y_output))
+            f.write("#define {}_DST_SIZE {}\n".format(prefix, self.x_output * self.y_output * self.output_ch))
+            f.write("#define {}_INPUT_SIZE {}\n".format(prefix, self.x_input * self.y_input * self.input_ch))
+            f.write("#define {}_INPUT_OFFSET {}\n".format(prefix, self.input_zero_point))
+            f.write("#define {}_OUTPUT_OFFSET {}\n".format(prefix, self.output_zero_point))
+            f.write("#define {}_OUT_ACTIVATION_MIN {}\n".format(prefix, self.minrange))
+            f.write("#define {}_OUT_ACTIVATION_MAX {}\n".format(prefix, self.maxrange))
+            f.write("#define {}_INPUT_BATCHES {}\n".format(prefix, self.batches))
+
+    def generate_c_array(self, name, array, datatype="q7_t"):
+        if not os.path.exists(self.headers_dir):
+            os.makedirs(self.headers_dir)
+
+        w = None
+        if type(array) is list:
+            w = array
+            size = len(array)
+        else:
+            w = array.numpy()
+            w = w.ravel()
+            size = tf.size(array)
+        filename = name + "_data.h"
+        filepath = self.headers_dir + filename
+
+        self.generated_header_files.append(filename)
+
+        print("Generating C header {}...".format(filepath))
+
+        with open(filepath, "w+") as f:
+            f.write("{}\n".format(LICENSE))
+            f.write("#pragma once\n")
+            f.write("// Generated by {}\n".format(os.path.basename(__file__)))
+            f.write("#include <stdint.h>\n\n")
+            f.write("const " + datatype + " " + self.testdataset + '_' + name + "[%d] =\n{\n" % size)
+            for i in range(size - 1):
+                f.write("  %d,\n" % w[i])
+            f.write("  %d\n" % w[size - 1])
+            f.write("};\n")
+
+    def set_padding_and_output_width_heigth(self):
+        if self.has_padding:
+            self.padding = 'SAME'
+            self.x_output = math.ceil(float(self.x_input) / float(self.stride_x))
+            self.y_output = math.ceil(float(self.y_input) / float(self.stride_y))
+            pad_along_width = max((self.x_output - 1) * self.stride_x + self.filter_x - self.x_input, 0)
+            pad_along_height = max((self.y_output - 1) * self.stride_y + self.filter_y - self.y_input, 0)
+            pad_top = pad_along_height // 2
+            pad_left = pad_along_width // 2
+            self.pad_x = pad_left
+            self.pad_y = pad_top
+        else:
+            self.padding = 'VALID'
+            self.x_output = math.ceil(float(self.x_input - self.filter_x + 1) / float(self.stride_x))
+            self.y_output = math.ceil(float(self.y_input - self.filter_y + 1) / float(self.stride_y))
+            self.pad_x = 0
+            self.pad_y = 0
+
+    @abstractmethod
+    def generate_data(self, input_data=None, weights=None, biases=None):
+        ''' Must be overriden '''
+
+
+class ConvSettings(TestSettings):
+
+    def __init__(self, args, randmin=-7, randmax=7, in_ch=1, out_ch=1, x_in=7, y_in=7, w_x=3, w_y=3, stride_x=2,
+                 stride_y=2, batches=1, pad=True, input_scale=0.5, output_scale=1.0, in_zero_point=0, out_zero_point=0):
+        super().__init__(args, randmin, randmax, in_ch, out_ch, x_in, y_in, w_x, w_y, stride_x, stride_y, batches, pad,
+                         input_scale, output_scale, in_zero_point, out_zero_point)
+
+    def quantize_bias(self, nparray):
+        num_channels = self.output_ch
+        quantized_values = []
+        values = np.array(nparray)
+
+        def quantize_float_to_int(value, scale):
+            quantized = round(value / scale)
+            if quantized > self.INT_MAX:
+                quantized = self.INT_MAX
+            elif quantized < self.INT_MIN:
+                quantized = self.INT_MIN
+            return quantized
+
+        for x in range(num_channels):
+            quantized_values.append(quantize_float_to_int(values[x], self.scaling_factors[x]*self.input_scale))
+
+        return np.asarray(quantized_values)
+
+    def quantize_input(self, value):
+        result = round(value / self.input_scale) + self.input_zero_point
+        int8_min = self.minrange
+        int8_max = self.maxrange
+        if result < int8_min:
+            result = int8_min
+        elif result > int8_max:
+            result = int8_max
+        return result
+
+    def quantize_filter(self, nparray):
+        quantized_values = []
+        channel_count = self.output_ch
+        input_size = self.filter_y * self.filter_x * self.input_ch * self.output_ch
+        per_channel_size = input_size // channel_count
+        values = np.array(nparray)
+        stride = 1
+        channel_stride = per_channel_size
+
+        for channel in range(channel_count):
+            fmin = 0
+            fmax = 0
+            for i in range(per_channel_size):
+                idx = channel * channel_stride + i * stride
+                fmin = min(fmin, values[idx])
+                fmax = max(fmax, values[idx])
+
+            self.scaling_factors.append(max(abs(fmin), abs(fmax)) / self.maxrange)
+
+            for x in range(per_channel_size):
+                chs = channel * channel_stride + x * stride
+                quantized_value = round(round(values[chs]) / self.scaling_factors[channel])
+                quantized_values.append(quantized_value)
+
+        return np.asarray(quantized_values)
+
+    def generate_quantize_per_channel_multiplier(self):
+        num_channels = self.output_ch
+        per_channel_multiplier = []
+        per_channel_shift = []
+
+        if len(self.scaling_factors) != num_channels:
+            print("missing scaling factors")
+            sys.exit(1)
+
+        def quantize_scale(scale):
+            significand, shift = math.frexp(scale)
+            significand_q31 = round(significand * (1 << 31))
+            return significand_q31, shift
+
+        for i in range(num_channels):
+            effective_output_scale = self.input_scale * self.scaling_factors[i] / self.output_scale
+            (quantized_multiplier, shift) = quantize_scale(effective_output_scale)
+
+            per_channel_multiplier.append(quantized_multiplier)
+            per_channel_shift.append(shift)
+
+        self.generate_c_array("output_mult", per_channel_multiplier, datatype='int32_t')
+        self.generate_c_array("output_shift", per_channel_shift, datatype='int32_t')
+
+    def convolution(self, indata, weights, bias=None):
+        out = tf.nn.conv2d(indata, weights, strides=[1, self.stride_x, self.stride_y, 1], padding=self.padding)
+
+        if tf.TensorShape([self.batches, self.y_output, self.x_output, self.output_ch]).as_list() != \
+           out.shape.as_list():
+            print("Shape mismatch, need to regenerate data?")
+            sys.exit(1)
+
+        b = tf.nn.bias_add(out, bias)
+        conv = tf.clip_by_value(b, self.minrange, self.maxrange)
+        return conv
+
+    def generate_data(self, input_data=None, weights=None, biases=None):
+        # Generate unless hardcoded data provided
+        if input_data is not None:
+            input_data = tf.reshape(input_data, [self.batches, self.y_input, self.x_input, self.input_ch])
+        else:
+            input_data = self.get_data([self.batches, self.y_input, self.x_input, self.input_ch],
+                                       self.inputs_table_file,
+                                       regenerate=self.regenerate_new_input)
+        if weights is not None:
+            weights = tf.reshape(weights, [self.filter_y, self.filter_x, self.input_ch, self.output_ch])
+        else:
+            weights = self.get_data([self.filter_y, self.filter_x, self.input_ch, self.output_ch],
+                                    self.kernel_table_file,
+                                    regenerate=self.regenerate_new_weights)
+        if biases is not None:
+            biases = tf.reshape(biases, [self.output_ch])
+        else:
+            biases = self.get_data([self.output_ch], self.bias_table_file, regenerate=self.regenerate_new_bias)
+
+        # Quantize and write to C headers
+        self.generate_c_array("input", self.convert_tensor(input_data, self.quantize_input))
+        self.generate_c_array("weights", self.convert_tensor_np(weights, self.quantize_filter))
+        self.generate_c_array("biases", self.convert_tensor_np(biases, self.quantize_bias), "int32_t")
+
+        # Generate conv reference
+        conv = self.convolution(input_data, weights, biases)
+        self.generate_c_array("output_ref", conv)
+
+        # Generate per output channel requantization mult/shift parameters
+        self.generate_quantize_per_channel_multiplier()
+
+        self.write_c_config_header()
+        self.write_c_header_wrapper()
+
+
+class PoolingSettings(TestSettings):
+
+    def __init__(self, args, randmin=-7, randmax=7, in_ch=1, out_ch=1, x_in=7, y_in=7, w_x=3, w_y=3, stride_x=2,
+                 stride_y=2, batches=1, pad=True, input_scale=0.5, output_scale=1.0, in_zero_point=0, out_zero_point=0):
+
+        super().__init__(args, randmin, randmax, in_ch, out_ch, x_in, y_in, w_x, w_y, stride_x, stride_y, batches, pad,
+                         input_scale, output_scale, in_zero_point, out_zero_point)
+
+    def generate_data(self, input_data=None, weights=None, biases=None):
+        # TODO
+        pass
+
+
+if __name__ == '__main__':
+    if version.parse(tf.__version__) < REQUIRED_MINIMUM_TENSORFLOW_VERSION:
+        print("Unsupported tensorflow version, ", version.parse(tf.__version__))
+        sys.exit(0)
+
+    args = parse_args()
+
+    if args.type == 'conv':
+        # basic
+        # generator = ConvSettings(args, x_in=5, y_in=8, w_x=2, w_y=4, stride_x=1, stride_y=1, pad=False)
+        # kernel1x1
+        # generator = ConvSettings(args, in_ch=4, x_in=8, y_in=8, w_x=1, w_y=1, stride_x=1, stride_y=1, pad=False)
+        # stride2pad1
+        generator = ConvSettings(args, x_in=7, y_in=7, w_x=3, w_y=3, stride_x=2, stride_y=2)
+    elif args.type == 'pooling':
+        generator = PoolingSettings(args)
+
+    generator.generate_data()

+ 51 - 0
CMSIS/NN/Tests/UnitTest/requirements.txt

@@ -0,0 +1,51 @@
+absl-py==0.9.0
+appdirs==1.4.3
+astor==0.8.1
+beautifulsoup4==4.8.2
+cachetools==4.0.0
+certifi==2019.11.28
+chardet==3.0.4
+colorama==0.4.3
+fasteners==0.15
+future==0.18.2
+gast==0.2.2
+google-auth==1.11.2
+google-auth-oauthlib==0.4.1
+google-pasta==0.1.8
+grpcio==1.27.2
+h5py==2.10.0
+idna==2.9
+intelhex==2.2.1
+junit-xml==1.9
+Keras-Applications==1.0.8
+Keras-Preprocessing==1.1.0
+lockfile==0.12.2
+Markdown==3.2.1
+mbed-cli==1.10.2
+mbed-ls==1.7.10
+mbed-os-tools==0.0.12
+mercurial==5.3
+monotonic==1.5
+numpy==1.18.1
+oauthlib==3.1.0
+opt-einsum==3.1.0
+packaging==20.1
+prettytable==0.7.2
+protobuf==3.11.3
+pyasn1==0.4.8
+pyasn1-modules==0.2.8
+pyparsing==2.4.6
+pyserial==3.4
+requests==2.23.0
+requests-oauthlib==1.3.0
+rsa==4.0
+scipy==1.4.1
+six==1.14.0
+soupsieve==2.0
+tensorboard==2.1.0
+tensorflow==2.1.0
+tensorflow-estimator==2.1.0
+termcolor==1.1.0
+urllib3==1.25.8
+Werkzeug==1.0.0
+wrapt==1.12.0

+ 427 - 0
CMSIS/NN/Tests/UnitTest/unittest_targets.py

@@ -0,0 +1,427 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os
+import re
+import sys
+import json
+import copy
+import glob
+import time
+import queue
+import shutil
+import serial
+import argparse
+import threading
+import subprocess
+
+from os import path
+
+OUTPUT = "Output/"
+BASE_PATH = "../../"
+CMSIS_PATH = "../../../../../"
+UNITY_PATH = "../Unity/"
+UNITY_BASE = BASE_PATH + UNITY_PATH
+UNITY_SRC = UNITY_BASE + "src/"
+CMSIS_FLAGS = " -DARM_MATH_DSP -DARM_MATH_LOOPUNROLL"
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(description="Run CMSIS-NN unit tests.",
+                                     epilog="Runs on all connected HW supported by Mbed.")
+    parser.add_argument('--testdir', type=str, default='TESTRUN', help="prefix of output dir name")
+    parser.add_argument('--compiler', type=str, default='GCC_ARM', choices=['GCC_ARM', 'ARMC6'])
+    args = parser.parse_args()
+    return args
+
+
+def error_handler(code, text=None):
+    print("Error: {}".format(text))
+    sys.exit(code)
+
+
+def detect_targets(targets):
+    process = subprocess.Popen(['mbedls'],
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE,
+                               universal_newlines=True)
+    print(process.stdout.readline().strip())
+    while True:
+        line = process.stdout.readline()
+        print(line.strip())
+        if not line:
+            break
+        if re.search(r"^\| ", line):
+            words = (line.split('| '))
+            target = {"model": words[1].strip(),
+                      "name": words[2].strip()[:-1].replace('[', '_'),
+                      "port": words[4].strip(),
+                      "tid": words[5].strip()}  # Target id can be used to filter out targets
+            targets.append(target)
+    return_code = process.poll()
+    if return_code != 0:
+        error_handler(return_code, 'RETURN CODE {}'.format(process.stderr.read()))
+
+
+def run_command(command, error_msg=None, die=True):
+    # TODO handle error:
+    # cp: error writing '/media/mannil01/NODE_F411RE/TESTRUN_NUCLEO_F411RE_GCC_ARM.bin': No space left on device
+    # https://os.mbed.com/questions/59636/STM-Nucleo-No-space-left-on-device-when-/
+
+    # print(command)
+    command_list = command.split(' ')
+    process = subprocess.run(command_list)
+    if die and process.returncode != 0:
+        error_handler(process.returncode, error_msg)
+    return process.returncode
+
+
+def detect_architecture(target_name, target_json):
+    arch = None
+
+    try:
+        with open(target_json, "r") as read_file:
+            data = json.load(read_file)
+
+            if data[target_name]['core']:
+                arch = data[target_name]['core'][:9]
+                if data[target_name]['core'][:8] == 'Cortex-M':
+                    return arch
+            error_handler(668, 'Unsupported target: {} with architecture: {}'.format(
+                target_name, arch))
+    except Exception as e:
+        error_handler(667, e)
+
+    return arch
+
+
+def test_target(target, args, main_test):
+    result = 3
+    compiler = args.compiler
+    target_name = target['name']
+    target_model = target['model']
+    cmsis_flags = None
+    unittestframework = 'UNITY_UNITTEST'
+
+    dir_name = OUTPUT + args.testdir + '_' + unittestframework + '_' + target_name + '_' + compiler
+
+    os.makedirs(dir_name, exist_ok=True)
+    start_dir = os.getcwd()
+    os.chdir(dir_name)
+
+    try:
+        target_json = 'mbed-os/targets/targets.json'
+
+        if not path.exists("mbed-os.lib"):
+            print("Initializing mbed in {}".format(os.getcwd()))
+            run_command('mbed new .')
+            shutil.copyfile(BASE_PATH + 'Profiles/mbed_app.json', 'mbed_app.json')
+
+        arch = detect_architecture(target_model, target_json)
+        if arch == 'Cortex-M4' or arch == 'Cortex-M7':
+            cmsis_flags = CMSIS_FLAGS
+
+        print("----------------------------------------------------------------")
+        print("Running {} on {} target: {} with compiler: {} and cmsis flags: {} in directory: {} test: {}\n".format(
+            unittestframework, arch, target_name, compiler, cmsis_flags, os.getcwd(), main_test))
+
+        die = False
+        flash_error_msg = 'failed to flash'
+        mbed_command = "compile"
+        test = ''
+        additional_options = ' --source ' + BASE_PATH + main_test + \
+                             ' --source ' + UNITY_SRC + \
+                             ' --profile ' + BASE_PATH + 'Profiles/release.json' + \
+                             ' -f'
+
+        result = run_command("mbed {} -v -m ".format(mbed_command) + target_model + ' -t ' + compiler +
+                             test +
+                             ' --source .'
+                             ' --source ' + BASE_PATH + 'TestCases/Utils/'
+                             ' --source ' + CMSIS_PATH + 'NN/Include/'
+                             ' --source ' + CMSIS_PATH + 'DSP/Include/'
+                             ' --source ' + CMSIS_PATH + 'Core/Include/'
+                             ' --source ' + CMSIS_PATH + 'NN/Source/ConvolutionFunctions/'
+                             ' --source ' + CMSIS_PATH + 'NN/Source/NNSupportFunctions/'
+                             + cmsis_flags +
+                             additional_options,
+                             flash_error_msg, die=die)
+
+    except Exception as e:
+        error_handler(666, e)
+
+    os.chdir(start_dir)
+    return result
+
+
+def read_serial_port(ser, inputQueue, stop):
+    while True:
+        if stop():
+            break
+        line = ser.readline()
+        inputQueue.put(line.decode('latin-1').strip())
+
+
+def test_target_with_unity(target, args, main_test):
+    port = target['port']
+    stop_thread = False
+    baudrate = 9600
+    timeout = 30
+    inputQueue = queue.Queue()
+    tests = copy.deepcopy(target["tests"])
+    result = []
+
+    try:
+        ser = serial.Serial(port, baudrate, timeout=timeout)
+    except Exception as e:
+        error_handler(669, "serial exception: {}".format(e))
+
+    # Clear read buffer
+    time.sleep(0.1)  # Workaround in response to: open() returns before port is ready
+    ser.reset_input_buffer()
+
+    serial_thread = threading.Thread(target=read_serial_port, args=(ser, inputQueue, lambda: stop_thread), daemon=True)
+    serial_thread.start()
+
+    test_target(target, args, main_test)
+
+    start_time = time.time()
+    while time.time() < start_time + timeout:
+        if inputQueue.qsize() > 0:
+            str_line = inputQueue.get()
+            print(str_line)
+            test = None
+            try:
+                test = str_line.split(':')[2]
+                test_result = ':'.join(str_line.split(':')[2:4])
+            except IndexError:
+                pass
+            if test in tests:
+                result.append("{}: {}".format(target["name"], test_result))
+                tests.remove(test)
+                target[test]["tested"] = True
+                if test_result == test + ':PASS':
+                    target[test]["pass"] = True
+            if len(tests) == 0:
+                break
+
+    stop_thread = True
+    serial_thread.join()
+    ser.close()
+
+    print()
+    for res in result:
+        print(res)
+
+
+def print_summary(targets):
+    """
+    Return 0 if all test passed
+    Return 1 if all test completed but one or more failed
+    Return 2 if one or more tests did not complete or was not detected
+    """
+    passed = 0
+    failed = 0
+    tested = 0
+    expected = 0
+    return_code = 3
+
+    print("-----------------------------------------------------------------------------------------------------------")
+
+    # Find all passed and failed
+    for target in targets:
+        for test in target["tests"]:
+            expected += 1
+            if target[test]["tested"]:
+                tested += 1
+            else:
+                print("ERROR: Test {} for target {} not found".format(test, target["name"]))
+            if target[test]["pass"]:
+                passed += 1
+            else:
+                failed += 1
+
+    if tested != expected:
+        print("ERROR: Not all tests found!")
+        print("Expected: {} Actual: {}".format(expected, tested))
+        return_code = 2
+    elif tested == passed:
+        return_code = 0
+    else:
+        return_code = 1
+
+    print("Summary: {} tests in total passed on {} targets ({})".
+          format(passed, len(targets), ', '.join([t['name'] for t in targets])))
+
+    # Print those that failed
+    if failed > 0:
+        print()
+        for target in targets:
+            for test in target["tests"]:
+                if not target[test]["pass"]:
+                    print("{}: {} failed".format(target["name"], test))
+
+    if (passed > 0):
+        print("{:.0f}% tests passed, {} tests failed out of {}".format(passed/expected*100, failed, expected))
+    else:
+        print("0% tests passed, {} tests failed out of {}".format(failed, tested))
+
+    return return_code
+
+
+def test_targets(args):
+    """
+    Return 0 if successful
+    Return 3 if no targets are detected
+    Return 4 if no tests are found
+    """
+    result = 0
+    targets = []
+    main_tests = []
+
+    detect_targets(targets)
+
+    if len(targets) == 0:
+        print("No targets detected!")
+        return 3
+
+    download_unity()
+    if not parse_tests(targets, main_tests):
+        print("No tests found?!")
+        return 4
+
+    for target in targets:
+        for tst in main_tests:
+            test_target_with_unity(target, args, tst)
+
+    result = print_summary(targets)
+
+    return result
+
+
+def download_unity(force=False):
+    unity_dir = UNITY_PATH
+    unity_src = unity_dir+"src/"
+    process = subprocess.run(['mktemp'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+    download_dir = process.stdout.strip()
+    run_command("rm -f {}".format(download_dir))
+    download_dir += '/'
+
+    # Check if already downloaded
+    if not force and path.isdir(unity_dir) and path.isfile(unity_src+"unity.c") and path.isfile(unity_src+"unity.h"):
+        return
+
+    if path.isdir(download_dir):
+        shutil.rmtree(download_dir)
+    if path.isdir(unity_dir):
+        shutil.rmtree(unity_dir)
+    os.mkdir(unity_dir)
+    os.makedirs(download_dir, exist_ok=False)
+    current_dir = os.getcwd()
+    os.chdir(download_dir)
+
+    process = subprocess.Popen("curl -LJO https://api.github.com/repos/ThrowTheSwitch/Unity/tarball/v2.5.0".split(),
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE,
+                               universal_newlines=True)
+    for line in process.stderr:
+        print(line.strip())
+    print()
+    for line in process.stdout:
+        pass
+    if not line:
+        error_handler(671)
+    try:
+        m = re.search('\'(.+?)\'', line.strip())
+    except AttributeError as e:
+        error_handler(673, e)
+    downloaded_file = download_dir + m.group(1)
+    os.chdir(current_dir)
+    try:
+        filename_base = downloaded_file.split('-')[0]
+    except IndexError as e:
+        error_handler(674, e)
+    if not filename_base:
+        error_handler(675)
+    run_command("tar xzf "+downloaded_file+" -C "+unity_dir+" --strip-components=1")
+    os.chdir(current_dir)
+
+    # Cleanup
+    shutil.rmtree(download_dir)
+
+
+def parse_tests(targets, main_tests):
+    """
+    Generate test runners and parse it to know what to expect from the serial console
+    Return True if successful
+    """
+    directory = 'TestCases'
+    for dir in next(os.walk(directory))[1]:
+        if re.search(r'test_arm', dir):
+            testpath = directory + '/' + dir + '/Unity/'
+            main_tests.append(testpath)
+            for content in os.listdir(testpath):
+                if re.search(r'unity_test_arm', content):
+                    ut_test_file = content
+            ut_test_file_runner = path.splitext(ut_test_file)[0] + '_runner' + path.splitext(ut_test_file)[1]
+            test_code = testpath + ut_test_file
+            test_runner_path = testpath + 'TestRunner/'
+            if not os.path.exists(test_runner_path):
+                os.mkdir(test_runner_path)
+            test_runner = test_runner_path + ut_test_file_runner
+            for old_files in glob.glob(test_runner_path + '/*'):
+                if not old_files.endswith('readme.txt'):
+                    os.remove(old_files)
+
+            # Generate test runners
+            run_command('ruby '+UNITY_PATH+'auto/generate_test_runner.rb ' + test_code + ' ' + test_runner)
+            test_found = parse_test(test_runner, targets)
+            if not test_found:
+                return False
+    return True
+
+
+def parse_test(test_runner, targets):
+    tests_found = False
+
+    # Get list of tests
+    try:
+        read_file = open(test_runner, "r")
+    except IOError as e:
+        error_handler(670, e)
+    else:
+        with read_file:
+            for line in read_file:
+                if not line:
+                    break
+                if re.search(r"  run_test\(", line) and len(line.strip().split(',')) == 3:
+                    function = line.strip().split(',')[0].split('(')[1]
+                    tests_found = True
+                    for target in targets:
+                        if 'tests' not in target.keys():
+                            target['tests'] = []
+                        target["tests"].append(function)
+                        target[function] = {}
+                        target[function]["pass"] = False
+                        target[function]["tested"] = False
+    return tests_found
+
+
+if __name__ == '__main__':
+    args = parse_args()
+    sys.exit(test_targets(args))