pendsv.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2013, 2014 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <stdlib.h>
  27. #include "py/runtime.h"
  28. #include "lib/utils/interrupt_char.h"
  29. #include "pendsv.h"
  30. #include "irq.h"
  31. // This variable is used to save the exception object between a ctrl-C and the
  32. // PENDSV call that actually raises the exception. It must be non-static
  33. // otherwise gcc-5 optimises it away. It can point to the heap but is not
  34. // traced by GC. This is okay because we only ever set it to
  35. // mp_kbd_exception which is in the root-pointer set.
  36. void *pendsv_object;
  37. void pendsv_init(void) {
  38. // set PendSV interrupt at lowest priority
  39. NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
  40. }
  41. // Call this function to raise a pending exception during an interrupt.
  42. // It will first try to raise the exception "softly" by setting the
  43. // mp_pending_exception variable and hoping that the VM will notice it.
  44. // If this function is called a second time (ie with the mp_pending_exception
  45. // variable already set) then it will force the exception by using the hardware
  46. // PENDSV feature. This will wait until all interrupts are finished then raise
  47. // the given exception object using nlr_jump in the context of the top-level
  48. // thread.
  49. void pendsv_kbd_intr(void) {
  50. if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_NULL) {
  51. mp_keyboard_interrupt();
  52. } else {
  53. MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
  54. pendsv_object = &MP_STATE_VM(mp_kbd_exception);
  55. SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
  56. }
  57. }
  58. void pendsv_isr_handler(void) {
  59. // re-jig the stack so that when we return from this interrupt handler
  60. // it returns instead to nlr_jump with argument pendsv_object
  61. // note that stack has a different layout if DEBUG is enabled
  62. //
  63. // on entry to this (naked) function, stack has the following layout:
  64. //
  65. // stack layout with DEBUG disabled:
  66. // sp[6]: pc=r15
  67. // sp[5]: lr=r14
  68. // sp[4]: r12
  69. // sp[3]: r3
  70. // sp[2]: r2
  71. // sp[1]: r1
  72. // sp[0]: r0
  73. //
  74. // stack layout with DEBUG enabled:
  75. // sp[8]: pc=r15
  76. // sp[7]: lr=r14
  77. // sp[6]: r12
  78. // sp[5]: r3
  79. // sp[4]: r2
  80. // sp[3]: r1
  81. // sp[2]: r0
  82. // sp[1]: 0xfffffff9
  83. // sp[0]: ?
  84. #if MICROPY_PY_THREAD
  85. __asm volatile (
  86. "ldr r1, pendsv_object_ptr\n"
  87. "ldr r0, [r1]\n"
  88. "cmp r0, 0\n"
  89. "beq .no_obj\n"
  90. "str r0, [sp, #0]\n" // store to r0 on stack
  91. "mov r0, #0\n"
  92. "str r0, [r1]\n" // clear pendsv_object
  93. "ldr r0, nlr_jump_ptr\n"
  94. "str r0, [sp, #24]\n" // store to pc on stack
  95. "bx lr\n" // return from interrupt; will return to nlr_jump
  96. ".no_obj:\n" // pendsv_object==NULL
  97. "push {r4-r11, lr}\n"
  98. "vpush {s16-s31}\n"
  99. "mrs r5, primask\n" // save PRIMASK in r5
  100. "cpsid i\n" // disable interrupts while we change stacks
  101. "mov r0, sp\n" // pass sp to save
  102. "mov r4, lr\n" // save lr because we are making a call
  103. "bl pyb_thread_next\n" // get next thread to execute
  104. "mov lr, r4\n" // restore lr
  105. "mov sp, r0\n" // switch stacks
  106. "msr primask, r5\n" // reenable interrupts
  107. "vpop {s16-s31}\n"
  108. "pop {r4-r11, lr}\n"
  109. "bx lr\n" // return from interrupt; will return to new thread
  110. ".align 2\n"
  111. "pendsv_object_ptr: .word pendsv_object\n"
  112. "nlr_jump_ptr: .word nlr_jump\n"
  113. );
  114. #else
  115. __asm volatile (
  116. "ldr r0, pendsv_object_ptr\n"
  117. "ldr r0, [r0]\n"
  118. #if defined(PENDSV_DEBUG)
  119. "str r0, [sp, #8]\n"
  120. #else
  121. "str r0, [sp, #0]\n"
  122. #endif
  123. "ldr r0, nlr_jump_ptr\n"
  124. #if defined(PENDSV_DEBUG)
  125. "str r0, [sp, #32]\n"
  126. #else
  127. "str r0, [sp, #24]\n"
  128. #endif
  129. "bx lr\n"
  130. ".align 2\n"
  131. "pendsv_object_ptr: .word pendsv_object\n"
  132. "nlr_jump_ptr: .word nlr_jump\n"
  133. );
  134. #endif
  135. /*
  136. uint32_t x[2] = {0x424242, 0xdeaddead};
  137. printf("PendSV: %p\n", x);
  138. for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) {
  139. printf(" %p: %08x %08x %08x %08x\n", p, (uint)p[0], (uint)p[1], (uint)p[2], (uint)p[3]);
  140. }
  141. */
  142. }