nrf_atfifo_internal.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /**
  2. * Copyright (c) 2011 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /**
  41. * @file
  42. * @brief Atomic FIFO internal file
  43. *
  44. * This file should be included only by nrf_atfifo internally.
  45. * Needs nrf_atfifo.h included first.
  46. */
  47. #ifndef NRF_ATFIFO_H__
  48. #error This is internal file. Do not include this file in your program.
  49. #endif
  50. #ifndef NRF_ATFIFO_INTERNAL_H__
  51. #define NRF_ATFIFO_INTERNAL_H__
  52. #include <stddef.h>
  53. #include "nrf.h"
  54. #include "app_util.h"
  55. #include "nordic_common.h"
  56. #if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0
  57. #error Unsupported core version
  58. #endif
  59. /*
  60. * Make sure that rd and wr pos in a tag are aligned like expected
  61. * Changing this would require changes inside assembly code!
  62. */
  63. STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, wr) == 0);
  64. STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, rd) == 2);
  65. /**
  66. * @brief Atomically reserve space for a new write.
  67. *
  68. * @param[in,out] p_fifo FIFO object.
  69. * @param[out] old_tail Tail position tag before new space is reserved.
  70. *
  71. * @retval true Space available.
  72. * @retval false Memory full.
  73. *
  74. * @sa nrf_atfifo_wspace_close
  75. */
  76. static bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail);
  77. /**
  78. * @brief Atomically mark all written data available.
  79. *
  80. * This function marks all data available for reading.
  81. * This marking is done by copying tail.pos.wr into tail.pos.rd.
  82. *
  83. * It must be called only when closing the first write.
  84. * It cannot be called if any write access was interrupted.
  85. * See the code below:
  86. * @code
  87. * if (old_tail.pos.wr == old_tail.pos.rd)
  88. * {
  89. * nrf_atfifo_wspace_close(my_fifo);
  90. * return true;
  91. * }
  92. * return false;
  93. * @endcode
  94. *
  95. * @param[in,out] p_fifo FIFO object.
  96. *
  97. * @sa nrf_atfifo_wspace_req
  98. */
  99. static void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo);
  100. /**
  101. * @brief Atomically get a part of a buffer to read data.
  102. *
  103. * @param[in,out] p_fifo FIFO object.
  104. * @param[out] old_head Head position tag before the data buffer is read.
  105. *
  106. * @retval true Data available for reading.
  107. * @retval false No data in the buffer.
  108. *
  109. * @sa nrf_atfifo_rspace_close
  110. */
  111. static bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head);
  112. /**
  113. * @brief Atomically release all read data.
  114. *
  115. * This function marks all data that was read as free space,
  116. * which is available for writing.
  117. * This marking is done by copying head.pos.rd into head.pos.wr.
  118. *
  119. * It must be called only when closing the first read.
  120. * It cannot be called when the current read access interrupted any other read access.
  121. * See code below:
  122. * @code
  123. * if (old_head.pos.wr == old_head.pos.rd)
  124. * {
  125. * nrf_atfifo_rspace_close(my_fifo);
  126. * return true;
  127. * }
  128. * return false;
  129. * @endcode
  130. *
  131. * @param[in,out] p_fifo FIFO object.
  132. *
  133. * @sa nrf_atfifo_rspace_req
  134. */
  135. static void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo);
  136. /**
  137. * @brief Safely clear the FIFO, internal function.
  138. *
  139. * This function realizes the functionality required by @ref nrf_atfifo_clear.
  140. *
  141. * @param[in,out] p_fifo FIFO object.
  142. *
  143. * @retval true All the data was released.
  144. * @retval false All the data available for releasing was released, but there is some pending transfer.
  145. */
  146. static bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo);
  147. /* ---------------------------------------------------------------------------
  148. * Implementation starts here
  149. */
  150. #if defined ( __CC_ARM )
  151. __ASM bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
  152. {
  153. /* Registry usage:
  154. * R0 - p_fifo
  155. * R1 - p_old_tail
  156. * R2 - internal variable old_tail (saved by caller)
  157. * R3 - internal variable new_tail (saved by caller)
  158. * R4 - internal temporary register (saved by this function)
  159. * R5 - not used stored to keep the stack aligned to 8 bytes
  160. * Returned value:
  161. * R0 (bool - 32 bits)
  162. */
  163. push {r4, r5}
  164. nrf_atfifo_wspace_req_repeat
  165. /* Load tail tag and set memory monitor !!! R2 - old tail !!! */
  166. ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
  167. /* Extract write position !!! R3 !!! */
  168. uxth r3, r2
  169. /* Increment address with overload support !!! R4 used temporary !!! */
  170. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, item_size))]
  171. add r3, r4
  172. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, buf_size))]
  173. cmp r3, r4
  174. it hs
  175. subhs r3, r3, r4
  176. /* Check if FIFO would overload after making this increment !!! R4 used temporary !!! */
  177. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr))]
  178. cmp r3, r4
  179. ittt eq
  180. clrexeq
  181. moveq r0, #__cpp(false)
  182. beq nrf_atfifo_wspace_req_exit
  183. /* Pack everything back !!! R3 - new tail !!! */
  184. /* Copy lower byte from new_tail, and higher byte is a value from the top of old_tail */
  185. pkhbt r3, r3, r2
  186. /* Store new value clearing memory monitor !!! R4 used temporary !!! */
  187. strex r4, r3, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
  188. cmp r4, #0
  189. bne nrf_atfifo_wspace_req_repeat
  190. /* Return true */
  191. mov r0, #__cpp(true)
  192. nrf_atfifo_wspace_req_exit
  193. /* Save old tail */
  194. str r2, [r1]
  195. pop {r4, r5}
  196. bx lr
  197. }
  198. __ASM void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo)
  199. {
  200. /* Registry usage:
  201. * R0 - p_fifo
  202. * R1 - internal temporary register
  203. * R2 - new_tail
  204. */
  205. nrf_atfifo_wspace_close_repeat
  206. ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
  207. /* Copy from lower byte to higher */
  208. pkhbt r2, r2, r2, lsl #16
  209. strex r1, r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
  210. cmp r1, #0
  211. bne nrf_atfifo_wspace_close_repeat
  212. bx lr
  213. }
  214. __ASM bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
  215. {
  216. /* Registry usage:
  217. * R0 - p_fifo
  218. * R1 - p_old_head
  219. * R2 - internal variable old_head (saved by caller)
  220. * R3 - internal variable new_head (saved by caller)
  221. * R4 - internal temporary register (saved by this function)
  222. * R5 - not used stored to keep the stack aligned to 8 bytes
  223. * Returned value:
  224. * R0 (bool - 32 bits)
  225. */
  226. push {r4, r5}
  227. nrf_atfifo_rspace_req_repeat
  228. /* Load tail tag and set memory monitor !!! R2 - old tail !!! */
  229. ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
  230. /* Extract read position !!! R3 !!! */
  231. uxth r3, r2, ror #16
  232. /* Check if we have any data !!! R4 used temporary !!! */
  233. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
  234. cmp r3, r4
  235. ittt eq
  236. clrexeq
  237. moveq r0, #__cpp(false)
  238. beq nrf_atfifo_rspace_req_exit
  239. /* Increment address with overload support !!! R4 used temporary !!! */
  240. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, item_size))]
  241. add r3, r4
  242. ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, buf_size))]
  243. cmp r3, r4
  244. it hs
  245. subhs r3, r3, r4
  246. /* Pack everything back !!! R3 - new tail !!! */
  247. /* Copy lower byte from old_head, and higher byte is a value from write_pos */
  248. pkhbt r3, r2, r3, lsl #16
  249. /* Store new value clearing memory monitor !!! R4 used temporary !!! */
  250. strex r4, r3, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
  251. cmp r4, #0
  252. bne nrf_atfifo_rspace_req_repeat
  253. /* Return true */
  254. mov r0, #__cpp(true)
  255. nrf_atfifo_rspace_req_exit
  256. /* Save old head */
  257. str r2, [r1]
  258. pop {r4, r5}
  259. bx lr
  260. }
  261. __ASM void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo)
  262. {
  263. /* Registry usage:
  264. * R0 - p_fifo
  265. * R1 - internal temporary register
  266. * R2 - new_tail
  267. */
  268. nrf_atfifo_rspace_close_repeat
  269. ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
  270. /* Copy from higher byte to lower */
  271. pkhtb r2, r2, r2, asr #16
  272. strex r1, r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
  273. cmp r1, #0
  274. bne nrf_atfifo_rspace_close_repeat
  275. bx lr
  276. }
  277. __ASM bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo)
  278. {
  279. /* Registry usage:
  280. * R0 - p_fifo as input, bool output after
  281. * R1 - tail, rd pointer, new_head
  282. * R2 - head_old, destroyed when creating new_head
  283. * R3 - p_fifo - copy
  284. */
  285. mov r3, r0
  286. nrf_atfifo_space_clear_repeat
  287. /* Load old head in !!! R2 register !!! and read pointer of tail in !!! R1 register !!! */
  288. ldrex r2, [r3, #__cpp(offsetof(nrf_atfifo_t, head))]
  289. ldrh r1, [r3, #__cpp(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
  290. cmp r2, r2, ror #16
  291. /* Return false as default */
  292. mov r0, #__cpp(false)
  293. /* Create new head in !!! R1 register !!! Data in !!! R2 register broken !!! */
  294. itett ne
  295. uxthne r2, r2
  296. orreq r1, r1, r1, lsl #16
  297. orrne r1, r2, r1, lsl #16
  298. /* Skip header test */
  299. bne nrf_atfifo_space_clear_head_test_skip
  300. /* Load whole tail and test it !!! R2 used !!! */
  301. ldr r2, [r3, #__cpp(offsetof(nrf_atfifo_t, tail))]
  302. cmp r2, r2, ror #16
  303. /* Return true if equal */
  304. it eq
  305. moveq r0, #__cpp(true)
  306. nrf_atfifo_space_clear_head_test_skip
  307. /* Store and test if success !!! R2 used temporary !!! */
  308. strex r2, r1, [r3, #__cpp(offsetof(nrf_atfifo_t, head))]
  309. cmp r2, #0
  310. bne nrf_atfifo_space_clear_repeat
  311. bx lr
  312. }
  313. #elif defined ( __ICCARM__ ) || defined ( __GNUC__ )
  314. bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
  315. {
  316. volatile bool ret;
  317. volatile uint32_t old_tail;
  318. uint32_t new_tail;
  319. uint32_t temp;
  320. __ASM volatile(
  321. /* For more comments see Keil version above */
  322. "1: \n"
  323. " ldrex %[old_tail], [%[p_fifo], %[offset_tail]] \n"
  324. " uxth %[new_tail], %[old_tail] \n"
  325. " \n"
  326. " ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
  327. " add %[new_tail], %[temp] \n"
  328. " ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
  329. " cmp %[new_tail], %[temp] \n"
  330. " it hs \n"
  331. " subhs %[new_tail], %[new_tail], %[temp] \n"
  332. " \n"
  333. " ldrh %[temp], [%[p_fifo], %[offset_head_wr]] \n"
  334. " cmp %[new_tail], %[temp] \n"
  335. " ittt eq \n"
  336. " clrexeq \n"
  337. " moveq %[ret], %[false_val] \n"
  338. " beq.n 2f \n"
  339. " \n"
  340. " pkhbt %[new_tail], %[new_tail], %[old_tail] \n"
  341. " \n"
  342. " strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
  343. " cmp %[temp], #0 \n"
  344. " bne.n 1b \n"
  345. " \n"
  346. " mov %[ret], %[true_val] \n"
  347. "2: \n"
  348. : /* Output operands */
  349. [ret] "=r"(ret),
  350. [temp] "=&r"(temp),
  351. [old_tail]"=&r"(old_tail),
  352. [new_tail]"=&r"(new_tail)
  353. : /* Input operands */
  354. [p_fifo] "r"(p_fifo),
  355. [offset_tail] "J"(offsetof(nrf_atfifo_t, tail)),
  356. [offset_head_wr] "J"(offsetof(nrf_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr)),
  357. [offset_item_size]"J"(offsetof(nrf_atfifo_t, item_size)),
  358. [offset_buf_size] "J"(offsetof(nrf_atfifo_t, buf_size)),
  359. [true_val] "I"(true),
  360. [false_val] "I"(false)
  361. : /* Clobbers */
  362. "cc");
  363. p_old_tail->tag = old_tail;
  364. UNUSED_VARIABLE(new_tail);
  365. UNUSED_VARIABLE(temp);
  366. return ret;
  367. }
  368. void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo)
  369. {
  370. uint32_t temp;
  371. uint32_t new_tail;
  372. __ASM volatile(
  373. /* For more comments see Keil version above */
  374. "1: \n"
  375. " ldrex %[new_tail], [%[p_fifo], %[offset_tail]] \n"
  376. " pkhbt %[new_tail],%[new_tail], %[new_tail], lsl #16 \n"
  377. " \n"
  378. " strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
  379. " cmp %[temp], #0 \n"
  380. " bne.n 1b \n"
  381. : /* Output operands */
  382. [temp] "=&r"(temp),
  383. [new_tail] "=&r"(new_tail)
  384. : /* Input operands */
  385. [p_fifo] "r"(p_fifo),
  386. [offset_tail] "J"(offsetof(nrf_atfifo_t, tail))
  387. : /* Clobbers */
  388. "cc");
  389. UNUSED_VARIABLE(temp);
  390. UNUSED_VARIABLE(new_tail);
  391. }
  392. bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
  393. {
  394. volatile bool ret;
  395. volatile uint32_t old_head;
  396. uint32_t new_head;
  397. uint32_t temp;
  398. __ASM volatile(
  399. /* For more comments see Keil version above */
  400. "1: \n"
  401. " ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
  402. " uxth %[new_head], %[old_head], ror #16 \n"
  403. " \n"
  404. " ldrh %[temp], [%[p_fifo], %[offset_tail_rd]] \n"
  405. " cmp %[new_head], %[temp] \n"
  406. " ittt eq \n"
  407. " clrexeq \n"
  408. " moveq %[ret], %[false_val] \n"
  409. " beq.n 2f \n"
  410. " \n"
  411. " ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
  412. " add %[new_head], %[temp] \n"
  413. " ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
  414. " cmp %[new_head], %[temp] \n"
  415. " it hs \n"
  416. " subhs %[new_head], %[new_head], %[temp] \n"
  417. " \n"
  418. " pkhbt %[new_head], %[old_head], %[new_head], lsl #16 \n"
  419. " \n"
  420. " strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
  421. " cmp %[temp], #0 \n"
  422. " bne.n 1b \n"
  423. " \n"
  424. " mov %[ret], %[true_val] \n"
  425. "2: \n"
  426. : /* Output operands */
  427. [ret] "=r"(ret),
  428. [temp] "=&r"(temp),
  429. [old_head]"=&r"(old_head),
  430. [new_head]"=&r"(new_head)
  431. : /* Input operands */
  432. [p_fifo] "r"(p_fifo),
  433. [offset_head] "J"(offsetof(nrf_atfifo_t, head)),
  434. [offset_tail_rd] "J"(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
  435. [offset_item_size]"J"(offsetof(nrf_atfifo_t, item_size)),
  436. [offset_buf_size] "J"(offsetof(nrf_atfifo_t, buf_size)),
  437. [true_val] "I"(true),
  438. [false_val] "I"(false)
  439. : /* Clobbers */
  440. "cc");
  441. p_old_head->tag = old_head;
  442. UNUSED_VARIABLE(new_head);
  443. UNUSED_VARIABLE(temp);
  444. return ret;
  445. }
  446. void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo)
  447. {
  448. uint32_t temp;
  449. uint32_t new_head;
  450. __ASM volatile(
  451. /* For more comments see Keil version above */
  452. "1: \n"
  453. " ldrex %[new_head], [%[p_fifo], %[offset_head]] \n"
  454. " pkhtb %[new_head],%[new_head], %[new_head], asr #16 \n"
  455. " \n"
  456. " strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
  457. " cmp %[temp], #0 \n"
  458. " bne.n 1b \n"
  459. : /* Output operands */
  460. [temp] "=&r"(temp),
  461. [new_head] "=&r"(new_head)
  462. : /* Input operands */
  463. [p_fifo] "r"(p_fifo),
  464. [offset_head] "J"(offsetof(nrf_atfifo_t, head))
  465. : /* Clobbers */
  466. "cc");
  467. UNUSED_VARIABLE(temp);
  468. UNUSED_VARIABLE(new_head);
  469. }
  470. bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo)
  471. {
  472. volatile bool ret;
  473. uint32_t old_head; /* This variable is left broken after assembly code finishes */
  474. uint32_t new_head;
  475. __ASM volatile(
  476. "1: \n"
  477. " ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
  478. " ldrh %[new_head], [%[p_fifo], %[offset_tail_rd]] \n"
  479. " cmp %[old_head], %[old_head], ror #16 \n"
  480. " \n"
  481. " mov %[ret], %[false_val] \n"
  482. " \n"
  483. " itett ne \n"
  484. " uxthne %[old_head], %[old_head] \n"
  485. " orreq %[new_head], %[new_head], %[new_head], lsl #16 \n"
  486. " orrne %[new_head], %[old_head], %[new_head], lsl #16 \n"
  487. " \n"
  488. " bne.n 2f \n"
  489. " \n"
  490. " ldr %[old_head], [%[p_fifo], %[offset_tail]] \n"
  491. " cmp %[old_head], %[old_head], ror #16 \n"
  492. " it eq \n"
  493. " moveq %[ret], %[true_val] \n"
  494. " \n"
  495. "2: \n"
  496. " strex %[old_head], %[new_head], [%[p_fifo], %[offset_head]] \n"
  497. " cmp %[old_head], #0 \n"
  498. " bne.n 1b \n"
  499. : /* Output operands */
  500. [ret] "=&r"(ret),
  501. [old_head] "=&r"(old_head),
  502. [new_head] "=&r"(new_head)
  503. : /* Input operands */
  504. [p_fifo] "r"(p_fifo),
  505. [offset_head] "J"(offsetof(nrf_atfifo_t, head)),
  506. [offset_tail] "J"(offsetof(nrf_atfifo_t, tail)),
  507. [offset_tail_rd] "J"(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
  508. [true_val] "I"(true),
  509. [false_val] "I"(false)
  510. : /* Clobbers */
  511. "cc");
  512. UNUSED_VARIABLE(old_head);
  513. UNUSED_VARIABLE(new_head);
  514. return ret;
  515. }
  516. #else
  517. #error Unsupported compiler
  518. #endif
  519. #endif /* NRF_ATFIFO_INTERNAL_H__ */