pico_divider_nesting_test.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <math.h>
  9. #include "pico/stdlib.h"
  10. #include "hardware/dma.h"
  11. #include "hardware/irq.h"
  12. volatile bool failed;
  13. volatile uint32_t count[3];
  14. volatile bool done;
  15. #define FAILED() ({ failed = true; })
  16. //#define FAILED() ({ failed = true; __breakpoint(); })
  17. bool timer_callback(repeating_timer_t *t) {
  18. count[0]++;
  19. static int z;
  20. for (int i=0; i<100;i++) {
  21. z += 23;
  22. int a = z / 7;
  23. int b = z % 7;
  24. if (z != a * 7 + b) {
  25. FAILED();
  26. }
  27. a = z / -7;
  28. b = z % -7;
  29. if (z != a * -7 + b) {
  30. FAILED();
  31. }
  32. }
  33. float fz = z;
  34. float fa = fz / 11.0f;
  35. float fb = fmodf(fz, 11.0f);
  36. if (fabsf(fz - (fa * 11.0 + fb) > 1e-9)) {
  37. FAILED();
  38. }
  39. double dz = z;
  40. double da = dz / 11.0;
  41. double db = fmod(dz, 11.0);
  42. if (fabsf(dz - (da * 11.0 + db) > 1e-9)) {
  43. FAILED();
  44. }
  45. return !done;
  46. }
  47. void do_dma_start(uint ch) {
  48. static uint32_t word[2];
  49. assert(ch < 2);
  50. dma_channel_config c = dma_channel_get_default_config(ch);
  51. // todo remove this; landing in a separate PR
  52. #ifndef DREQ_DMA_TIMER0
  53. #define DREQ_DMA_TIMER0 0x3b
  54. #endif
  55. channel_config_set_dreq(&c, DREQ_DMA_TIMER0);
  56. dma_channel_configure(ch, &c, &word[ch], &word[ch], 513 + ch * 23, true);
  57. }
  58. double d0c, d0s, d0t, dz;
  59. float f0c, f0s, f0t, fz;
  60. void test_irq_handler0() {
  61. count[1]++;
  62. dma_hw->ints0 |= 1u;
  63. static uint z;
  64. static uint dz;
  65. for (int i=0; i<80;i++) {
  66. z += 31;
  67. uint a = z / 11;
  68. uint b = z % 11;
  69. if (z != a * 11 + b) {
  70. FAILED();
  71. }
  72. }
  73. if (done) dma_channel_abort(0);
  74. else do_dma_start(0);
  75. }
  76. void test_irq_handler1() {
  77. static uint z;
  78. dma_hw->ints1 |= 2u;
  79. count[2]++;
  80. for (int i=0; i<130;i++) {
  81. z += 47;
  82. uint a = z / -13;
  83. uint b = z % -13;
  84. if (z != a * -13 + b) {
  85. FAILED();
  86. }
  87. static uint64_t z64;
  88. z64 -= 47;
  89. uint64_t a64 = z64 / -13;
  90. uint64_t b64 = z64 % -13;
  91. if (z64 != a64 * -13 + b64) {
  92. FAILED();
  93. }
  94. }
  95. if (done) dma_channel_abort(1);
  96. else do_dma_start(1);
  97. }
  98. void test_nesting() {
  99. uint z = 0;
  100. // We have 3 different IRQ handlers, one for timer, two for DMA completion (on DMA_IRQ0/1)
  101. // thus we expect re-entrancy even between IRQs
  102. //
  103. // They all busily make use of the dividers, to expose any issues with nested use
  104. repeating_timer_t timer;
  105. add_repeating_timer_us(929, timer_callback, NULL, &timer);
  106. irq_set_exclusive_handler(DMA_IRQ_0, test_irq_handler0);
  107. irq_set_exclusive_handler(DMA_IRQ_1, test_irq_handler1);
  108. dma_set_irq0_channel_mask_enabled(1u, true);
  109. dma_set_irq1_channel_mask_enabled(2u, true);
  110. dma_hw->timer[0] = (1 << 16) | 32; // run at 1/32 system clock
  111. irq_set_enabled(DMA_IRQ_0, 1);
  112. irq_set_enabled(DMA_IRQ_1, 1);
  113. do_dma_start(0);
  114. do_dma_start(1);
  115. absolute_time_t end = delayed_by_ms(get_absolute_time(), 10000);
  116. int count_local=0;
  117. while (!time_reached(end)) {
  118. for(uint i=0;i<100;i++) {
  119. z += 31;
  120. uint a = z / 11;
  121. uint b = z % 11;
  122. if (z != a * 11 + b) {
  123. FAILED();
  124. }
  125. int zz = (int)z;
  126. int aa = zz / -11;
  127. int bb = zz % -11;
  128. if (zz != aa * -11 + bb) {
  129. FAILED();
  130. }
  131. aa = -zz / -11;
  132. bb = -zz % -11;
  133. if (-zz != aa * -11 + bb) {
  134. FAILED();
  135. }
  136. aa = -zz / 11;
  137. bb = -zz % 11;
  138. if (-zz != aa * 11 + bb) {
  139. FAILED();
  140. }
  141. a = 0xffffffffu / 11;
  142. b = 0xffffffffu % 11;
  143. if (0xffffffffu != a * 11 + b) {
  144. FAILED();
  145. }
  146. static uint64_t z64;
  147. z64 -= 47;
  148. uint64_t a64 = z64 / -13635;
  149. uint64_t b64 = z64 % -13635;
  150. if (z64 != a64 * -13635 + b64) {
  151. FAILED();
  152. }
  153. // specifically check 64/32 divide
  154. static uint64_t c64 = 0x13ffffffffull;
  155. static uint32_t cd = 1;
  156. a64 = c64 / cd;
  157. b64 = c64 % cd;
  158. if (c64 != a64 * cd + b64) {
  159. FAILED();
  160. }
  161. cd++;
  162. }
  163. // these use the divider
  164. for(uint i=0;i<=100;i+=20) {
  165. // both in and out bootrom range (we perform mod in wrapper code if necessarry)
  166. f0t = tanf(i * 50);
  167. f0c = cosf(i * 50);
  168. f0s = sinf(i * 50);
  169. d0t = tan(i * 1000);
  170. d0c = cos(i * 1000);
  171. d0s = sin(i * 1000);
  172. }
  173. count_local++;
  174. }
  175. done = true;
  176. cancel_repeating_timer(&timer);
  177. printf("%d: %d %d %d\n", count_local, (int)count[0], (int)count[1], (int)count[2]);
  178. // make sure all the IRQs ran
  179. if (!(count_local && count[0] && count[1] && count[2])) {
  180. printf("DID NOT RUN\n");
  181. exit(1);
  182. }
  183. if (failed) {
  184. printf("FAILED\n");
  185. exit(1);
  186. }
  187. }
  188. int main() {
  189. #ifndef uart_default
  190. #warning test/pico_divider requires a default uart
  191. #else
  192. stdio_init_all();
  193. #endif
  194. test_nesting();
  195. printf("PASSED\n");
  196. return 0;
  197. }