test_fp.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include <math.h>
  2. #include <stdio.h>
  3. #include "freertos/FreeRTOS.h"
  4. #include "freertos/task.h"
  5. #include "unity.h"
  6. static float addsf(float a, float b)
  7. {
  8. float result;
  9. asm volatile (
  10. "wfr f0, %1\n"
  11. "wfr f1, %2\n"
  12. "add.s f2, f0, f1\n"
  13. "rfr %0, f2\n"
  14. :"=r"(result):"r"(a), "r"(b)
  15. );
  16. return result;
  17. }
  18. static float mulsf(float a, float b)
  19. {
  20. float result;
  21. asm volatile (
  22. "wfr f0, %1\n"
  23. "wfr f1, %2\n"
  24. "mul.s f2, f0, f1\n"
  25. "rfr %0, f2\n"
  26. :"=r"(result):"r"(a), "r"(b)
  27. );
  28. return result;
  29. }
  30. static float divsf(float a, float b)
  31. {
  32. float result;
  33. asm volatile (
  34. "wfr f0, %1\n"
  35. "wfr f1, %2\n"
  36. "div0.s f3, f1 \n"
  37. "nexp01.s f4, f1 \n"
  38. "const.s f5, 1 \n"
  39. "maddn.s f5, f4, f3 \n"
  40. "mov.s f6, f3 \n"
  41. "mov.s f7, f1 \n"
  42. "nexp01.s f8, f0 \n"
  43. "maddn.s f6, f5, f3 \n"
  44. "const.s f5, 1 \n"
  45. "const.s f2, 0 \n"
  46. "neg.s f9, f8 \n"
  47. "maddn.s f5,f4,f6 \n"
  48. "maddn.s f2, f0, f3 \n"
  49. "mkdadj.s f7, f0 \n"
  50. "maddn.s f6,f5,f6 \n"
  51. "maddn.s f9,f4,f2 \n"
  52. "const.s f5, 1 \n"
  53. "maddn.s f5,f4,f6 \n"
  54. "maddn.s f2,f9,f6 \n"
  55. "neg.s f9, f8 \n"
  56. "maddn.s f6,f5,f6 \n"
  57. "maddn.s f9,f4,f2 \n"
  58. "addexpm.s f2, f7 \n"
  59. "addexp.s f6, f7 \n"
  60. "divn.s f2,f9,f6\n"
  61. "rfr %0, f2\n"
  62. :"=r"(result):"r"(a), "r"(b)
  63. );
  64. return result;
  65. }
  66. static float sqrtsf(float a)
  67. {
  68. float result;
  69. asm volatile (
  70. "wfr f0, %1\n"
  71. "sqrt0.s f2, f0\n"
  72. "const.s f5, 0\n"
  73. "maddn.s f5, f2, f2\n"
  74. "nexp01.s f3, f0\n"
  75. "const.s f4, 3\n"
  76. "addexp.s f3, f4\n"
  77. "maddn.s f4, f5, f3\n"
  78. "nexp01.s f5, f0\n"
  79. "neg.s f6, f5\n"
  80. "maddn.s f2, f4, f2\n"
  81. "const.s f1, 0\n"
  82. "const.s f4, 0\n"
  83. "const.s f7, 0\n"
  84. "maddn.s f1, f6, f2\n"
  85. "maddn.s f4, f2, f3\n"
  86. "const.s f6, 3\n"
  87. "maddn.s f7, f6, f2\n"
  88. "maddn.s f5, f1, f1\n"
  89. "maddn.s f6, f4, f2\n"
  90. "neg.s f3, f7\n"
  91. "maddn.s f1, f5, f3\n"
  92. "maddn.s f7, f6, f7\n"
  93. "mksadj.s f2, f0\n"
  94. "nexp01.s f5, f0\n"
  95. "maddn.s f5, f1, f1\n"
  96. "neg.s f3, f7\n"
  97. "addexpm.s f1, f2\n"
  98. "addexp.s f3, f2\n"
  99. "divn.s f1, f5, f3\n"
  100. "rfr %0, f1\n"
  101. :"=r"(result):"r"(a)
  102. );
  103. return result;
  104. }
  105. TEST_CASE("test FP add", "[fp]")
  106. {
  107. float a = 100.0f;
  108. float b = 0.5f;
  109. float c = addsf(a, b);
  110. float eps = c - 100.5f;
  111. printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
  112. TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
  113. }
  114. TEST_CASE("test FP mul", "[fp]")
  115. {
  116. float a = 100.0f;
  117. float b = 0.05f;
  118. float c = mulsf(a, b);
  119. float eps = c - 5.0f;
  120. printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
  121. TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
  122. }
  123. TEST_CASE("test FP div", "[fp]")
  124. {
  125. float a = 100.0f;
  126. float b = 5.0f;
  127. float c = divsf(a, b);
  128. float eps = c - 20.0f;
  129. printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
  130. TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
  131. }
  132. TEST_CASE("test FP sqrt", "[fp]")
  133. {
  134. float a = 100.0f;
  135. float c = sqrtsf(a);
  136. float eps = c - 10.0f;
  137. printf("a=%g c=%g eps=%g\r\n", a, c, eps);
  138. TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
  139. }
  140. struct TestFPState {
  141. int fail;
  142. int done;
  143. };
  144. static const int testFpIter = 100000;
  145. static void tskTestFP(void *pvParameters)
  146. {
  147. struct TestFPState *state = (struct TestFPState *) pvParameters;
  148. for (int i = 0; i < testFpIter; ++i) {
  149. // calculate zero in a slightly obscure way
  150. float y = sqrtsf(addsf(1.0f, divsf(mulsf(sqrtsf(2), sqrtsf(2)), 2.0f)));
  151. y = mulsf(y, y);
  152. y = addsf(y, -2.0f);
  153. // check that result is not far from zero
  154. float eps = fabs(y);
  155. if (eps > 1e-6f) {
  156. state->fail++;
  157. printf("%s: i=%d y=%f eps=%f\r\n", __func__, i, y, eps);
  158. }
  159. }
  160. state->done++;
  161. vTaskDelete(NULL);
  162. }
  163. TEST_CASE("context switch saves FP registers", "[fp]")
  164. {
  165. struct TestFPState state;
  166. state.done = 0;
  167. state.fail = 0;
  168. xTaskCreatePinnedToCore(tskTestFP, "tsk1", 2048, &state, 3, NULL, 0);
  169. xTaskCreatePinnedToCore(tskTestFP, "tsk2", 2048, &state, 3, NULL, 0);
  170. xTaskCreatePinnedToCore(tskTestFP, "tsk3", 2048, &state, 3, NULL, 1);
  171. xTaskCreatePinnedToCore(tskTestFP, "tsk4", 2048, &state, 3, NULL, 0);
  172. while (state.done != 4) {
  173. vTaskDelay(100 / portTICK_PERIOD_MS);
  174. }
  175. if (state.fail) {
  176. const int total = testFpIter * 4;
  177. printf("Failed: %d, total: %d\r\n", state.fail, total);
  178. }
  179. TEST_ASSERT(state.fail == 0);
  180. }