xtensa_loadstore_handler.S 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * LoadStoreErrorCause: Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit
  8. * LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner
  9. *
  10. * xxxx xxxx = imm8 field
  11. * yyyy = imm4 field
  12. * ssss = s field
  13. * tttt = t field
  14. *
  15. * 16 0
  16. * -------------------
  17. * L32I.N yyyy ssss tttt 1000
  18. * S32I.N yyyy ssss tttt 1001
  19. *
  20. * 23 0
  21. * -----------------------------
  22. * L8UI xxxx xxxx 0000 ssss tttt 0010 <- LoadStoreError
  23. * L16UI xxxx xxxx 0001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment
  24. * L16SI xxxx xxxx 1001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment
  25. * L32I xxxx xxxx 0010 ssss tttt 0010 <- LoadStoreAlignment
  26. *
  27. * S8I xxxx xxxx 0100 ssss tttt 0010 <- LoadStoreError
  28. * S16I xxxx xxxx 0101 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment
  29. * S32I xxxx xxxx 0110 ssss tttt 0010 <- LoadStoreAlignment
  30. *
  31. * ******* UNSUPPORTED *******
  32. *
  33. * L32E 0000 1001 rrrr ssss tttt 0000
  34. * S32E 0100 1001 rrrr ssss tttt 0000
  35. * -----------------------------
  36. */
  37. #include "xtensa_rtos.h"
  38. #include "sdkconfig.h"
  39. #include "soc/soc.h"
  40. #define LOADSTORE_HANDLER_STACK_SZ 8
  41. .section .bss, "aw"
  42. .balign 16
  43. LoadStoreHandlerStack:
  44. .rept LOADSTORE_HANDLER_STACK_SZ
  45. .word 0
  46. .endr
  47. /* LoadStoreErrorCause handler:
  48. *
  49. * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region
  50. * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
  51. */
  52. .global LoadStoreErrorHandler
  53. .section .iram1, "ax"
  54. .literal_position
  55. .balign 4
  56. LoadStoreErrorHandler:
  57. .type LoadStoreErrorHandler, @function
  58. wsr a0, depc // Save return address in depc
  59. mov a0, sp
  60. movi sp, LoadStoreHandlerStack
  61. s32i a0, sp, 0x04 // Since a0 contains value of a1
  62. s32i a2, sp, 0x08
  63. s32i a3, sp, 0x0c
  64. s32i a4, sp, 0x10
  65. rsr a0, sar // Save SAR in a0 to restore later
  66. /* Check whether the address lies in the valid range */
  67. rsr a3, excvaddr
  68. movi a4, _iram_text_end // End of code section of IRAM
  69. bge a3, a4, 1f
  70. movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region
  71. blt a3, a4, .LS_wrong_opcode
  72. movi a4, SOC_CACHE_APP_HIGH
  73. bge a3, a4, .LS_wrong_opcode
  74. j 2f
  75. 1:
  76. movi a4, SOC_IRAM_HIGH // End of IRAM address range
  77. bge a3, a4, .LS_wrong_opcode
  78. 2:
  79. /* Examine the opcode which generated the exception */
  80. /* Note: Instructions are in this order to avoid pipeline stalls. */
  81. rsr a2, epc1
  82. movi a4, ~3
  83. ssa8l a2 // sar is now correct shift for aligned read
  84. and a2, a2, a4 // a2 now 4-byte aligned address of instruction
  85. l32i a4, a2, 0
  86. l32i a2, a2, 4
  87. src a2, a2, a4 // a2 now instruction that failed
  88. bbci a2, 1, .LS_wrong_opcode
  89. bbsi a2, 14, .LSE_store_op // Store instruction
  90. /* l8/l16ui/l16si */
  91. movi a4, ~3
  92. and a4, a3, a4 // a4 now word aligned read address
  93. ssa8l a3 // sar is now shift to extract a3's byte
  94. l32i a4, a4, 0 // perform the actual read
  95. srl a4, a4 // shift right correct distance
  96. extui a3, a2, 12, 4
  97. bnez a3, 1f // l16ui/l16si
  98. extui a4, a4, 0, 8 // mask off bits needed for an l8
  99. j 2f
  100. 1:
  101. extui a4, a4, 0, 16
  102. bbci a2, 15, 2f // l16ui
  103. /* Sign adjustment */
  104. slli a4, a4, 16
  105. srai a4, a4, 16 // a4 contains the value
  106. 2:
  107. /* a4 contains the value */
  108. rsr a3, epc1
  109. addi a3, a3, 3
  110. wsr a3, epc1
  111. wsr a0, sar
  112. rsr a0, excsave1
  113. extui a2, a2, 3, 5
  114. blti a2, 10, .LSE_stack_reg
  115. movi a3, .LS_jumptable_base
  116. addx8 a2, a2, a3 // a2 is now the address to jump to
  117. l32i a3, sp, 0x0c
  118. jx a2
  119. .LSE_stack_reg:
  120. addx2 a2, a2, sp
  121. s32i a4, a2, 0
  122. /* Restore all values */
  123. l32i a4, sp, 0x10
  124. l32i a3, sp, 0x0c
  125. l32i a2, sp, 0x08
  126. l32i a1, sp, 0x04
  127. rfe
  128. .LSE_store_op:
  129. s32i a5, a1, 0x14
  130. s32i a6, a1, 0x18
  131. /* a2 -> instruction that caused the error */
  132. /* a3 -> unaligned address */
  133. extui a4, a2, 4, 4
  134. blti a4, 7, 1f
  135. movi a5, .LSE_store_reg
  136. addx8 a5, a4, a5
  137. jx a5
  138. 1:
  139. addx4 a4, a4, sp
  140. l32i a4, a4, 0
  141. .LSE_store_data:
  142. /* a4 contains the value */
  143. rsr a6, epc1
  144. addi a6, a6, 3
  145. wsr a6, epc1
  146. ssa8b a3
  147. movi a5, -1
  148. bbsi a2, 12, 1f // s16
  149. extui a4, a4, 0, 8
  150. movi a6, 0xff
  151. j 2f
  152. 1:
  153. extui a4, a4, 0, 16
  154. movi a6, 0xffff
  155. 2:
  156. sll a4, a4 // shift the value to proper offset
  157. sll a6, a6
  158. xor a5, a5, a6 // a5 contains the mask
  159. movi a6, ~3
  160. and a3, a3, a6 // a3 has the aligned address
  161. l32i a6, a3, 0 // a6 contains the data at the aligned address
  162. and a6, a6, a5
  163. or a4, a6, a4
  164. s32i a4, a3, 0
  165. /* Restore registers */
  166. wsr a0, sar
  167. l32i a6, sp, 0x18
  168. l32i a5, sp, 0x14
  169. l32i a4, sp, 0x10
  170. l32i a3, sp, 0x0c
  171. l32i a2, sp, 0x08
  172. l32i a1, sp, 0x04
  173. rsr a0, excsave1
  174. rfe
  175. .LSE_store_reg:
  176. .org .LSE_store_reg + (7 * 8)
  177. mov a4, a7
  178. j .LSE_store_data
  179. .org .LSE_store_reg + (8 * 8)
  180. mov a4, a8
  181. j .LSE_store_data
  182. .org .LSE_store_reg + (9 * 8)
  183. mov a4, a9
  184. j .LSE_store_data
  185. .org .LSE_store_reg + (10 * 8)
  186. mov a4, a10
  187. j .LSE_store_data
  188. .org .LSE_store_reg + (11 * 8)
  189. mov a4, a11
  190. j .LSE_store_data
  191. .org .LSE_store_reg + (12 * 8)
  192. mov a4, a12
  193. j .LSE_store_data
  194. .org .LSE_store_reg + (13 * 8)
  195. mov a4, a13
  196. j .LSE_store_data
  197. .org .LSE_store_reg + (14 * 8)
  198. mov a4, a14
  199. j .LSE_store_data
  200. .org .LSE_store_reg + (15 * 8)
  201. mov a4, a15
  202. j .LSE_store_data
  203. /* LoadStoreAlignmentCause handler:
  204. *
  205. * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region
  206. * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause
  207. */
  208. .global AlignmentErrorHandler
  209. .section .iram1, "ax"
  210. .literal_position
  211. .balign 4
  212. AlignmentErrorHandler:
  213. .type AlignmentErrorHandler, @function
  214. wsr a0, depc // Save return address in depc
  215. mov a0, sp
  216. movi sp, LoadStoreHandlerStack
  217. s32i a0, sp, 0x04 // Since a0 contains value of a1
  218. s32i a2, sp, 0x08
  219. s32i a3, sp, 0x0c
  220. s32i a4, sp, 0x10
  221. rsr a0, sar // Save SAR in a0 to restore later
  222. /* Check whether the address lies in the valid range */
  223. rsr a3, excvaddr
  224. movi a4, _iram_text_end // End of code section of IRAM
  225. bge a3, a4, 1f
  226. movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region
  227. blt a3, a4, .LS_wrong_opcode
  228. movi a4, SOC_CACHE_APP_HIGH
  229. bge a3, a4, .LS_wrong_opcode
  230. j 2f
  231. 1:
  232. movi a4, SOC_IRAM_HIGH // End of IRAM address range
  233. bge a3, a4, .LS_wrong_opcode
  234. 2:
  235. /* Examine the opcode which generated the exception */
  236. /* Note: Instructions are in this order to avoid pipeline stalls. */
  237. rsr a2, epc1
  238. movi a4, ~3
  239. ssa8l a2 // sar is now correct shift for aligned read
  240. and a2, a2, a4 // a2 now 4-byte aligned address of instruction
  241. l32i a4, a2, 0
  242. l32i a2, a2, 4
  243. /* a2 has the instruction that caused the error */
  244. src a2, a2, a4
  245. extui a4, a2, 0, 4
  246. addi a4, a4, -9
  247. beqz a4, .LSA_store_op
  248. bbsi a2, 14, .LSA_store_op
  249. ssa8l a3 // a3 contains the unaligned address
  250. movi a4, ~3
  251. and a4, a3, a4 // a4 has the aligned address
  252. l32i a3, a4, 0
  253. l32i a4, a4, 4
  254. src a4, a4, a3
  255. rsr a3, epc1
  256. addi a3, a3, 2
  257. bbsi a2, 3, 1f // l32i.n
  258. bbci a2, 1, .LS_wrong_opcode
  259. addi a3, a3, 1
  260. bbsi a2, 13, 1f // l32
  261. extui a4, a4, 0, 16
  262. bbci a2, 15, 1f // l16ui
  263. /* Sign adjustment */
  264. slli a4, a4, 16
  265. srai a4, a4, 16 // a4 contains the value
  266. 1:
  267. wsr a3, epc1
  268. wsr a0, sar
  269. rsr a0, excsave1
  270. extui a2, a2, 4, 4
  271. blti a2, 5, .LSA_stack_reg // a3 contains the target register
  272. movi a3, .LS_jumptable_base
  273. slli a2, a2, 4
  274. add a2, a2, a3 // a2 is now the address to jump to
  275. l32i a3, sp, 0x0c
  276. jx a2
  277. .LSA_stack_reg:
  278. addx4 a2, a2, sp
  279. s32i a4, a2, 0
  280. /* Restore all values */
  281. l32i a4, sp, 0x10
  282. l32i a3, sp, 0x0c
  283. l32i a2, sp, 0x08
  284. l32i a1, sp, 0x04
  285. rfe
  286. /* Store instruction */
  287. .LSA_store_op:
  288. s32i a5, sp, 0x14
  289. s32i a6, sp, 0x18
  290. s32i a7, sp, 0x1c
  291. /* a2 -> instruction that caused the error */
  292. /* a3 -> unaligned address */
  293. extui a4, a2, 4, 4
  294. blti a4, 8, 1f
  295. movi a5, .LSA_store_reg
  296. addx8 a5, a4, a5
  297. jx a5
  298. 1:
  299. addx4 a4, a4, sp
  300. l32i a4, a4, 0 // a4 contains the value
  301. .LSA_store_data:
  302. movi a6, 0
  303. rsr a7, epc1
  304. addi a7, a7 ,2
  305. bbsi a2, 3, 1f // s32i.n
  306. bbci a2, 1, .LS_wrong_opcode
  307. addi a7, a7, 1
  308. bbsi a2, 13, 1f // s32i
  309. movi a5, -1
  310. extui a4, a4, 0, 16
  311. slli a6, a5, 16 // 0xffff0000
  312. 1:
  313. wsr a7, epc1
  314. movi a5, ~3
  315. and a5, a3, a5 // a5 has the aligned address
  316. ssa8b a3
  317. movi a3, -1
  318. src a7, a6, a3
  319. src a3, a3, a6
  320. /* Store data on lower address */
  321. l32i a6, a5, 0
  322. and a6, a6, a7
  323. sll a7, a4
  324. or a6, a6, a7
  325. s32i a6, a5, 0
  326. /* Store data on higher address */
  327. l32i a7, a5, 4
  328. srl a6, a4
  329. and a3, a7, a3
  330. or a3, a3, a6
  331. s32i a3, a5, 4
  332. /* Restore registers */
  333. wsr a0, sar
  334. rsr a0, excsave1
  335. l32i a7, sp, 0x1c
  336. l32i a6, sp, 0x18
  337. l32i a5, sp, 0x14
  338. l32i a4, sp, 0x10
  339. l32i a3, sp, 0x0c
  340. l32i a2, sp, 0x08
  341. l32i a1, sp, 0x04
  342. rfe
  343. .LSA_store_reg:
  344. .org .LSA_store_reg + (8 * 8)
  345. mov a4, a8
  346. j .LSA_store_data
  347. .org .LSA_store_reg + (9 * 8)
  348. mov a4, a9
  349. j .LSA_store_data
  350. .org .LSA_store_reg + (10 * 8)
  351. mov a4, a10
  352. j .LSA_store_data
  353. .org .LSA_store_reg + (11 * 8)
  354. mov a4, a11
  355. j .LSA_store_data
  356. .org .LSA_store_reg + (12 * 8)
  357. mov a4, a12
  358. j .LSA_store_data
  359. .org .LSA_store_reg + (13 * 8)
  360. mov a4, a13
  361. j .LSA_store_data
  362. .org .LSA_store_reg + (14 * 8)
  363. mov a4, a14
  364. j .LSA_store_data
  365. .org .LSA_store_reg + (15 * 8)
  366. mov a4, a15
  367. j .LSA_store_data
  368. /*
  369. * Common routines for both the exception handlers
  370. */
  371. .balign 4
  372. .LS_jumptable:
  373. /* The first 5 entries (80 bytes) of this table are unused (registers
  374. a0..a4 are handled separately above). Rather than have a whole bunch
  375. of wasted space, just pretend that the table starts 80 bytes
  376. earlier in memory. */
  377. .set .LS_jumptable_base, .LS_jumptable - (16 * 5)
  378. .org .LS_jumptable_base + (16 * 5)
  379. mov a5, a4
  380. l32i a4, sp, 0x10
  381. l32i a2, sp, 0x08
  382. l32i a1, sp, 0x04
  383. rfe
  384. .org .LS_jumptable_base + (16 * 6)
  385. mov a6, a4
  386. l32i a4, sp, 0x10
  387. l32i a2, sp, 0x08
  388. l32i a1, sp, 0x04
  389. rfe
  390. .org .LS_jumptable_base + (16 * 7)
  391. mov a7, a4
  392. l32i a4, sp, 0x10
  393. l32i a2, sp, 0x08
  394. l32i a1, sp, 0x04
  395. rfe
  396. .org .LS_jumptable_base + (16 * 8)
  397. mov a8, a4
  398. l32i a4, sp, 0x10
  399. l32i a2, sp, 0x08
  400. l32i a1, sp, 0x04
  401. rfe
  402. .org .LS_jumptable_base + (16 * 9)
  403. mov a9, a4
  404. l32i a4, sp, 0x10
  405. l32i a2, sp, 0x08
  406. l32i a1, sp, 0x04
  407. rfe
  408. .org .LS_jumptable_base + (16 * 10)
  409. mov a10, a4
  410. l32i a4, sp, 0x10
  411. l32i a2, sp, 0x08
  412. l32i a1, sp, 0x04
  413. rfe
  414. .org .LS_jumptable_base + (16 * 11)
  415. mov a11, a4
  416. l32i a4, sp, 0x10
  417. l32i a2, sp, 0x08
  418. l32i a1, sp, 0x04
  419. rfe
  420. .org .LS_jumptable_base + (16 * 12)
  421. mov a12, a4
  422. l32i a4, sp, 0x10
  423. l32i a2, sp, 0x08
  424. l32i a1, sp, 0x04
  425. rfe
  426. .org .LS_jumptable_base + (16 * 13)
  427. mov a13, a4
  428. l32i a4, sp, 0x10
  429. l32i a2, sp, 0x08
  430. l32i a1, sp, 0x04
  431. rfe
  432. .org .LS_jumptable_base + (16 * 14)
  433. mov a14, a4
  434. l32i a4, sp, 0x10
  435. l32i a2, sp, 0x08
  436. l32i a1, sp, 0x04
  437. rfe
  438. .org .LS_jumptable_base + (16 * 15)
  439. mov a15, a4
  440. l32i a4, sp, 0x10
  441. l32i a2, sp, 0x08
  442. l32i a1, sp, 0x04
  443. rfe
  444. .LS_wrong_opcode:
  445. /* Reaches here if the address is in invalid range or the opcode isn't supported.
  446. * Restore registers and jump back to _xt_user_exc
  447. */
  448. wsr a0, sar
  449. l32i a4, sp, 0x10
  450. l32i a3, sp, 0x0c
  451. l32i a2, sp, 0x08
  452. l32i a1, sp, 0x04
  453. rsr a0, depc
  454. ret // Equivalent to jx a0